fnschool 20251016.81138.855__py3-none-any.whl → 20251018.80328.837__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fnschool might be problematic. Click here for more details.

Files changed (34) hide show
  1. fnschoo1/__init__.py +1 -1
  2. fnschoo1/canteen/models.py +5 -0
  3. fnschoo1/canteen/templates/canteen/category/create.html +3 -1
  4. fnschoo1/canteen/templates/canteen/category/delete.html +3 -1
  5. fnschoo1/canteen/templates/canteen/category/update.html +3 -1
  6. fnschoo1/canteen/templates/canteen/consumption/create.html +38 -14
  7. fnschoo1/canteen/templates/canteen/ingredient/create.html +6 -2
  8. fnschoo1/canteen/templates/canteen/ingredient/create_one.html +3 -1
  9. fnschoo1/canteen/templates/canteen/ingredient/delete.html +3 -1
  10. fnschoo1/canteen/templates/canteen/ingredient/list.html +3 -1
  11. fnschoo1/canteen/templates/canteen/ingredient/update.html +3 -1
  12. fnschoo1/canteen/templates/canteen/meal_type/create.html +3 -1
  13. fnschoo1/canteen/templates/canteen/meal_type/delete.html +3 -1
  14. fnschoo1/canteen/templates/canteen/meal_type/update.html +3 -1
  15. fnschoo1/canteen/views.py +29 -5
  16. fnschoo1/canteen/workbook/generate.py +569 -32
  17. fnschoo1/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  18. fnschoo1/profiles/templates/profiles/create.html +3 -1
  19. fnschoo1/profiles/templates/profiles/detail.html +3 -1
  20. fnschoo1/profiles/templates/profiles/edit.html +3 -1
  21. fnschoo1/profiles/templates/profiles/log_in.html +3 -1
  22. fnschoo1/templates/includes/_footer.html +12 -4
  23. fnschoo1/templates/includes/_paginator.html +3 -1
  24. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/METADATA +1 -1
  25. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/RECORD +34 -34
  26. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/SOURCES.txt.py +0 -0
  27. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/WHEEL +0 -0
  28. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/dependency_links.txt.py +0 -0
  29. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/entry_points.txt +0 -0
  30. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/entry_points.txt.py +0 -0
  31. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/licenses/LICENSE +0 -0
  32. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/requires.txt.py +0 -0
  33. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/top_level.txt +0 -0
  34. {fnschool-20251016.81138.855.dist-info → fnschool-20251018.80328.837.dist-info}/top_level.txt.py +0 -0
@@ -208,8 +208,10 @@ class CanteenWorkBook:
208
208
  )
209
209
  self.surplus_sheet = self.wb.create_sheet(title=_("Sheet Surplus"))
210
210
  self.center_alignment = Alignment(
211
- horizontal="center", vertical="center"
211
+ horizontal="center", vertical="center", wrap_text=True
212
212
  )
213
+ self.left_alignment = Alignment(horizontal="left", vertical="center")
214
+
213
215
  self.thin_border = Border(
214
216
  left=Side(style="thin"),
215
217
  right=Side(style="thin"),
@@ -222,6 +224,7 @@ class CanteenWorkBook:
222
224
  self.font_14 = Font(size=14)
223
225
  self.font_16 = Font(size=16)
224
226
  self.font_16_bold = Font(size=16, bold=True)
227
+ self.font_18_bold = Font(size=18, bold=True)
225
228
  self.font_20_bold = Font(size=20, bold=True)
226
229
 
227
230
  self.request = request
@@ -263,6 +266,7 @@ class CanteenWorkBook:
263
266
 
264
267
  def fill_in_non_storage_sheet(self):
265
268
  sheet = self.non_storage_sheet
269
+ sheet.sheet_properties.tabColor = "e616ff"
266
270
  user = self.user
267
271
  title_cell = sheet.cell(1, 1)
268
272
  title_cell.value = _(
@@ -367,7 +371,7 @@ class CanteenWorkBook:
367
371
  "Total Price Text: {total_price_text} {total_price}"
368
372
  ).format(
369
373
  total_price_text=get_CNY_TEXT(summary_total_price),
370
- total_price=summary_total_price,
374
+ total_price=summary_total_price.normalize(),
371
375
  )
372
376
  if self.is_zh_CN
373
377
  else _(
@@ -383,7 +387,9 @@ class CanteenWorkBook:
383
387
  handler_row_num = summary_row_num + 1
384
388
  handler_cell = sheet.cell(handler_row_num, 1)
385
389
  handler_cell.border = self.thin_border
386
- handler_cell.value = _("Handler:")
390
+ handler_cell.value = _("Handler: {handler}").format(
391
+ handler=user.username
392
+ )
387
393
  sheet.merge_cells(f"A{handler_row_num}:C{handler_row_num}")
388
394
  set_row_height_in_inches(sheet, handler_row_num, 0.32)
389
395
 
@@ -430,6 +436,7 @@ class CanteenWorkBook:
430
436
 
431
437
  def fill_in_consumption_sheet(self):
432
438
  sheet = self.consumption_sheet
439
+ sheet.sheet_properties.tabColor = "ff8116"
433
440
  user = self.user
434
441
  title_cell = sheet.cell(1, 1)
435
442
  title_cell.value = _(
@@ -509,13 +516,19 @@ class CanteenWorkBook:
509
516
  )
510
517
  )
511
518
  & Q(meal_type=self.meal_type)
519
+ & Q(category__is_disabled=False)
512
520
  & Q(is_disabled=False)
513
521
  & Q(is_ignorable=False)
514
522
  ).distinct()
