Skip to content

Commit 8def4a4

Browse files
authored
Merge pull request #114 from guillaumep/food_prep
Include food prepration in kitchen count: add table at the end (#93)
2 parents 5c672c8 + d6ff9ad commit 8def4a4

File tree

2 files changed

+125
-6
lines changed

2 files changed

+125
-6
lines changed

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="souschef",
8-
version="1.4.1dev1",
8+
version="1.4.1dev3",
99
license="AGPL-3.0",
1010
author="Santropol Roulant and Savoir Faire Linux",
1111
author_email="[email protected]",

souschef/delivery/views.py

+124-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
import json
33
import os
44
import textwrap
5+
from dataclasses import dataclass
56
from datetime import date, datetime
7+
from typing import List
68

79
import labels # package pylabels
810
from django.conf import settings
@@ -1113,12 +1115,20 @@ def get(self, request, *args, **kwargs):
11131115

11141116
component_lines = kcr_make_component_lines(kitchen_list, delivery_date)
11151117
meal_lines = kcr_make_meal_lines(kitchen_list)
1118+
preperation_lines_with_incompatible_ingr = kcr_make_preparation_lines(
1119+
kitchen_list, "only_clients_with_incompatible_ingredients"
1120+
)
1121+
preperation_lines_without_incompatible_ingr = kcr_make_preparation_lines(
1122+
kitchen_list, "only_clients_without_incompatible_ingredients"
1123+
)
11161124
if component_lines:
11171125
# we have orders on that date
11181126
num_pages = kcr_make_pages( # kitchen count as PDF
11191127
delivery_date,
11201128
component_lines,
11211129
meal_lines, # summary
1130+
preperation_lines_with_incompatible_ingr,
1131+
preperation_lines_without_incompatible_ingr,
11221132
) # detail
11231133
num_labels = kcr_make_labels( # meal labels as PDF
11241134
delivery_date,
@@ -1249,7 +1259,7 @@ def kcr_make_meal_lines(kitchen_list):
12491259
[
12501260
(client_id, kitchen_item)
12511261
for client_id, kitchen_item in kitchen_list.items()
1252-
if kitchen_item.incompatible_ingredients or kitchen_item.preparation
1262+
if kitchen_item.incompatible_ingredients
12531263
],
12541264
key=lambda item: item[1].incompatible_ingredients,
12551265
)
@@ -1388,17 +1398,74 @@ def format_client_name(firstname, lastname):
13881398
return f"{lastname}, {firstname[:2]}."
13891399

13901400

1391-
def kcr_make_pages(kcr_date, component_lines, meal_lines):
1401+
@dataclass
1402+
class PreparationLine:
1403+
preparation_method: str
1404+
quantity: int
1405+
client_names: List[str]
1406+
1407+
1408+
def kcr_make_preparation_lines(kitchen_list, client_filter):
1409+
"""Get food preparation method for clients not having clashing (incompatible)
1410+
ingredients."""
1411+
if client_filter == "only_clients_with_incompatible_ingredients":
1412+
1413+
def select_item(item):
1414+
return bool(item.incompatible_ingredients)
1415+
elif client_filter == "only_clients_without_incompatible_ingredients":
1416+
1417+
def select_item(item):
1418+
return not item.incompatible_ingredients
1419+
else:
1420+
raise ValueError(f"Incompatible client_filter: {client_filter}")
1421+
1422+
items = [item for item in kitchen_list.values() if select_item(item)]
1423+
1424+
# Group KitchenItem per preparation method
1425+
items_per_preparation = collections.defaultdict(list)
1426+
for item in items:
1427+
for prep in item.preparation:
1428+
items_per_preparation[prep].append(item)
1429+
1430+
preparation_lines = []
1431+
for prep in sorted(items_per_preparation.keys()):
1432+
client_names = sorted(
1433+
format_client_name(item.firstname, item.lastname)
1434+
+ (f" (x {item.meal_qty})" if item.meal_qty > 1 else "")
1435+
for item in items_per_preparation[prep]
1436+
)
1437+
quantity = sum(item.meal_qty for item in items_per_preparation[prep])
1438+
1439+
preparation_lines.append(
1440+
PreparationLine(
1441+
preparation_method=prep,
1442+
quantity=quantity,
1443+
client_names=client_names,
1444+
)
1445+
)
1446+
1447+
return preparation_lines
1448+
1449+
1450+
def kcr_make_pages(
1451+
kcr_date,
1452+
component_lines,
1453+
meal_lines,
1454+
preperation_lines_with_incompatible_ingr,
1455+
preperation_lines_without_incompatible_ingr,
1456+
):
13921457
"""Generate the kitchen count report pages as a PDF file.
13931458
13941459
Uses ReportLab see http://www.reportlab.com/documentation/faq/
13951460
13961461
Args:
1397-
kcr_date : The delivery date of the meals.
1398-
component_lines : A list of ComponentLine objects, the summary of
1462+
kcr_date: The delivery date of the meals.
1463+
component_lines: A list of ComponentLine objects, the summary of
13991464
component quantities and sizes for the date's meal.
1400-
meal_lines : A list of MealLine objects, the details of the clients
1465+
meal_lines: A list of MealLine objects, the details of the clients
14011466
for the date that have ingredients clashing with those in main dish.
1467+
preperation_lines_with_incompatible_ingr: list[PreperationLine]
1468+
preperation_lines_without_incompatible_ingr: list[PreperationLine]
14021469
14031470
Returns:
14041471
An integer : The number of pages generated.
@@ -1459,6 +1526,43 @@ def myLaterPages(canvas, doc):
14591526
drawHeader(canvas, doc)
14601527
canvas.restoreState()
14611528

1529+
def get_food_preperation_table(preperation_lines, heading_suffix):
1530+
rows = []
1531+
line = 0
1532+
tab_style = RLTableStyle([("VALIGN", (0, 0), (-1, -1), "TOP")])
1533+
rows.append(
1534+
[
1535+
RLParagraph("Food Preparation", styles["NormalLeft"]),
1536+
RLParagraph("Quantity", styles["NormalRight"]),
1537+
"",
1538+
[
1539+
RLParagraph("Clients", styles["NormalLeft"]),
1540+
RLParagraph(f"({heading_suffix})", styles["NormalLeftBold"]),
1541+
],
1542+
]
1543+
)
1544+
tab_style.add("LINEABOVE", (0, line), (-1, line), 1, rl_colors.black)
1545+
tab_style.add("LINEBELOW", (0, line), (-1, line), 1, rl_colors.black)
1546+
tab_style.add("LINEBEFORE", (0, line), (0, line), 1, rl_colors.black)
1547+
tab_style.add("LINEAFTER", (-1, line), (-1, line), 1, rl_colors.black)
1548+
line += 1
1549+
1550+
for prepline in preperation_lines:
1551+
rows.append(
1552+
[
1553+
RLParagraph(prepline.preparation_method, styles["LargeBoldLeft"]),
1554+
RLParagraph(str(prepline.quantity), styles["NormalRightBold"]),
1555+
"",
1556+
RLParagraph(
1557+
";   ".join(prepline.client_names),
1558+
styles["NormalLeft"],
1559+
),
1560+
]
1561+
)
1562+
tab = RLTable(rows, colWidths=(150, 50, 10, 310), repeatRows=1)
1563+
tab.setStyle(tab_style)
1564+
return tab
1565+
14621566
def go():
14631567
"""Generate the pages.
14641568
@@ -1611,6 +1715,21 @@ def go():
16111715
story.append(RLSpacer(1, 1 * rl_inch))
16121716
# end Detail section
16131717

1718+
story.append(RLPageBreak())
1719+
story.append(
1720+
get_food_preperation_table(
1721+
preperation_lines_with_incompatible_ingr, "with restrictions"
1722+
)
1723+
)
1724+
story.append(RLSpacer(1, 1 * rl_inch))
1725+
1726+
story.append(
1727+
get_food_preperation_table(
1728+
preperation_lines_without_incompatible_ingr, "without restrictions"
1729+
)
1730+
)
1731+
story.append(RLSpacer(1, 1 * rl_inch))
1732+
16141733
# build full document
16151734
doc.build(story, onFirstPage=myFirstPage, onLaterPages=myLaterPages)
16161735
return doc.page

0 commit comments

Comments
 (0)