Add optional nursery roster composition
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from pathlib import Path
|
||||
from typing import Literal, Sequence
|
||||
|
||||
import fitz # type: ignore
|
||||
|
||||
@@ -36,3 +37,169 @@ def make_geometry_pdf(path: Path) -> Path:
|
||||
doc.save(path)
|
||||
doc.close()
|
||||
return path
|
||||
|
||||
|
||||
def _make_subsplash_roster_pdf(
|
||||
path: Path,
|
||||
roster_type: Literal["main", "nursery_only"],
|
||||
dates: Sequence[str],
|
||||
) -> Path:
|
||||
"""Create a realistic one-page, vector Subsplash-style roster fixture.
|
||||
|
||||
The fixture deliberately resembles the structure of ``input/original.pdf``:
|
||||
dates run across the top, role headings and assignment labels run down the
|
||||
left, and the cells contain volunteer names. It is not used by the legacy
|
||||
geometry golden, so changes here cannot mask a single-roster regression.
|
||||
"""
|
||||
|
||||
if not dates:
|
||||
raise ValueError("at least one date is required")
|
||||
|
||||
document = fitz.open()
|
||||
page = document.new_page(width=792, height=612)
|
||||
page.draw_rect(page.rect, color=None, fill=(1, 1, 1), width=0)
|
||||
|
||||
if roster_type == "main":
|
||||
table = fitz.Rect(34, 48, 758, 446)
|
||||
roles = (
|
||||
("MEDIA", "Sound", "Alex Morgan"),
|
||||
("NURSERY", "Nursery Workers", "Jamie Rivera"),
|
||||
("LITTLE WADERS", "Teacher", "Taylor Brooks"),
|
||||
("RIVER KID", "Teacher", "Jordan Lee"),
|
||||
("GREETERS", "Greet", "Morgan Reed"),
|
||||
("USHERS", "Usher", "Casey Miller"),
|
||||
("OFFERING MESSAGE", "Speaker", "Riley Davis"),
|
||||
("PRAYER", "Prayer", "Avery Wilson"),
|
||||
)
|
||||
else:
|
||||
# Mirrors the compact real nursery strip: roughly 36 points of date
|
||||
# header plus about 66 points for the band and worker row.
|
||||
table = fitz.Rect(14, 188, 778, 290)
|
||||
roles = (("NURSERY WORKERS", "Nursery Workers", "Jamie Rivera"),)
|
||||
|
||||
first_column_width = 154
|
||||
header_height = 42 if roster_type == "main" else 36
|
||||
date_width = (table.width - first_column_width) / len(dates)
|
||||
role_height = (table.height - header_height) / len(roles)
|
||||
navy = (0.06, 0.18, 0.25)
|
||||
pale_blue = (0.90, 0.95, 0.97)
|
||||
grid = (0.36, 0.43, 0.47)
|
||||
|
||||
page.draw_rect(table, color=grid, fill=(1, 1, 1), width=0.8)
|
||||
page.draw_rect(
|
||||
fitz.Rect(table.x0, table.y0, table.x1, table.y0 + header_height),
|
||||
color=grid,
|
||||
fill=navy,
|
||||
width=0.8,
|
||||
)
|
||||
page.insert_text(
|
||||
(table.x0 + 8, table.y0 + 26),
|
||||
"SERVING SCHEDULE",
|
||||
fontname="helv",
|
||||
fontsize=10,
|
||||
color=(1, 1, 1),
|
||||
)
|
||||
|
||||
first_date_x = table.x0 + first_column_width
|
||||
page.draw_line(
|
||||
fitz.Point(first_date_x, table.y0),
|
||||
fitz.Point(first_date_x, table.y1),
|
||||
color=grid,
|
||||
width=0.8,
|
||||
)
|
||||
for index, date_label in enumerate(dates):
|
||||
x = first_date_x + index * date_width
|
||||
if index:
|
||||
page.draw_line(
|
||||
fitz.Point(x, table.y0),
|
||||
fitz.Point(x, table.y1),
|
||||
color=grid,
|
||||
width=0.6,
|
||||
)
|
||||
page.insert_text(
|
||||
(x + 8, table.y0 + 18),
|
||||
date_label,
|
||||
fontname="hebo",
|
||||
fontsize=9,
|
||||
color=(1, 1, 1),
|
||||
)
|
||||
page.insert_text(
|
||||
(x + 8, table.y0 + 32),
|
||||
"7:00pm" if date_label.lower().startswith(("wed", "thu")) else "10:00am",
|
||||
fontname="helv",
|
||||
fontsize=8,
|
||||
color=(1, 1, 1),
|
||||
)
|
||||
|
||||
for role_index, (heading, assignment, volunteer) in enumerate(roles):
|
||||
y0 = table.y0 + header_height + role_index * role_height
|
||||
y1 = y0 + role_height
|
||||
if role_index:
|
||||
page.draw_line(
|
||||
fitz.Point(table.x0, y0),
|
||||
fitz.Point(table.x1, y0),
|
||||
color=grid,
|
||||
width=0.6,
|
||||
)
|
||||
page.draw_rect(
|
||||
fitz.Rect(table.x0, y0, first_date_x, y1),
|
||||
color=None,
|
||||
fill=pale_blue,
|
||||
width=0,
|
||||
)
|
||||
page.insert_text(
|
||||
(table.x0 + 7, y0 + 15),
|
||||
heading,
|
||||
fontname="hebo",
|
||||
fontsize=7.5,
|
||||
color=navy,
|
||||
)
|
||||
page.insert_text(
|
||||
(
|
||||
table.x0 + 7,
|
||||
min(y1 - 5, y0 + (31 if roster_type == "main" else 43)),
|
||||
),
|
||||
assignment,
|
||||
fontname="helv",
|
||||
fontsize=7.5,
|
||||
color=(0.12, 0.12, 0.12),
|
||||
)
|
||||
for date_index in range(len(dates)):
|
||||
x = first_date_x + date_index * date_width + 7
|
||||
name = volunteer if date_index % 2 == 0 else f"{volunteer.split()[0]} Kim"
|
||||
page.insert_text(
|
||||
(
|
||||
x,
|
||||
y0
|
||||
+ min(
|
||||
27 if roster_type == "main" else 41,
|
||||
role_height * 0.72,
|
||||
),
|
||||
),
|
||||
name,
|
||||
fontname="helv",
|
||||
fontsize=7.5,
|
||||
color=(0.08, 0.08, 0.08),
|
||||
)
|
||||
|
||||
document.save(path)
|
||||
document.close()
|
||||
return path
|
||||
|
||||
|
||||
def make_main_roster_pdf(
|
||||
path: Path,
|
||||
dates: Sequence[str] = ("Sun 6 Sep", "Sun 13 Sep", "Sun 20 Sep", "Sun 27 Sep"),
|
||||
) -> Path:
|
||||
"""Create a full roster with several broad ministry-role headings."""
|
||||
|
||||
return _make_subsplash_roster_pdf(path, "main", dates)
|
||||
|
||||
|
||||
def make_nursery_only_roster_pdf(
|
||||
path: Path,
|
||||
dates: Sequence[str] = ("Wed 2 Sep", "Wed 9 Sep", "Wed 16 Sep", "Wed 23 Sep"),
|
||||
) -> Path:
|
||||
"""Create a roster whose only ministry role is Nursery Workers."""
|
||||
|
||||
return _make_subsplash_roster_pdf(path, "nursery_only", dates)
|
||||
|
||||
Reference in New Issue
Block a user