523
+
515
524
  total_price_cell = sheet.cell(row_num, 2)
516
525
  total_price_consumed = Decimal("0.0")
517
526
  for i in ingredients:
518
- consumptions = i.consumptions.filter(is_disabled=False).all()
527
+ consumptions = i.consumptions.filter(
528
+ Q(is_disabled=False)
529
+ & Q(date_of_using__lte=self.date_end)
530
+ & Q(date_of_using__gte=self.date_start)
531
+ ).all()
519
532
  total_price_consumed += sum(
520
533
  [c.amount_used * i.unit_price for c in consumptions]
521
534
  )
@@ -540,12 +553,16 @@ class CanteenWorkBook:
540
553
  & Q(category__is_disabled=False)
541
554
  & Q(is_disabled=False)
542
555
  & Q(is_ignorable=False)
543
- ).all()
556
+ ).distinct()
544
557
 
545
558
  summary_row_num = len(categories) + header_row_num + 1
546
559
  summary_total_price = Decimal("0.0")
547
560
  for i in ingredients:
548
- consumptions = i.consumptions.filter(Q(is_disabled=False)).all()
561
+ consumptions = i.consumptions.filter(
562
+ Q(is_disabled=False)
563
+ & Q(date_of_using__lte=self.date_end)
564
+ & Q(date_of_using__gte=self.date_start)
565
+ ).all()
549
566
  summary_total_price += sum(
550
567
  [c.amount_used * i.unit_price for c in consumptions]
551
568
  )
@@ -556,14 +573,14 @@ class CanteenWorkBook:
556
573
  "Total Price Text: {total_price_text} {total_price}"
557
574
  ).format(
558
575
  total_price_text=get_CNY_TEXT(summary_total_price),
559
- total_price=summary_total_price,
576
+ total_price=summary_total_price.normalize(),
560
577
  )
561
578
  if self.is_zh_CN
562
579
  else _(
563
580
  "Total Price Text: {total_price_text} {total_price}"
564
581
  ).format(
565
582
  total_price_text=str(summary_total_price),
566
- total_price=summary_total_price,
583
+ total_price=summary_total_price.normalize(),
567
584
  )
568
585
  )
569
586
  sheet.merge_cells(f"A{summary_row_num}:C{summary_row_num}")
@@ -572,7 +589,9 @@ class CanteenWorkBook:
572
589
  handler_row_num = summary_row_num + 1
573
590
  handler_cell = sheet.cell(handler_row_num, 1)
574
591
  handler_cell.border = self.thin_border
575
- handler_cell.value = _("Handler:")
592
+ handler_cell.value = _("Handler: {handler}").format(
593
+ handler=user.username
594
+ )
576
595
  sheet.merge_cells(f"A{handler_row_num}:C{handler_row_num}")
577
596
  set_row_height_in_inches(sheet, handler_row_num, 0.32)
578
597
 
@@ -619,6 +638,7 @@ class CanteenWorkBook:
619
638
 
620
639
  def fill_in_storage_sheet(self):
621
640
  sheet = self.storage_sheet
641
+ sheet.sheet_properties.tabColor = "16d2ff"
622
642
  user = self.user
623
643
  title_cell = sheet.cell(1, 1)
624
644
  title_cell.value = _(
@@ -723,7 +743,7 @@ class CanteenWorkBook:
723
743
  "Total Price Text: {total_price_text} {total_price}"
724
744
  ).format(
725
745
  total_price_text=get_CNY_TEXT(summary_total_price),
726
- total_price=summary_total_price,
746
+ total_price=summary_total_price.normalize(),
727
747
  )
728
748
  if self.is_zh_CN
729
749
  else _(
@@ -739,7 +759,9 @@ class CanteenWorkBook:
739
759
  handler_row_num = summary_row_num + 1
740
760
  handler_cell = sheet.cell(handler_row_num, 1)
741
761
  handler_cell.border = self.thin_border
742
- handler_cell.value = _("Handler:")
762
+ handler_cell.value = _("Handler: {handler}").format(
763
+ handler=user.username
764
+ )
743
765
  sheet.merge_cells(f"A{handler_row_num}:C{handler_row_num}")
744
766
  set_row_height_in_inches(sheet, handler_row_num, 0.32)
745
767
 
@@ -786,6 +808,7 @@ class CanteenWorkBook:
786
808
 
787
809
  def fill_in_consumption_list_sheet(self):
788
810
  sheet = self.consumption_list_sheet
811
+ sheet.sheet_properties.tabColor = "ff9e16"
789
812
  user = self.user
790
813
  consumption_rows_count = 21
791
814
  categories = Category.objects.filter(
@@ -1087,7 +1110,22 @@ class CanteenWorkBook:
1087
1110
  )
1088
1111
  last_category = consumption.ingredient.category
1089
1112
 
1090
- sheet.cell(consumption_row_num, 2, consumption.ingredient.name)
1113
+ ingredient_name_cell = sheet.cell(consumption_row_num, 2)
1114
+ ingredient_name_cell.value = consumption.ingredient.name
1115
+ if consumption.ingredient.name:
1116
+ ingredient_name_cell.comment = Comment(
1117
+ _(
1118
+ "{meal_type}({category}, Storaged/Checked at {storage_date})."
1119
+ ).format(
1120
+ meal_type=consumption.ingredient.meal_type,
1121
+ category=consumption.ingredient.category,
1122
+ storage_date=consumption.ingredient.storage_date.strftime(
1123
+ "%Y.%m.%d"
1124
+ ),
1125
+ ),
1126
+ user.username,
1127
+ )
1128
+
1091
1129
  sheet.cell(
1092
1130
  consumption_row_num,
1093
1131
  3,
@@ -1097,8 +1135,8 @@ class CanteenWorkBook:
1097
1135
  consumption_row_num,
1098
1136
  4,
1099
1137
  (
1100
- consumption.ingredient.quantity
1101
- if consumption.ingredient.quantity
1138
+ consumption.amount_used
1139
+ if consumption.ingredient.name
1102
1140
  else ""
1103
1141
  ),
1104
1142
  )
@@ -1107,7 +1145,7 @@ class CanteenWorkBook:
1107
1145
  5,
1108
1146
  (
1109
1147
  consumption.ingredient.unit_price
1110
- if consumption.ingredient.unit_price
1148
+ if consumption.ingredient.name
1111
1149
  else ""
1112
1150
  ),
1113
1151
  )
@@ -1117,8 +1155,7 @@ class CanteenWorkBook:
1117
1155
  (
1118
1156
  consumption.ingredient.unit_price
1119
1157
  * consumption.amount_used
1120
- if consumption.ingredient.unit_price
1121
- and consumption.amount_used
1158
+ if consumption.ingredient.name
1122
1159
  else ""
1123
1160
  ),
1124
1161
  )
@@ -1164,6 +1201,7 @@ class CanteenWorkBook:
1164
1201
 
1165
1202
  def fill_in_storage_list_sheet(self):
1166
1203
  sheet = self.storage_list_sheet
1204
+ sheet.sheet_properties.tabColor = "16b1ff"
1167
1205
  user = self.user
1168
1206
  ingredient_rows_count = 21
1169
1207
  ingredients = Ingredient.objects.filter(
@@ -1465,7 +1503,7 @@ class CanteenWorkBook:
1465
1503
  signature_row_num = summary_row_num + 1
1466
1504
  signature_cell = sheet.cell(signature_row_num, 1)
1467
1505
  signature_cell.value = _(
1468
- " Reviewer: Handler:{handler}   Weigher: Warehouseman:  "
1506
+ " Reviewer: Handler: {handler}   Weigher: Warehouseman:  "
1469
1507
  ).format(handler=user.username)
1470
1508
  signature_cell.font = self.font_14
1471
1509
  signature_cell.alignment = self.center_alignment
@@ -1486,6 +1524,7 @@ class CanteenWorkBook:
1486
1524
 
1487
1525
  def fill_in_cover_sheet(self):
1488
1526
  sheet = self.cover_sheet
1527
+ sheet.sheet_properties.tabColor = "9416ff"
1489
1528
  user = self.user
1490
1529
  title_cell = sheet.cell(1, 1)
1491
1530
  title_cell.value = _(
@@ -1601,6 +1640,7 @@ class CanteenWorkBook:
1601
1640
 
1602
1641
  def fill_in_surplus_sheet(self):
1603
1642
  sheet = self.surplus_sheet
1643
+ sheet.sheet_properties.tabColor = "29ff16"
1604
1644
  user = self.user
1605
1645
  ingredient_rows_count = 17
1606
1646
 
@@ -1909,7 +1949,7 @@ class CanteenWorkBook:
1909
1949
  signature_row_num,
1910
1950
  1,
1911
1951
  _(
1912
- " Reviewer: Handler:{handler_name} Weigher: Warehouseman:   "
1952
+ " Reviewer: Handler: {handler_name} Weigher: Warehouseman:   "
1913
1953
  ).format(handler_name=user.username),
1914
1954
  )
1915
1955
  sheet.merge_cells(f"A{signature_row_num}:I{signature_row_num}")
@@ -1929,6 +1969,7 @@ class CanteenWorkBook:
1929
1969
 
1930
1970
  def fill_in_non_storage_list_sheet(self):
1931
1971
  sheet = self.non_storage_list_sheet
1972
+ sheet.sheet_properties.tabColor = "ff16ee"
1932
1973
  user = self.user
1933
1974
  ingredient_rows_count = 11
1934
1975
 
@@ -1946,6 +1987,7 @@ class CanteenWorkBook:
1946
1987
  category_ingredients = []
1947
1988
  for category in categories:
1948
1989
  _ingredients = [i for i in ingredients if i.category == category]
1990
+ _ingredients = sorted(_ingredients, key=lambda i: (i.storage_date))
1949
1991
  split_count = math.ceil(len(_ingredients) / ingredient_rows_count)
1950
1992
  for i in range(0, len(_ingredients), ingredient_rows_count):
1951
1993
  _split_ingredients = _ingredients[i : i + ingredient_rows_count]
@@ -1968,9 +2010,6 @@ class CanteenWorkBook:
1968
2010
  )
1969
2011
  ]
1970
2012
 
1971
- _split_ingredients = sorted(
1972
- _split_ingredients, key=lambda i: (i.storage_date)
1973
- )
1974
2013
  category_ingredients.append([category, _split_ingredients])
1975
2014
 
1976
2015
  for index, (category, c_ingredients) in enumerate(category_ingredients):
@@ -2125,16 +2164,512 @@ class CanteenWorkBook:
2125
2164
 
2126
2165
  def fill_in_food_sheets(self):
2127
2166
  user = self.request.user
2128
- date_start = self.date_start
2129
- date_end = self.date_end
2167
+ wb = self.wb
2168
+ year = datetime.now().year
2169
+ date_start = date(year, 1, 1)
2170
+ date_end = date(year, 12, 31)
2130
2171
  meal_type = self.meal_type
2131
2172
 
2132
- ingredients = Ingredient.objects.filter(
2133
- Q(is_disabled=False)
2134
- & Q(is_ignorable=False)
2135
- & Q(user=user)
2136
- & Q(meal_type=meal_type)
2137
- ).all()
2173
+ ingredients = (
2174
+ Ingredient.objects.filter(
2175
+ Q(is_disabled=False)
2176
+ & Q(is_ignorable=False)
2177
+ & Q(user=user)
2178
+ & Q(meal_type=meal_type)
2179
+ )
2180
+ .prefetch_related("consumptions")
2181
+ .all()
2182
+ )
2183
+ ingredients = [
2184
+ i
2185
+ for i in ingredients
2186
+ if date_start <= i.storage_date <= date_end
2187
+ or any(
2188
+ [
2189
+ date_start <= c.date_of_using <= date_end
2190
+ for c in i.consumptions.all()
2191
+ if c.is_disabled == False
2192
+ ]
2193
+ )
2194
+ ]
2195
+
2196
+ ingredient_names = list(set([i.name for i in ingredients]))
2197
+ for ingredient_name_index, ingredient_name in enumerate(
2198
+ ingredient_names
2199
+ ):
2200
+ sheet = wb.create_sheet(ingredient_name)
2201
+ sheet.sheet_properties.tabColor = "1689ff"
2202
+ named_ingredients = [
2203
+ i for i in ingredients if i.name == ingredient_name
2204
+ ]
2205
+ year_ingredient0 = named_ingredients[0]
2206
+
2207
+ year_storage_quantity = Decimal("0")
2208
+ year_storage_total_price = Decimal("0.0")
2209
+ year_consumption_quantity = Decimal("0")
2210
+ year_consumption_total_price = Decimal("0.0")
2211
+ ingredient_rows_count = 31
2212
+
2213
+ for col_index, col_width in [
2214
+ [1, 0.4],
2215
+ [2, 0.4],
2216
+ [3, 1.86],
2217
+ [4, 0.7],
2218
+ [5, 0.8],
2219
+ [6, 0.95],
2220
+ [7, 0.7],
2221
+ [8, 0.8],
2222
+ [9, 0.97],
2223
+ [10, 0.7],
2224
+ [11, 0.8],
2225
+ [12, 0.8],
2226
+ [13, 1.67],
2227
+ ]:
2228
+ set_column_width_in_inches(sheet, col_index, col_width)
2229
+
2230
+ for month_index in range(12):
2231
+ month = month_index + 1
2232
+
2233
+ ___, month_days = calendar.monthrange(year, month)
2234
+ month_day_1 = date(year, month, 1)
2235
+ month_day_n1 = date(year, month, month_days)
2236
+
2237
+ row_num = (ingredient_rows_count + 8) * month_index
2238
+ title_row_num = row_num + 1
2239
+ title_cell = sheet.cell(title_row_num, 1)
2240
+ title_cell.value = (
2241
+ _(
2242
+ "Ingredients Storage and Consumption Records of Principal Canteen"
2243
+ )
2244
+ if self.is_school
2245
+ else _(
2246
+ "Ingredients Storage and Consumption Records of Affiliation Canteen"
2247
+ )
2248
+ )
2249
+ title_cell.font = self.font_18_bold
2250
+ title_cell.alignment = self.center_alignment
2251
+ set_row_height_in_inches(sheet, title_row_num, 0.38)
2252
+ sheet.merge_cells(f"A{title_row_num}:M{title_row_num}")
2253
+
2254
+ ingredient_name_row_num = title_row_num + 1
2255
+
2256
+ for row_index in range(
2257
+ ingredient_name_row_num, ingredient_rows_count + 6 + 1
2258
+ ):
2259
+ set_row_height_in_inches(sheet, row_index, 0.22)
2260
+
2261
+ ingredient_name_cell = sheet.cell(ingredient_name_row_num, 1)
2262
+ ingredient_name_cell.value = _(
2263
+ "Ingredient Name: {ingredient_name} ({quantity_unit_name})"
2264
+ ).format(
2265
+ ingredient_name=ingredient_name,
2266
+ quantity_unit_name=year_ingredient0.quantity_unit_name,
2267
+ )
2268
+ ingredient_name_cell.alignment = self.left_alignment
2269
+ ingredient_name_cell.font = self.font_14
2270
+ sheet.merge_cells(
2271
+ f"A{ingredient_name_row_num}:M{ingredient_name_row_num}"
2272
+ )
2273
+
2274
+ year_header_row_num = ingredient_name_row_num + 1
2275
+
2276
+ for row_index in range(
2277
+ year_header_row_num, year_header_row_num + 1 + 1
2278
+ ):
2279
+ for col_index in range(1, 14):
2280
+ sheet.cell(row_index, col_index).border = (
2281
+ self.thin_border
2282
+ )
2283
+
2284
+ year_header_cell = sheet.cell(year_header_row_num, 1)
2285
+ year_header_cell.value = _("Year {year}").format(year=year)
2286
+ year_header_cell.font = self.font_14
2287
+ year_header_cell.alignment = self.center_alignment
2288
+ year_header_cell.border = self.thin_border
2289
+ sheet.merge_cells(
2290
+ f"A{year_header_row_num}:B{year_header_row_num}"
2291
+ )
2292
+
2293
+ storage_header_row_num = year_header_row_num
2294
+ storage_header_cell = sheet.cell(storage_header_row_num, 4)
2295
+ storage_header_cell.value = _("Storage (Food Sheet)")
2296
+ storage_header_cell.font = self.font_14
2297
+ storage_header_cell.alignment = self.center_alignment
2298
+ storage_header_cell.border = self.thin_border
2299
+ sheet.merge_cells(
2300
+ f"D{storage_header_row_num}:F{storage_header_row_num}"
2301
+ )
2302
+
2303
+ consumption_header_row_num = year_header_row_num
2304
+ consumption_header_cell = sheet.cell(
2305
+ consumption_header_row_num, 7
2306
+ )
2307
+ consumption_header_cell.value = _("Consumption (Food Sheet)")
2308
+ consumption_header_cell.font = self.font_14
2309
+ consumption_header_cell.alignment = self.center_alignment
2310
+ consumption_header_cell.border = self.thin_border
2311
+ sheet.merge_cells(
2312
+ f"G{consumption_header_row_num}:I{consumption_header_row_num}"
2313
+ )
2314
+
2315
+ surplus_header_row_num = year_header_row_num
2316
+ surplus_header_cell = sheet.cell(surplus_header_row_num, 10)
2317
+ surplus_header_cell.value = _("Surplus (Food Sheet)")
2318
+ surplus_header_cell.font = self.font_14
2319
+ surplus_header_cell.alignment = self.center_alignment
2320
+ surplus_header_cell.border = self.thin_border
2321
+ sheet.merge_cells(
2322
+ f"J{surplus_header_row_num}:L{surplus_header_row_num}"
2323
+ )
2324
+
2325
+ num_header_row_num = year_header_row_num
2326
+ num_header_cell = sheet.cell(num_header_row_num, 13)
2327
+ num_header_cell.value = _(
2328
+ "Storage/Consumption No. (Food Sheet)"
2329
+ )
2330
+ num_header_cell.font = self.font_14
2331
+ num_header_cell.alignment = self.center_alignment
2332
+ num_header_cell.border = self.thin_border
2333
+ sheet.merge_cells(
2334
+ f"M{num_header_row_num}:M{num_header_row_num+1}"
2335
+ )
2336
+
2337
+ month_header_row_num = year_header_row_num + 1
2338
+ month_header_cell = sheet.cell(month_header_row_num, 1)
2339
+ month_header_cell.value = _("Month (Food Sheet)")
2340
+ month_header_cell.font = self.font_14
2341
+ month_header_cell.alignment = self.center_alignment
2342
+ month_header_cell.border = self.thin_border
2343
+
2344
+ day_header_row_num = year_header_row_num + 1
2345
+ day_header_cell = sheet.cell(day_header_row_num, 2)
2346
+ day_header_cell.value = _("Day (Food Sheet)")
2347
+ day_header_cell.font = self.font_14
2348
+ day_header_cell.alignment = self.center_alignment
2349
+ day_header_cell.border = self.thin_border
2350
+
2351
+ price_header_row_num = day_header_row_num
2352
+ for col_index in range(4, 13, 3):
2353
+ quantity_header_col_num = col_index
2354
+ unit_price_header_col_num = col_index + 1
2355
+ total_price_header_col_num = col_index + 2
2356
+
2357
+ quantity_header_cell = sheet.cell(
2358
+ price_header_row_num, quantity_header_col_num
2359
+ )
2360
+ quantity_header_cell.value = _("Quantity (Food Sheet)")
2361
+ quantity_header_cell.font = self.font_14
2362
+ quantity_header_cell.alignment = self.center_alignment
2363
+ quantity_header_cell.border = self.thin_border
2364
+
2365
+ unit_price_header_cell = sheet.cell(
2366
+ price_header_row_num, unit_price_header_col_num
2367
+ )
2368
+ unit_price_header_cell.value = _("Unit Price (Food Sheet)")
2369
+ unit_price_header_cell.font = self.font_14
2370
+ unit_price_header_cell.alignment = self.center_alignment
2371
+ unit_price_header_cell.border = self.thin_border
2372
+
2373
+ total_price_header_cell = sheet.cell(
2374
+ price_header_row_num, total_price_header_col_num
2375
+ )
2376
+ total_price_header_cell.value = _(
2377
+ "Total Price (Food Sheet)"
2378
+ )
2379
+ total_price_header_cell.font = self.font_14
2380
+ total_price_header_cell.alignment = self.center_alignment
2381
+ total_price_header_cell.border = self.thin_border
2382
+
2383
+ month_surplus_header_row_num = month_header_row_num + 1
2384
+ month_surplus_header_cell = sheet.cell(
2385
+ month_surplus_header_row_num, 3
2386
+ )
2387
+ month_surplus_header_cell.value = (
2388
+ _("Surplus for last month")
2389
+ if month > 1
2390
+ else _("Surplus for last year")
2391
+ )
2392
+
2393
+ date_day_1 = month_day_1
2394
+ _date_day_1 = date_day_1 + timedelta(days=-1)
2395
+
2396
+ if any(
2397
+ [i.storage_date < date_day_1 for i in named_ingredients]
2398
+ ):
2399
+ remaining_quantity_last_month = sum(
2400
+ [
2401
+ i.get_remaining_quantity(_date_day_1)
2402
+ for i in named_ingredients
2403
+ ]
2404
+ )
2405
+ remaining_total_price_last_month = sum(
2406
+ [
2407
+ i.unit_price * i.get_remaining_quantity(_date_day_1)
2408
+ for i in named_ingredients
2409
+ ]
2410
+ )
2411
+ unit_price = (
2412
+ Decimal(str(remaining_total_price_last_month))
2413
+ / Decimal(str(remaining_quantity_last_month))
2414
+ if remaining_quantity_last_month
2415
+ else Decimal("0.0")
2416
+ )
2417
+
2418
+ sheet.cell(
2419
+ month_surplus_header_row_num,
2420
+ 4,
2421
+ remaining_quantity_last_month,
2422
+ )
2423
+ sheet.cell(
2424
+ month_surplus_header_row_num,
2425
+ 6,
2426
+ remaining_total_price_last_month,
2427
+ )
2428
+ sheet.cell(
2429
+ month_surplus_header_row_num, 5, unit_price.normalize()
2430
+ )
2431
+
2432
+ month_ingredients = []
2433
+ storage_dates = list(
2434
+ set(
2435
+ [
2436
+ i.storage_date
2437
+ for i in ingredients
2438
+ if month_day_1 <= i.storage_date <= month_day_n1
2439
+ ]
2440
+ )
2441
+ )
2442
+ consumption_dates = []
2443
+ for i in ingredients:
2444
+ consumptions = [
2445
+ c for c in i.consumptions.all() if not c.is_disabled
2446
+ ]
2447
+ for c in consumptions:
2448
+ if (
2449
+ month_day_1 <= c.date_of_using <= month_day_n1
2450
+ and not c.date_of_using in consumption_dates
2451
+ ):
2452
+ consumption_dates.append(c.date_of_using)
2453
+
2454
+ storage_dates = sorted(storage_dates)
2455
+ consumption_dates = sorted(consumption_dates)
2456
+
2457
+ for ingredient in named_ingredients:
2458
+ consumptions = [
2459
+ c
2460
+ for c in ingredient.consumptions.all()
2461
+ if not c.is_disabled
2462
+ ]
2463
+ ingredient_consumption_dates = [
2464
+ c.date_of_using for c in consumptions
2465
+ ]
2466
+ if month_day_1 <= ingredient.storage_date <= month_day_n1:
2467
+ month_ingredients.append(ingredient)
2468
+ elif any(
2469
+ [
2470
+ month_day_1 <= consumption_date <= month_day_n1
2471
+ for consumption_date in ingredient_consumption_dates
2472
+ ]
2473
+ ):
2474
+ month_ingredients.append(ingredient)
2475
+
2476
+ month_storage_quantity = Decimal("0")
2477
+ month_storage_total_price = Decimal("0.0")
2478
+ month_consumption_quantity = Decimal("0")
2479
+ month_consumption_total_price = Decimal("0.0")
2480
+
2481
+ for day_index in range(ingredient_rows_count):
2482
+
2483
+ if day_index + 1 <= month_days:
2484
+ day = date(year, month, day_index + 1)
2485
+ ingredient_row_num = (
2486
+ month_surplus_header_row_num + 1 + day_index
2487
+ )
2488
+ sheet.cell(ingredient_row_num, 1, day.month)
2489
+ sheet.cell(ingredient_row_num, 2, day.day)
2490
+ storage_quantity = sum(
2491
+ [
2492
+ i.quantity
2493
+ for i in month_ingredients
2494
+ if i.storage_date == day
2495
+ ]
2496
+ )
2497
+ storage_total_price = sum(
2498
+ [
2499
+ i.total_price
2500
+ for i in month_ingredients
2501
+ if i.storage_date == day
2502
+ ]
2503
+ )
2504
+ storage_unit_price = (
2505
+ Decimal(str(storage_total_price))
2506
+ / Decimal(str(storage_quantity))
2507
+ if storage_quantity
2508
+ else Decimal("0.0")
2509
+ )
2510
+ storage_unit_price = storage_unit_price.normalize()
2511
+ if storage_quantity:
2512
+ sheet.cell(ingredient_row_num, 4, storage_quantity)
2513
+ sheet.cell(
2514
+ ingredient_row_num, 5, storage_unit_price
2515
+ )
2516
+ sheet.cell(
2517
+ ingredient_row_num, 6, storage_total_price
2518
+ )
2519
+
2520
+ consumption_quantity = Decimal("0")
2521
+ consumption_total_price = Decimal("0.0")
2522
+
2523
+ for i in month_ingredients:
2524
+ for c in [
2525
+ c
2526
+ for c in i.consumptions.all()
2527
+ if not c.is_disabled
2528
+ ]:
2529
+ if c.date_of_using == day:
2530
+ consumption_quantity += c.amount_used
2531
+ consumption_total_price += (
2532
+ c.amount_used * i.unit_price
2533
+ )
2534
+
2535
+ consumption_unit_price = (
2536
+ (consumption_total_price / consumption_quantity)
2537
+ if consumption_quantity
2538
+ else Decimal("0.0")
2539
+ )
2540
+ consumption_unit_price = (
2541
+ f"{consumption_unit_price:.{decimal_prec}f}"
2542
+ )
2543
+
2544
+ if consumption_quantity:
2545
+ sheet.cell(
2546
+ ingredient_row_num, 7, consumption_quantity
2547
+ )
2548
+ sheet.cell(
2549
+ ingredient_row_num, 8, consumption_unit_price
2550
+ )
2551
+ sheet.cell(
2552
+ ingredient_row_num, 9, consumption_total_price
2553
+ )
2554
+
2555
+ surplus_quantity = Decimal("0")
2556
+ surplus_total_price = Decimal("0.0")
2557
+ for i in month_ingredients:
2558
+ if i.storage_date > day:
2559
+ continue
2560
+ remaining_quantity = i.get_remaining_quantity(day)
2561
+ surplus_quantity += remaining_quantity
2562
+ surplus_total_price += (
2563
+ remaining_quantity * i.unit_price
2564
+ )
2565
+ surplus_unit_price = (
2566
+ (surplus_total_price / surplus_quantity)
2567
+ if surplus_quantity
2568
+ else Decimal("0.0")
2569
+ )
2570
+ surplus_unit_price = (
2571
+ f"{surplus_unit_price:.{decimal_prec}f}"
2572
+ )
2573
+
2574
+ if surplus_quantity:
2575
+ sheet.cell(ingredient_row_num, 10, surplus_quantity)
2576
+ sheet.cell(
2577
+ ingredient_row_num, 11, surplus_unit_price
2578
+ )
2579
+ sheet.cell(
2580
+ ingredient_row_num, 12, surplus_total_price
2581
+ )
2582
+ elif consumption_quantity:
2583
+ sheet.cell(ingredient_row_num, 10, "0")
2584
+ sheet.cell(ingredient_row_num, 11, "")
2585
+ sheet.cell(ingredient_row_num, 12, "0")
2586
+
2587
+ num_value = ""
2588
+ if storage_quantity:
2589
+ storage_num = storage_dates.index(day) + 1
2590
+ num_value += (
2591
+ (f"R{month:0>2}{storage_num:0>2}")
2592
+ if self.is_zh_CN
2593
+ else (f"S{month:0>2}{storage_num:0>2}")
2594
+ )
2595
+
2596
+ if consumption_quantity:
2597
+ if not num_value == "":
2598
+ num_value += _("and (Food Sheet)")
2599
+ consumption_num = consumption_dates.index(day) + 1
2600
+ num_value += (
2601
+ (f"C{month:0>2}{consumption_num:0>2}")
2602
+ if self.is_zh_CN
2603
+ else (f"C{month:0>2}{consumption_num:0>2}")
2604
+ )
2605
+
2606
+ sheet.cell(ingredient_row_num, 13, num_value)
2607
+
2608
+ month_storage_quantity += storage_quantity
2609
+ month_storage_total_price += storage_total_price
2610
+ month_consumption_quantity += consumption_quantity
2611
+ month_consumption_total_price += consumption_total_price
2612
+
2613
+ year_storage_quantity += storage_quantity
2614
+ year_storage_total_price += storage_total_price
2615
+ year_consumption_quantity += consumption_quantity
2616
+ year_consumption_total_price += consumption_total_price
2617
+
2618
+ for row_index in range(
2619
+ month_surplus_header_row_num,
2620
+ month_surplus_header_row_num
2621
+ + ingredient_rows_count
2622
+ + 2
2623
+ + 1,
2624
+ ):
2625
+ for col_index in range(1, 13 + 1):
2626
+ cell = sheet.cell(row_index, col_index)
2627
+ cell.font = self.font_12
2628
+ cell.alignment = self.center_alignment
2629
+ cell.border = self.thin_border
2630
+
2631
+ month_summary_row_num = (
2632
+ year_header_row_num + 2 + ingredient_rows_count + 1
2633
+ )
2634
+ year_accumulation_row_num = month_summary_row_num + 1
2635
+
2636
+ sheet.cell(month_summary_row_num, 3, _("Monthly Summary"))
2637
+ sheet.cell(month_summary_row_num, 4, month_storage_quantity)
2638
+ sheet.cell(month_summary_row_num, 6, month_storage_total_price)
2639
+ sheet.cell(month_summary_row_num, 7, month_consumption_quantity)
2640
+ sheet.cell(
2641
+ month_summary_row_num, 9, month_consumption_total_price
2642
+ )
2643
+
2644
+ sheet.cell(year_accumulation_row_num, 3, _("Year Accumulation"))
2645
+ sheet.cell(year_accumulation_row_num, 4, year_storage_quantity)
2646
+ sheet.cell(
2647
+ year_accumulation_row_num, 6, year_storage_total_price
2648
+ )
2649
+ sheet.cell(
2650
+ year_accumulation_row_num, 7, year_consumption_quantity
2651
+ )
2652
+ sheet.cell(
2653
+ year_accumulation_row_num,
2654
+ 9,
2655
+ year_consumption_total_price,
2656
+ )
2657
+
2658
+ note_row_num = year_accumulation_row_num + 1
2659
+ sheet.cell(
2660
+ note_row_num,
2661
+ 2,
2662
+ (
2663
+ _(
2664
+ "Note: The 'Principal Canteen Material Storage and Outbound Ledger' is registered on a daily basis based on the storage and outbound receipts."
2665
+ )
2666
+ if self.is_school
2667
+ else _(
2668
+ "Note: The 'Affiliation Canteen Material Storage and Outbound Ledger' is registered on a daily basis based on the storage and outbound receipts."
2669
+ )
2670
+ ),
2671
+ )
2672
+ sheet.merge_cells(f"B{note_row_num}:M{note_row_num}")
2138
2673
 
2139
2674
  def fill_in(self):
2140
2675
  self.fill_in_cover_sheet()
@@ -2145,12 +2680,14 @@ class CanteenWorkBook:
2145
2680
  self.fill_in_consumption_sheet()
2146
2681
  self.fill_in_consumption_list_sheet()
2147
2682
  self.fill_in_surplus_sheet()
2148
- # self.fill_in_food_sheets()
2683
+ self.fill_in_food_sheets()
2149
2684
 
2150
2685
  return self.wb
2151
2686
 
2152
2687
 
2153
2688
  def get_workbook_zip(request, month):
2689
+ from ..views import meal_type_name_0
2690
+
2154
2691
  meal_types = MealType.objects.annotate(
2155
2692
  ingredients_count=Count("ingredients")
2156
2693
  ).filter(
@@ -2166,7 +2703,7 @@ def get_workbook_zip(request, month):
2166
2703
  ).format(
2167
2704
  meal_type=(
2168
2705
  (meal_type.abbreviation or meal_type.name)
2169
- if meal_type
2706
+ if not meal_type.name == meal_type_name_0
2170
2707
  else ""
2171
2708
  ),
2172
2709
  month=month.replace("-", ""),