fnschool 20241126.81759.821__py3-none-any.whl → 20250109.80500.803__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. fnschool/__init__.py +2 -2
  2. fnschool/canteen/bill.py +11 -2
  3. fnschool/canteen/currency.py +1 -1
  4. fnschool/canteen/entry.py +7 -1
  5. fnschool/canteen/spreadsheet/base.py +23 -2
  6. fnschool/canteen/spreadsheet/consumingsum.py +13 -7
  7. fnschool/canteen/spreadsheet/ctspreadsheet.py +1 -1
  8. fnschool/canteen/spreadsheet/food.py +59 -3
  9. fnschool/canteen/spreadsheet/merging.py +4 -7
  10. fnschool/canteen/spreadsheet/preconsuming.py +10 -6
  11. fnschool/canteen/spreadsheet/purchasing.py +8 -8
  12. fnschool/canteen/spreadsheet/purchasingsum.py +28 -14
  13. fnschool/canteen/spreadsheet/spreadsheet.py +1 -1
  14. fnschool/canteen/spreadsheet/translating.py +12 -0
  15. fnschool/entry.py +15 -9
  16. fnschool/exam/email.py +3 -3
  17. fnschool/exam/entry.py +4 -4
  18. fnschool/exam/score.py +8 -8
  19. fnschool/external.py +1 -1
  20. fnschool/{show.py → inoutput.py} +1 -1
  21. fnschool/locales/en_US/LC_MESSAGES/fnschool.mo +0 -0
  22. fnschool/locales/zh_CN/LC_MESSAGES/fnschool.mo +0 -0
  23. fnschool/locales/zh_HK/LC_MESSAGES/fnschool.mo +0 -0
  24. fnschool/locales/zh_SG/LC_MESSAGES/fnschool.mo +0 -0
  25. fnschool/locales/zh_TW/LC_MESSAGES/fnschool.mo +0 -0
  26. fnschool/path.py +1 -1
  27. fnschool/user.py +5 -5
  28. {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/METADATA +2 -2
  29. {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/RECORD +33 -33
  30. {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/WHEEL +1 -1
  31. fnschool/canteen/workbook.py +0 -2661
  32. {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/LICENSE +0 -0
  33. {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/entry_points.txt +0 -0
  34. {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/top_level.txt +0 -0
@@ -1,2661 +0,0 @@
1
- import os
2
- import sys
3
-
4
- import pandas as pd
5
- import numpy as np
6
- import uuid
7
-
8
- import secrets
9
- from datetime import datetime
10
- import calendar
11
- from openpyxl import load_workbook
12
- from openpyxl.styles import *
13
- from openpyxl.formatting.rule import *
14
- from openpyxl.styles.differential import *
15
- from openpyxl.utils.cell import *
16
-
17
-
18
- from openpyxl.utils import range_boundaries
19
- from fnschool import *
20
- from fnschool.canteen import *
21
- from fnschool.language import *
22
- from fnschool.canteen.food import *
23
- from fnschool.canteen.bill import *
24
- from fnschool.canteen.path import *
25
- from fnschool.canteen.config import *
26
-
27
-
28
- class WorkBook:
29
- def __init__(self, bill):
30
- self.bill = bill
31
- self.check_sheet_name = "清点表"
32
- self.unit_sheet_name = "计量单位表"
33
- self.warehousing_sheet_name = "入库单"
34
- self.unwarehousing_sheet_name = "未入库明细表"
35
- self.consuming_sum_sheet_name = "出库汇总表"
36
- self.consuming_sheet_name = "出库单"
37
- self.inventory_sheet_name = "食材盘存表"
38
- self.food_sheet0_name = "材料台账母表"
39
- self.pre_consuming_sheet0_name = "简易出库母表"
40
- self.base_class_sheet_name = "大类表"
41
- self.pre_consuming_sheet_name_prefix = "出库表"
42
- self.purchase_sum_sheet_name = "入库、未入库汇总表"
43
- self.cover_sheet_name = "六大类总封面"
44
- self.pre_consuming_sheet0_name = "出库计划表"
45
- self._recounts = None
46
- self.food_name_col_names = ["商品名称", "食材名称", "商品名", "食材名"]
47
- self.purchase_sheet_names = [
48
- "食堂购入表",
49
- "客户商品销售报表",
50
- "客户送货明细报表",
51
- ]
52
- self.negligible_col_names = [
53
- "忽略",
54
- "不计",
55
- "非入库",
56
- "可忽略",
57
- "非盘点",
58
- ]
59
- self.residue_col_names = [
60
- "上季结余",
61
- "是剩余",
62
- "是结余",
63
- "上年结余",
64
- "剩余",
65
- "结余",
66
- ]
67
- self.org_col_names = ["客户名称"]
68
- self.total_price_col_names = ["金额", "折后金额", "总价", "折前金额"]
69
- self.count_col_names = [
70
- "数量",
71
- "记账数量",
72
- "订货数量",
73
- "订货总量",
74
- "订货总数量",
75
- ]
76
- self.unit_name_col_names = ["单位", "订货单位"]
77
- self.xdate_col_names = ["送货日期", "送货时间"]
78
- self.warehousing_form_index_offset = 0
79
- self.inventory_form_index_offset = 1
80
- self.bill_workbook = None
81
- self.pre_consuming_workbook0 = None
82
- self._main_spreadsheet_path = None
83
- self._check_df = None
84
- self._unit_name_list = None
85
- self._unit_df = None
86
- self._negligible_class_list = None
87
- self._base_class_df = None
88
- self.purchase_workbook_fdpath = None
89
- self.pre_consuming_sheet_col_index_offset = 5
90
- self.pre_consuming_sheet_row_index_offset = 3
91
- self.spreadsheet_ext_names = ["xlsx"]
92
- self.cell_alignment0 = Alignment(horizontal="center", vertical="center")
93
- self.cell_side0 = Side(border_style="thin")
94
- self.cell_border0 = Border(
95
- top=self.cell_side0,
96
- left=self.cell_side0,
97
- right=self.cell_side0,
98
- bottom=self.cell_side0,
99
- )
100
- self.purchase_sheets_properties = []
101
- self.excluded_purchase_sheets = []
102
-
103
- def get_recounts(self):
104
- if self._recounts is None:
105
- self._recounts = get_food_recounts_config()
106
- return self._recounts
107
-
108
- @property
109
- def profile(self):
110
- return self.bill.profile
111
-
112
- @property
113
- def food(self):
114
- return self.bill.food
115
-
116
- def get_pre_consuming_workbook0(self):
117
- if not self.pre_consuming_workbook0:
118
- self.pre_consuming_workbook0 = load_workbook(pre_consuming0_fpath)
119
- return self.pre_consuming_workbook0
120
-
121
- def get_pre_consuming_workbook_fpath(self, time_node=None):
122
- time_node = time_node or self.bill.get_time_node()
123
- t0, t1 = time_node
124
- ext = pre_consuming0_fpath.as_posix().split(".")[-1]
125
- consuming_fpath = (
126
- pre_consuming0_fpath.as_posix()[: -len(ext) - 1]
127
- + "."
128
- + t0.strftime("%Y%m%d")
129
- + t1.strftime("%Y%m%d")
130
- + "."
131
- + ext
132
- )
133
- consuming_fpath = (
134
- self.get_profile_copy_data_dpath()
135
- / consuming_fpath.split(os.sep)[-1]
136
- )
137
- return consuming_fpath
138
-
139
- def get_pre_consuming_workbook(self, time_node=None, new_foods=None):
140
- pre_consuming_fpath = self.get_pre_consuming_workbook_fpath()
141
- if not pre_consuming_fpath.exists():
142
- print_warning(_("Workbook {0} doesn't exist."))
143
- return None
144
- workbook = load_workbook(pre_consuming_fpath.as_posix())
145
- return workbook
146
-
147
- def get_pre_consuming_sheet_of_time_node(self, new_foods=None):
148
- pre_consuming_fpath = self.get_pre_consuming_workbook_fpath()
149
- if not pre_consuming_fpath.exists():
150
- shutil.copy(pre_consuming0_fpath, pre_consuming_fpath)
151
- print_info(
152
- _("Spreadsheet {0} was copied to {1} .").format(
153
- pre_consuming0_fpath, pre_consuming_fpath
154
- )
155
- )
156
- print_warning(
157
- _(
158
- "Please design the consumptions of spreadsheet '{0}' ."
159
- ).format(pre_consuming_fpath)
160
- )
161
- self.design_pre_consuming_sheet(new_foods=new_foods)
162
- wb = load_workbook(pre_consuming_fpath.as_posix())
163
- sheet = wb[self.pre_consuming_sheet0_name]
164
- return [wb, sheet]
165
-
166
- def get_conver_sheet(self):
167
- return self.get_bill_sheet(self.cover_sheet_name)
168
-
169
- def get_purchase_sum_sheet(self):
170
- return self.get_bill_sheet(self.purchase_sum_sheet_name)
171
-
172
- def get_consuming_sum_sheet(self):
173
- return self.get_bill_sheet(self.consuming_sum_sheet_name)
174
-
175
- def get_days_of_pre_consuming_sheet(self, name):
176
- t0, t1 = self.get_time_node_of_pre_consuming_sheet(name)
177
- return (t1 - t0).days + 1
178
-
179
- def get_time_node_of_pre_consuming_sheet(self, name):
180
- pcsheet = self.get_bill_sheet(name)
181
- t0 = pcsheet.cell(
182
- 1, self.pre_consuming_sheet_col_index_offset
183
- ).value.split(".")
184
- t0 = datetime(int(t0[0]), int(t0[1]), int(t0[2]))
185
- time_node = [t0, None]
186
- for col_index in range(
187
- self.pre_consuming_sheet_col_index_offset, pcsheet.max_column
188
- ):
189
- cell_value = pcsheet.cell(1, col_index).value
190
- if not cell_value:
191
- t1 = pcsheet.cell(1, col_index - 1).value.split(".")
192
- t1 = datetime(int(t1[0]), int(t1[1]), int(t1[2]))
193
- time_node[1] = t1
194
- return time_node
195
-
196
- return None
197
-
198
- def get_base_class_names(self, include_negligible_name=False):
199
- df = self.get_base_class_df()
200
- names = df.index.tolist()
201
- return names[:-1]
202
-
203
- def get_base_class_names_include_negligible_name(self):
204
- return self.get_base_class_names(include_negligible_name=True)
205
-
206
- def get_base_class_df(self):
207
- return self.get_base_class_df_from_spreadsheet()
208
-
209
- def get_base_class_df_from_spreadsheet(self, sheet_name="大类表"):
210
- if not self._base_class_df is None:
211
- return self._base_class_df
212
-
213
- base_class_df = pd.read_excel(
214
- self.bill.workbook.get_main_spreadsheet_path(),
215
- sheet_name=sheet_name,
216
- )
217
- self._base_class_df = base_class_df.T
218
- return self._base_class_df
219
-
220
- def get_negligible_class_list(self):
221
- if not self._negligible_class_list is None:
222
- return self._negligible_class_list
223
- self._negligible_class_list = (
224
- self.get_base_class_df().loc["非入库类"].to_list()
225
- )
226
- return self._negligible_class_list
227
-
228
- def get_unit_name_list(self):
229
- if not self._unit_name_list is None:
230
- return self._unit_name_list
231
- unit_df = self.get_unit_df()
232
- self._unit_name_list = unit_df["Name"].tolist()
233
- return self._unit_name_list
234
-
235
- def get_sheet_names(self):
236
- wb = self.get_bill_workbook()
237
- return wb.sheetnames
238
-
239
- def includes_sheet(self, sheet):
240
- if isinstance(sheet, str):
241
- name = sheet
242
- else:
243
- name = sheet.title
244
- names = self.get_sheet_names()
245
- if name.endswith("*"):
246
- name = name.replace("*", "")
247
- return any(_name.startswith(name) for _name in names)
248
- return name in names
249
-
250
- def get_consuming_n_by_time_node(self, time_node):
251
- time_nodes = self.bill.get_time_nodes()
252
- time_nodes = [t for t in time_nodes if t[0].month == time_node.month]
253
- n_index = 0
254
- for t0, t1 in time_nodes:
255
- time_range = [
256
- t0 + timedelta(days=i) for i in range((t1 - t0).days + 1)
257
- ]
258
- if time_node in time_range:
259
- n_index += time_range.index(time_node) + 1
260
- else:
261
- n_index += len(time_range)
262
- return n_index
263
-
264
- def format_inventory_sheet(self):
265
- isheet = self.get_inventory_sheet()
266
- self.unmerge_cells_of_sheet(isheet)
267
-
268
- for row in isheet.iter_rows(
269
- min_row=1, max_row=isheet.max_row, min_col=1, max_col=9
270
- ):
271
- isheet.row_dimensions[row[0].row].height = 14.25
272
-
273
- if row[8].value and "原因" in str(row[8].value).replace(" ", ""):
274
- isheet.merge_cells(
275
- start_row=row[0].row,
276
- end_row=row[0].row + 1,
277
- start_column=9,
278
- end_column=9,
279
- )
280
-
281
- if row[6].value and str(row[6].value).replace(" ", "") == "差额栏":
282
- isheet.merge_cells(
283
- start_row=row[0].row,
284
- end_row=row[0].row,
285
- start_column=7,
286
- end_column=8,
287
- )
288
-
289
- if row[4].value and str(row[4].value).replace(" ", "") == "盘点栏":
290
- isheet.merge_cells(
291
- start_row=row[0].row,
292
- end_row=row[0].row,
293
- start_column=5,
294
- end_column=6,
295
- )
296
-
297
- if row[2].value and str(row[2].value).replace(" ", "") == "账面栏":
298
- isheet.merge_cells(
299
- start_row=row[0].row,
300
- end_row=row[0].row,
301
- start_column=3,
302
- end_column=4,
303
- )
304
-
305
- if row[0].value and row[0].value.replace(" ", "") == "食材名称":
306
- isheet.merge_cells(
307
- start_row=row[0].row,
308
- end_row=row[0].row + 1,
309
- start_column=1,
310
- end_column=1,
311
- )
312
-
313
- if row[0].value and (
314
- "备注" in row[0].value.replace(" ", "")
315
- or "审核人" in row[0].value.replace(" ", "")
316
- ):
317
- isheet.merge_cells(
318
- start_row=row[0].row,
319
- end_row=row[0].row,
320
- start_column=1,
321
- end_column=9,
322
- )
323
-
324
- if row[0].value and row[0].value.replace(" ", "") == "食材盘存表":
325
- isheet.merge_cells(
326
- start_row=row[0].row,
327
- end_row=row[0].row,
328
- start_column=1,
329
- end_column=9,
330
- )
331
- isheet.row_dimensions[row[0].row].height = 22.5
332
-
333
- isheet.merge_cells(
334
- start_row=row[0].row + 1,
335
- end_row=row[0].row + 1,
336
- start_column=1,
337
- end_column=9,
338
- )
339
-
340
- def update_inventory_sheet(self):
341
- isheet = self.get_inventory_sheet()
342
- tnfoods = self.food.get_residue_foods(self.bill.month)
343
- form_indexes = self.get_inventory_form_indexes()
344
-
345
- for form_index_n in range(0, len(form_indexes)):
346
- form_index = form_indexes[form_index_n]
347
- form_index0, form_index1 = form_index
348
- food_index0 = form_index0 + 3
349
- food_index1 = form_index1 - 1
350
- for row in isheet.iter_rows(
351
- min_row=food_index0,
352
- max_row=food_index1,
353
- min_col=1,
354
- max_col=9,
355
- ):
356
- for cell in row:
357
- cell.value = ""
358
-
359
- for i, (tn, _foods) in enumerate(tnfoods):
360
- form_indexes_n = i
361
- t0, t1 = tn
362
- form_index = form_indexes[form_indexes_n]
363
- form_i0, form_i1 = form_index
364
- fentry_i0 = form_i0 + 3
365
- fentry_i1 = form_i1 - 1
366
-
367
- self.unmerge_cells_of_sheet(isheet)
368
-
369
- isheet.cell(
370
- form_i0,
371
- 1,
372
- f" "
373
- + f"学校名称:{self.bill.profile.org_name}"
374
- + f" "
375
- + f"{t1.year} 年 {t1.month} 月 {t1.day} 日"
376
- + f" ",
377
- )
378
-
379
- for row in isheet.iter_rows(
380
- min_row=fentry_i0,
381
- max_row=fentry_i1,
382
- min_col=1,
383
- max_col=9,
384
- ):
385
- for cell in row:
386
- cell.value = ""
387
- cell.alignment = self.cell_alignment0
388
- cell.border = self.cell_border0
389
-
390
- for findex, food in enumerate(_foods):
391
- row_index = fentry_i0 + findex
392
- if (
393
- isheet.cell(row_index + 1, 1).value.replace(" ", "")
394
- == "合计"
395
- ):
396
- isheet.insert_rows(row_index + 1, 1)
397
- isheet.cell(row_index, 1, food.name)
398
- isheet.cell(row_index, 2, food.unit_name)
399
- isheet.cell(row_index, 3, food.get_remainder_by_time(tn[1]))
400
- isheet.cell(
401
- row_index,
402
- 4,
403
- food.get_remainder_by_time(tn[1]) * food.unit_price,
404
- )
405
- isheet.cell(row_index, 5, food.get_remainder_by_time(tn[1]))
406
- isheet.cell(
407
- row_index,
408
- 6,
409
- food.get_remainder_by_time(tn[1]) * food.unit_price,
410
- )
411
-
412
- self.format_inventory_sheet()
413
-
414
- wb = self.get_bill_workbook()
415
- wb.active = isheet
416
- print_info(_("Sheet '%s' was updated.") % (self.inventory_sheet_name))
417
-
418
- def update_check_sheet_by_time_node_m1(self):
419
- cksheet = self.get_check_sheet()
420
- rfoods = self.food.get_foods_from_pre_consuming_sheet_m1()
421
- time_node = self.bill.time_node
422
- t0, t1 = time_node
423
- rfoods = [f for f in rfoods if f.get_remainder() > 0.0]
424
-
425
- for food in rfoods:
426
- food_exists = False
427
- for row in cksheet.iter_rows(
428
- min_row=2, max_row=cksheet.max_row + 1, min_col=1, max_col=2
429
- ):
430
- if row[0].value == food.fid and row[1].value == t1.strftime(
431
- "%Y%m%d"
432
- ):
433
- food_exists = True
434
- break
435
- if food_exists:
436
- continue
437
- cksheet.insert_rows(2, 1)
438
- cksheet.cell(2, 1, food.fid)
439
- cksheet.cell(2, 2, t1.strftime("%Y%m%d"))
440
- cksheet.cell(2, 3, food.name)
441
- cksheet.cell(2, 4, food.get_remainder())
442
- cksheet.cell(2, 5, food.get_remainder() * food.unit_price)
443
- cksheet.cell(2, 6, "Y")
444
-
445
- wb = self.get_bill_workbook()
446
- wb.active = cksheet
447
- print_info(_("Sheet '%s' was updated.") % (self.check_sheet_name))
448
-
449
- def unmerge_cells_of_sheet(self, sheet):
450
- if isinstance(sheet, str):
451
- sheet = self.get_bill_sheet(sheet)
452
- merged_ranges = list(sheet.merged_cells.ranges)
453
- for cell_group in merged_ranges:
454
- sheet.unmerge_cells(str(cell_group))
455
-
456
- def update_cover_sheet(self):
457
- time_nodes = self.bill.get_time_nodes()
458
- t0, t1 = time_nodes[-1]
459
- cvsheet = self.get_conver_sheet()
460
- cvsheet.cell(
461
- 1,
462
- 1,
463
- self.bill.profile.org_name
464
- + f"{t1.year}年{t1.month}月份食堂食品采购统计表",
465
- )
466
- foods = [
467
- f
468
- for f in self.food.get_foods()
469
- if (not f.is_residue and f.xdate.month == self.bill.month)
470
- ]
471
- wfoods = [f for f in foods if not f.is_negligible]
472
- uwfoods = [f for f in foods if f.is_negligible]
473
- total_price = 0.0
474
- for row in cvsheet.iter_rows(
475
- min_row=3, max_row=9, min_col=1, max_col=3
476
- ):
477
- class_name = row[0].value.replace(" ", "")
478
- _total_price = 0.0
479
- for f in foods:
480
- if f.class_name == class_name:
481
- _total_price += f.count * f.unit_price
482
- cvsheet.cell(row[0].row, 2, _total_price)
483
-
484
- total_price += _total_price
485
- cvsheet.cell(10, 2, total_price)
486
-
487
- w_seasoning_total_price = sum(
488
- [f.count * f.unit_price for f in wfoods if ("调味" in f.class_name)]
489
- )
490
- unw_seasoning_total_price = sum(
491
- [
492
- f.count * f.unit_price
493
- for f in uwfoods
494
- if ("调味" in f.class_name)
495
- ]
496
- )
497
-
498
- cvsheet.cell(
499
- 8,
500
- 3,
501
- f"入库:{w_seasoning_total_price:.2f}元;"
502
- + f"未入库:{unw_seasoning_total_price:.2f}元",
503
- )
504
-
505
- if self.bill.is_changsheng and self.bill.is_xuelan:
506
- self.update_cover_sheet_for_cangsheng_xuelan(
507
- cvsheet, foods, wfoods, uwfoods, total_price
508
- )
509
-
510
- wb = self.get_bill_workbook()
511
- wb.active = cvsheet
512
-
513
- print_info(_("Sheet '%s' was updated.") % self.cover_sheet_name)
514
-
515
- def get_food_form_index(self, sheet):
516
- indexes = self.get_food_form_indexes(sheet)
517
- _index_range = indexes[self.bill.month - 1]
518
- return _index_range
519
-
520
- def get_food_form_indexes(self, sheet):
521
- indexes = []
522
- for row in sheet.iter_rows(
523
- min_row=1, max_row=sheet.max_row, min_col=1, max_col=14
524
- ):
525
- if row[0].value and "材料名称" in str(row[0].value).replace(
526
- " ", ""
527
- ):
528
- indexes.append([row[0].row + 3, None])
529
-
530
- if row[2].value and "合计" in str(row[2].value).replace(" ", ""):
531
- indexes[-1][1] = row[0].row + 1
532
- return indexes
533
-
534
- def get_residual_foods_by_month_m1(self):
535
- time_nodes = self.bill.get_time_nodes()
536
- t0, t1 = time_nodes[-1]
537
- t1_mm1 = datetime(t1.year, t1.month, 1) + timedelta(days=-1)
538
- time_nodes_mm1 = [
539
- t
540
- for t in time_nodes
541
- if self.bill.times_are_same_year_month(t[0], t1_mm1)
542
- ]
543
-
544
- foods = self.food.get_food_list_from_check_sheet()
545
-
546
- if len(time_nodes_mm1) < 1:
547
- t1_mm1 = t0 + timedelta(days=-1)
548
- else:
549
- time_nodes_mm1 = sorted(time_nodes_mm1, key=lambda t: t[1])
550
- t1_mm1 = time_nodes_mm1[-1][1]
551
-
552
- foods = [f for f in foods if (f.is_residue and f.xdate == t1_mm1)]
553
- return foods
554
-
555
- def get_food_sheet(self, name):
556
- sheet = None
557
- _, t1 = self.bill.get_time_nodes()[-1]
558
- if self.includes_sheet(name):
559
- sheet = self.get_bill_sheet(name)
560
- else:
561
- wb = self.get_bill_workbook()
562
- sheet = wb.copy_worksheet(self.get_food_sheet0())
563
- sheet.title = name
564
- for row in sheet.iter_rows(
565
- min_row=1, max_row=sheet.max_row, min_col=1, max_col=14
566
- ):
567
- if row[0].value and "材料名称" in str(row[0].value).replace(
568
- " ", ""
569
- ):
570
- row[0].value = (
571
- f"材料名称:{name}" + f"({self.food.unit_name})"
572
- )
573
- sheet.cell(row[0].row + 1, 1, f"{t1.year}年")
574
- return sheet
575
-
576
- def format_food_sheet(self, sheet):
577
- if isinstance(sheet, str):
578
- sheet = self.get_food_sheet(sheet)
579
- self.unmerge_cells_of_sheet(sheet)
580
- for row in sheet.iter_rows(
581
- min_row=1,
582
- max_row=sheet.max_row,
583
- min_col=1,
584
- max_col=14,
585
- ):
586
- sheet.row_dimensions[row[0].row].height = 15.75
587
- if row[0].value and "入库、出库台账" in str(row[0].value):
588
- sheet.row_dimensions[row[0].row].height = 27
589
- sheet.merge_cells(
590
- start_row=row[0].row,
591
- end_row=row[0].row,
592
- start_column=1,
593
- end_column=13,
594
- )
595
-
596
- if row[0].value and "年" in str(row[0].value):
597
- sheet.merge_cells(
598
- start_row=row[0].row,
599
- end_row=row[0].row,
600
- start_column=1,
601
- end_column=2,
602
- )
603
-
604
- if row[3].value and "入库" in str(row[3].value).replace(
605
- " ", ""
606
- ).replace(" ", ""):
607
- sheet.merge_cells(
608
- start_row=row[0].row,
609
- end_row=row[0].row,
610
- start_column=4,
611
- end_column=6,
612
- )
613
-
614
- if row[6].value and "出库" in str(row[6].value).replace(
615
- " ", ""
616
- ).replace(" ", ""):
617
- sheet.merge_cells(
618
- start_row=row[0].row,
619
- end_row=row[0].row,
620
- start_column=7,
621
- end_column=9,
622
- )
623
-
624
- if row[9].value and "库存" in str(row[9].value).replace(
625
- " ", ""
626
- ).replace(" ", ""):
627
- sheet.merge_cells(
628
- start_row=row[0].row,
629
- end_row=row[0].row,
630
- start_column=10,
631
- end_column=12,
632
- )
633
-
634
- if row[12].value and "编号" in str(row[12].value).replace(" ", ""):
635
- sheet.merge_cells(
636
- start_row=row[0].row,
637
- end_row=row[0].row + 1,
638
- start_column=13,
639
- end_column=13,
640
- )
641
-
642
- def update_food_sheets(self):
643
- time_nodes = sorted(
644
- [
645
- tn
646
- for tn in self.bill.get_time_nodes()
647
- if tn[1].month == self.bill.month
648
- ]
649
- )
650
- time_nodes_mm1 = sorted(
651
- [
652
- tn
653
- for tn in self.bill.get_time_nodes()
654
- if tn[1].month == self.bill.month - 1
655
- ]
656
- )
657
- t0, t1 = time_nodes[-1]
658
- cfoods = [
659
- f
660
- for f in self.food.get_foods()
661
- if (
662
- (
663
- f.xdate.month == self.bill.month
664
- or (
665
- self.bill.month
666
- in [d.month for d, c in f.consuming_list]
667
- )
668
- )
669
- and not f.is_negligible
670
- )
671
- ]
672
- food_names = list(set([f.name for f in cfoods]))
673
- wb = self.get_bill_workbook()
674
- tn0_dm1 = (
675
- (time_nodes[0][0] + timedelta(days=-1))
676
- if len(time_nodes_mm1) < 1
677
- else (time_nodes_mm1[-1][1])
678
- )
679
-
680
- rfoods = [
681
- f
682
- for f in self.food.get_foods()
683
- if (
684
- f.get_remainder_by_time(tn0_dm1) > 0
685
- and not f.is_negligible
686
- and f.xdate.month < self.bill.month
687
- )
688
- ]
689
-
690
- food_names = list(set([f.name for f in rfoods] + food_names))
691
-
692
- sheet = None
693
- for food_name in food_names:
694
- sheet = self.get_food_sheet(food_name)
695
- form_index_range = self.get_food_form_index(sheet)
696
- index_start, index_end = form_index_range
697
-
698
- for row_index in range(index_start, index_end - 1):
699
- for col_index in range(1, 14):
700
- sheet.cell(row_index, col_index).value = ""
701
- row_index = index_start
702
- col_index = 1
703
-
704
- _rfoods = [f for f in rfoods if f.name == food_name]
705
- _cfoods = [f for f in cfoods if f.name == food_name]
706
-
707
- self.unmerge_cells_of_sheet(sheet)
708
-
709
- sheet.cell(index_start - 2, 1, f"{t1.year}年")
710
-
711
- if len(_rfoods) > 0:
712
- for _row_index in range(
713
- index_start, index_start + len(_rfoods)
714
- ):
715
- food = _rfoods[_row_index - index_start]
716
- sheet.cell(
717
- _row_index,
718
- 3,
719
- ("上年结转" if t1.month == 1 else "上月结转"),
720
- )
721
- sheet.cell(row_index, 10, food.count)
722
- sheet.cell(row_index, 11, food.unit_price)
723
- sheet.cell(row_index, 12, food.count * food.unit_price)
724
- row_index += 1
725
- else:
726
- sheet.cell(
727
- row_index,
728
- 3,
729
- ("上年结转" if t1.month == 1 else "上月结转"),
730
- )
731
-
732
- row_index += 1
733
-
734
- _cdates = []
735
- for food in _cfoods:
736
- if len(food.consuming_list) > 0:
737
- _cdates += [d for d, c in food.consuming_list]
738
- _cdates.append(food.xdate)
739
- _cdates = [d for d in _cdates if d.month == self.bill.month]
740
- _cdates = sorted(list(set(_cdates)))
741
-
742
- consuming_n = 1
743
- warehousing_n = 1
744
- for cdate in _cdates:
745
- for food in _cfoods:
746
-
747
- if food.xdate == cdate:
748
- sheet.cell(row_index, 1, cdate.month)
749
- sheet.cell(row_index, 2, cdate.day)
750
- sheet.cell(row_index, 4, food.count)
751
- sheet.cell(row_index, 5, food.unit_price)
752
- sheet.cell(row_index, 6, food.count * food.unit_price)
753
- sheet.cell(row_index, 9, "")
754
- sheet.cell(row_index, 10, food.count)
755
- sheet.cell(row_index, 11, food.unit_price)
756
- sheet.cell(row_index, 12, food.count * food.unit_price)
757
- sheet.cell(
758
- row_index,
759
- 13,
760
- f"R{cdate.month:0>2}{warehousing_n:0>2}",
761
- )
762
- warehousing_n += 1
763
-
764
- if "合计" in str(sheet.cell(row_index + 1, 3).value):
765
- sheet.insert_rows(row_index + 1, 1)
766
-
767
- row_index += 1
768
-
769
- if cdate in [d for d, __ in food.consuming_list]:
770
- _count = [
771
- c for d, c in food.consuming_list if d == cdate
772
- ][0]
773
- _remainder = food.count - sum(
774
- [c for d, c in food.consuming_list if d <= cdate]
775
- )
776
- sheet.cell(row_index, 1, cdate.month)
777
- sheet.cell(row_index, 2, cdate.day)
778
- sheet.cell(row_index, 6, "")
779
- sheet.cell(row_index, 7, _count)
780
- sheet.cell(row_index, 8, food.unit_price)
781
- sheet.cell(row_index, 9, _count * food.unit_price)
782
- sheet.cell(row_index, 10, _remainder)
783
- sheet.cell(row_index, 11, food.unit_price)
784
- sheet.cell(row_index, 12, _remainder * food.unit_price)
785
- sheet.cell(
786
- row_index,
787
- 13,
788
- f"C{cdate.month:0>2}{consuming_n:0>2}",
789
- )
790
- consuming_n += 1
791
-
792
- if "合计" in str(sheet.cell(row_index + 1, 3).value):
793
- sheet.insert_rows(row_index + 1, 1)
794
-
795
- row_index += 1
796
-
797
- self.format_food_sheet(sheet)
798
- print_info(_("Sheet '%s' was updated.") % sheet.title)
799
-
800
- wb.active = sheet
801
-
802
- _food_names = list(set([f.name for f in self.food.get_foods()]))
803
- for name in _food_names:
804
- if self.includes_sheet(name):
805
- sheet = self.get_bill_sheet(name)
806
- sheet.sheet_properties.tabColor = "0" * 8
807
-
808
- print_info(_("All food sheets have their tab colors reset."))
809
-
810
- for name in food_names:
811
- sheet = self.get_food_sheet(name)
812
- sheet.sheet_properties.tabColor = secrets.token_hex(4)
813
-
814
- print_info(
815
- _("Food sheets [{0}] have their tab colors recolor.").format(
816
- " ".join(food_names)
817
- )
818
- )
819
- print_info(
820
- _("Food sheets [{0}] have been updated.").format(
821
- " ".join(food_names)
822
- )
823
- )
824
-
825
- def get_food_form_day_index(self, sheet):
826
- indexes = []
827
- for row in sheet.iter_rows(
828
- min_row=1, max_row=sheet.max_row, min_col=1, max_col=14
829
- ):
830
- if (
831
- row[2].value
832
- and "结转" in str(row[2].value).replace(" ", "")
833
- and not sheet.cell(row[0].row + 1, 3).value
834
- ):
835
- indexes.append([row[0].row + 1, None])
836
-
837
- if row[2].value and "合计" in str(row[2].value).replace(" ", ""):
838
- indexes[-1][1] = row[0].row - 1
839
- index_range = indexes[self.bill.month - 1]
840
- return index_range
841
-
842
- def update_cover_sheet_for_cangsheng_xuelan(
843
- self, cvsheet, foods, wfoods, uwfoods, total_price
844
- ):
845
- egg_milk_total_price = sum(
846
- [f.count * f.unit_price for f in foods if "蛋奶" in f.class_name]
847
- )
848
- xl_milk_total_price = sum(
849
- [f.count * f.unit_price for f in foods if "雪兰" in f.name]
850
- )
851
-
852
- cvsheet.cell(
853
- 5,
854
- 3,
855
- f"昌盛:{(egg_milk_total_price - xl_milk_total_price):.2f}元;"
856
- + f"雪兰:{xl_milk_total_price:.2f}元",
857
- )
858
-
859
- cvsheet.cell(
860
- 10,
861
- 3,
862
- f"昌盛:{total_price-xl_milk_total_price:.2f}元;"
863
- + f"雪兰:{xl_milk_total_price:.2f}元",
864
- )
865
-
866
- def get_changsheng_purchase_properties(self, fpath):
867
- if not fpath.split(".")[-1] in self.spreadsheet_ext_names:
868
- return None
869
- chwb_fpath = fpath
870
- ef = pd.ExcelFile(chwb_fpath)
871
- sheet_names = ef.sheet_names
872
- ef.close()
873
- for sheet_name in sheet_names:
874
- if sheet_name in self.purchase_sheet_names:
875
- chwb0 = load_workbook(chwb_fpath, read_only=True)
876
- cssheet0 = chwb0[sheet_name]
877
- cs_dates = []
878
-
879
- header_names = [
880
- str(cssheet0.cell(1, ci).value)
881
- for ci in range(1, cssheet0.max_column + 1)
882
- if cssheet0.cell(1, ci).value
883
- ]
884
-
885
- xdate_col_index = 0
886
- org_name_col_index = 0
887
- for hn in header_names:
888
- if hn in self.xdate_col_names:
889
- xdate_col_index = header_names.index(hn) + 1
890
- elif hn in self.org_col_names:
891
- org_name_col_index = header_names.index(hn) + 1
892
- if xdate_col_index == 0:
893
- print_error(
894
- _("Got no check date column index of {0} .").format(
895
- chwb_fpath + "-->" + sheet_name
896
- )
897
- )
898
- if org_name_col_index == 0:
899
- print_error(
900
- _("Got no organization name column of {0}").format(
901
- chwb_fpath + "-->" + sheet_name
902
- )
903
- )
904
-
905
- org_names = [
906
- str(cssheet0.cell(ri, org_name_col_index).value)
907
- for ri in range(1, cssheet0.max_row)
908
- ]
909
- if not self.bill.profile.org_name in org_names:
910
- chwb0.close()
911
- return None
912
- cs_dates = [
913
- str(cssheet0.cell(ri, xdate_col_index).value)
914
- for ri in range(1, cssheet0.max_row)
915
- ]
916
- cs_dates = sorted(
917
- list(
918
- set(
919
- [
920
- datetime.strptime(d, "%Y-%m-%d")
921
- for d in cs_dates
922
- if re.search(r"\d{4}-\d{2}-\d{2}", d)
923
- ]
924
- )
925
- )
926
- )
927
- chwb0.close()
928
- return (sheet_name, cs_dates)
929
-
930
- return None
931
-
932
- def get_changsheng_sheet_name(self, wb):
933
- sheet_names = []
934
- if isinstance(wb, str):
935
- ef = pd.ExcelFile(wb)
936
- sheet_names = ef.sheet_names
937
- ef.close()
938
- else:
939
- sheet_names = wb.sheetnames
940
- for sn in self.purchase_sheet_names:
941
- if sn in sheet_names:
942
- return sn
943
- return None
944
-
945
- def update_sheets(self):
946
- foods = self.food.get_foods()
947
- self.update_inventory_sheet()
948
- self.update_consuming_sheet()
949
- self.update_warehousing_sheet()
950
- self.update_unwarehousing_sheet()
951
- self.update_consuming_sum_sheet()
952
- self.update_purchase_sum_sheet()
953
- self.update_cover_sheet()
954
- self.update_food_sheets()
955
- self.save_updated_workbooks()
956
- print_info(_("Update completely!"))
957
-
958
- def save_updated_workbooks(self):
959
- spreadsheet0_fpath = self.get_main_spreadsheet_path()
960
- random_spreadsheet_fpath = self.get_random_bill_workbook_copy_fpath()
961
- print_info(
962
- _(
963
- "Do you want to save all updated data "
964
- + 'to "{0}"? or just save it as a '
965
- + 'copy to "{1}". (YyNn)'
966
- ).format(spreadsheet0_fpath, random_spreadsheet_fpath)
967
- )
968
- print_warning(
969
- _(
970
- 'If you save updated data to "{0}", '
971
- + "data of food sheets will be saved "
972
- + "for every month."
973
- ).format(spreadsheet0_fpath)
974
- )
975
- _input = input0()
976
- if len(_input) > 0 and _input in "Yy":
977
- self.save_bill_workbook(wb_fpath=spreadsheet0_fpath)
978
- print_info(
979
- _(
980
- "You can fill in the monthly missing data "
981
- + "to food sheets, they will be saved "
982
- + "for next updating."
983
- )
984
- )
985
- else:
986
- self.copy_bill_workbook(wb_fpath=random_spreadsheet_fpath)
987
- spreadsheet0_fpath = random_spreadsheet_fpath
988
-
989
- open_path(spreadsheet0_fpath)
990
- print_info(_("Updated data was saved."))
991
-
992
- def get_changsheng_properties_by_dir(self, fdpath=None):
993
- fd_path = self.purchase_workbook_fd_path or fdpath
994
- properties = []
995
- if not Path(fd_path).is_dir():
996
- return None
997
-
998
- for _file in os.listdir(fd_path):
999
- if _file.split(".")[-1] in self.spreadsheet_ext_names:
1000
- chwb_fpath = (Path(fd_path) / _file).as_posix()
1001
- sheet_name = None
1002
- ptime = None
1003
- if chwb_fpath in [
1004
- p[0] for p in self.purchase_sheets_properties
1005
- ]:
1006
- pinfo = [
1007
- p
1008
- for p in self.purchase_sheets_properties
1009
- if p[0] == chwb_fpath
1010
- ][0]
1011
- sheet_name, ptimes = pinfo[1:]
1012
- elif chwb_fpath in self.excluded_purchase_sheets:
1013
- continue
1014
- else:
1015
- print_info(_("Spreadsheet %s is being tested.") % _file)
1016
- pinfo = self.get_changsheng_purchase_properties(chwb_fpath)
1017
- if not pinfo:
1018
- self.excluded_purchase_sheets.append(chwb_fpath)
1019
- continue
1020
- sheet_name, ptimes = pinfo
1021
- if not chwb_fpath in [
1022
- p[0] for p in self.purchase_sheets_properties
1023
- ]:
1024
- self.purchase_sheets_properties.append(
1025
- [chwb_fpath, sheet_name, ptimes]
1026
- )
1027
-
1028
- if ptimes:
1029
- print_info(
1030
- _(
1031
- "The food purchasing times of preadsheet {0} is {1} ."
1032
- ).format(
1033
- _file,
1034
- " | ".join(
1035
- [ptime.strftime("%Y.%m.%d") for ptime in ptimes]
1036
- ),
1037
- )
1038
- )
1039
- properties.append([_file, sheet_name, chwb_fpath, ptimes])
1040
-
1041
- return properties if properties else None
1042
-
1043
- def get_pre_consuming_workbook_fpaths(self):
1044
- fpaths = []
1045
- for time_node in self.bill.get_time_nodes():
1046
- t0, t1 = time_node
1047
- fpath = Path(self.get_profile_copy_data_dpath()) / (
1048
- "consuming-"
1049
- + t0.strftime("%Y%m%d")
1050
- + "-"
1051
- + t1.strftime("%Y%m%d")
1052
- + "."
1053
- + self.spreadsheet_ext_names[0]
1054
- )
1055
-
1056
- if not fpath.exists():
1057
- shutil.copy(pre_consuming0_fpath, fpath)
1058
- print(
1059
- _(
1060
- "Workbook '{0}' doesn't exist, "
1061
- + "workbook '{1}' was copied to '{2}' ."
1062
- ).format(fpath, pre_consuming0_fpath, fpath)
1063
- )
1064
- fpaths.append([time_node, fpath])
1065
-
1066
- return fpaths
1067
-
1068
- def get_changsheng_col_indexes(self, sheet):
1069
- workbook_fpath, sheet = sheet
1070
- food_name_index = [_("Food name index"), -1]
1071
- food_count_index = [_("Food count index"), -1]
1072
- food_total_price_index = [_("Food total price index"), -1]
1073
- food_unit_index = [_("Food unit index"), -1]
1074
- food_xdate_index = [_("Food check date index"), -1]
1075
- food_neglect_mark_index = [
1076
- _("Food 'negligible' mark index"),
1077
- -1,
1078
- ]
1079
- food_residue_mark_index = [_("Food 'residue' mark index"), -1]
1080
- food_org_name_index = [_("Food purchaser name index"), -1]
1081
-
1082
- header_names = [
1083
- str(sheet.cell(1, ci).value)
1084
- for ci in range(1, sheet.max_column + 1)
1085
- ]
1086
-
1087
- for _col_index, cell_value in enumerate(header_names):
1088
- if cell_value in ["商品名称"]:
1089
- food_name_index[1] = _col_index
1090
- pass
1091
- elif cell_value in self.unit_name_col_names:
1092
- food_unit_index[1] = _col_index
1093
- pass
1094
- elif cell_value in self.count_col_names:
1095
- food_count_index[1] = _col_index
1096
- pass
1097
- elif cell_value in self.total_price_col_names:
1098
- food_total_price_index[1] = _col_index
1099
- pass
1100
- elif cell_value in self.xdate_col_names:
1101
- food_xdate_index[1] = _col_index
1102
- pass
1103
- elif cell_value in self.negligible_col_names:
1104
- food_neglect_mark_index[1] = _col_index
1105
- pass
1106
- elif cell_value in self.residue_col_names:
1107
- food_residue_mark_index[1] = _col_index
1108
- pass
1109
- elif cell_value in self.org_col_names:
1110
- food_org_name_index[1] = _col_index
1111
- pass
1112
-
1113
- indexes = self.clean_supplier_col_indexes(
1114
- workbook_fpath,
1115
- [
1116
- food_name_index,
1117
- food_count_index,
1118
- food_total_price_index,
1119
- food_unit_index,
1120
- food_xdate_index,
1121
- food_neglect_mark_index,
1122
- food_org_name_index,
1123
- ],
1124
- ) + [food_residue_mark_index[1]]
1125
- return indexes
1126
-
1127
- def read_consumptions_from_pre_consuming_workbooks(self):
1128
- foods = self.bill._foods
1129
- col_index_offset = self.pre_consuming_sheet_col_index_offset
1130
- row_index_offset = self.pre_consuming_sheet_row_index_offset
1131
- for time_node, fpath in self.get_pre_consuming_workbook_fpaths():
1132
- t0, t1 = time_node
1133
- wb = load_workbook(fpath)
1134
- sheet = wb[self.pre_consuming_sheet0_name]
1135
- ckt0, ckt1 = self.bill.get_check_times(time_node)
1136
- _foods = [
1137
- f
1138
- for f in foods
1139
- if (f.xdate <= ckt1 and f.remainder > 0 and not f.is_negligible)
1140
- ]
1141
- if len(_foods) < 1:
1142
- print_warning(
1143
- _(
1144
- "There is not food of time node %s ,skip workbook designing."
1145
- )
1146
- % (t0.strftime("%Y.%m.%d") + t1.strftime("%Y.%m.%d"))
1147
- )
1148
- continue
1149
-
1150
- if not sheet.cell(1, col_index_offset).value:
1151
- for i, t in enumerate(
1152
- [
1153
- t0 + timedelta(days=a)
1154
- for a in range(0, (t1 - t0).days + 1)
1155
- ]
1156
- ):
1157
- sheet.cell(1, col_index_offset + i, t.strftime("%Y.%m.%d"))
1158
- for i, _f in enumerate(_foods):
1159
- row_index = i + row_index_offset
1160
- sheet.cell(
1161
- row_index,
1162
- 1,
1163
- _f.name + (_f.residue_mark if _f.xdate < ckt0 else ""),
1164
- )
1165
- sheet.cell(row_index, 2, _f.remainder)
1166
- sheet.cell(row_index, 4, _f.unit_price)
1167
- wb.save(fpath)
1168
- wb.close()
1169
- print_info(
1170
- _(
1171
- "Workbook '{0}' was updated, please design the "
1172
- + "daily foods consumption and press ANY key "
1173
- + "to continue."
1174
- ).format(fpath)
1175
- )
1176
- open_path(fpath)
1177
- input0()
1178
- wb = load_workbook(fpath)
1179
- sheet = wb[self.pre_consuming_sheet0_name]
1180
- print_info(_("Workbook %s was read.") % fpath)
1181
-
1182
- for i, _f in enumerate(_foods):
1183
- row_index = row_index_offset + i
1184
- for col_index in range(col_index_offset, sheet.max_column + 1):
1185
- cell_value = sheet.cell(row_index, col_index).value
1186
- if cell_value:
1187
- _date = datetime.strptime(
1188
- sheet.cell(1, col_index).value, "%Y.%m.%d"
1189
- )
1190
- _count = float(cell_value)
1191
- _f.consume(_date, _count)
1192
-
1193
- print_info(_("Read consumption from '{0}' .").format(fpath))
1194
-
1195
- def clean_supplier_col_indexes(self, workbook_fpath, indexes):
1196
- global _
1197
- for i, [name, cn_index] in enumerate(indexes):
1198
- if cn_index < 0:
1199
- error_msg = _(
1200
- "Unable to find {0} from {1}, "
1201
- + "You can input it (1 base) directly or "
1202
- + "give feedback to the maintainers "
1203
- + "--> {2} ."
1204
- ).format(name, workbook_fpath, get_new_issue_url())
1205
- print_error(error_msg)
1206
- for __ in range(3):
1207
- cn_index = input0()
1208
- if cn_index.isnumeric():
1209
- cn_index = int(cn_index) - 1
1210
- indexes[i] = [name, cn_index]
1211
- break
1212
- else:
1213
- print("Unexpected value was got.")
1214
- indexes = [i for __, i in indexes]
1215
- return indexes
1216
-
1217
- def clean_quotation_marks(self, value):
1218
- value = value.replace("‘", "").replace("’", "").replace("'", "")
1219
- return value
1220
-
1221
- def read_changsheng_foods(self, dpath=None):
1222
- global Food
1223
- dpath = self.purchase_workbook_fdpath or dpath
1224
- dpath0 = (Path.home() / "Downloads").as_posix()
1225
- if not dpath:
1226
- print_info(
1227
- _(
1228
- "Please enter the 'purchase list file path' of "
1229
- + "spreadsheet Changsheng provided, "
1230
- + "or enter the directory path and then {app_name} will "
1231
- + "read all spreadsheets."
1232
- + " (default: '{dpath0}')"
1233
- ).format(app_name=app_name, dpath0=dpath0)
1234
- )
1235
- dpath = input0()
1236
-
1237
- if dpath.replace(" ", "") == "":
1238
- dpath = dpath0
1239
- if dpath.startswith("~"):
1240
- dpath = Path.home().as_posix() + dpath[1:]
1241
- if not Path(dpath).exists():
1242
- print_error(_("File or directory '%s' doesn't exist.") % (dpath))
1243
- return None
1244
-
1245
- self.purchase_workbook_fdpath = dpath
1246
- print_info(_("Entered directory: %s") % dpath)
1247
-
1248
- for file in os.listdir(dpath):
1249
- if file.split(".")[-1] in self.spreadsheet_ext_names:
1250
- wb_fpath = (Path(dpath) / file).as_posix()
1251
- if wb_fpath in self.excluded_purchase_sheets:
1252
- continue
1253
- wb = load_workbook(wb_fpath, read_only=True)
1254
- sheetnames = [
1255
- n for n in wb.sheetnames if n in self.purchase_sheet_names
1256
- ]
1257
- if len(sheetnames) < 1:
1258
- if not wb_fpath in self.excluded_purchase_sheets:
1259
- self.excluded_purchase_sheets.append(wb_fpath)
1260
- continue
1261
- sheet = wb[sheetnames[0]]
1262
-
1263
- header_row_index = 1
1264
- header_names = [
1265
- str(sheet.cell(header_row_index, ci).value)
1266
- for ci in range(1, sheet.max_column + 1)
1267
- ]
1268
-
1269
- _org_name_col_index = -1
1270
-
1271
- for hn in header_names:
1272
- if hn in self.org_col_names:
1273
- _org_name_col_index = header_names.index(hn)
1274
-
1275
- if _org_name_col_index < 0:
1276
- print_warning(
1277
- _(
1278
- "{app_name} desn't pick the index of organization name"
1279
- + " column, input it (0 base) or '{wb_fpath}' will be ignored."
1280
- ).format(app_name=app_name, wb_fpath=wb_fpath)
1281
- )
1282
- open_path(wb_fpath)
1283
- _org_name_col_index = input0()
1284
- if not _org_name_col_index.isnumeric():
1285
- continue
1286
- _org_name_col_index = int(_org_name_col_index)
1287
-
1288
- _org_names = list(
1289
- set(
1290
- [
1291
- str(sheet.cell(ri, _org_name_col_index + 1).value)
1292
- for ri in range(
1293
- header_row_index + 1, sheet.max_row + 1
1294
- )
1295
- if sheet.cell(ri, _org_name_col_index + 1).value
1296
- ]
1297
- )
1298
- )
1299
-
1300
- if not any(
1301
- [o == self.bill.profile.org_name for o in _org_names]
1302
- ):
1303
- print_warning(
1304
- (
1305
- _('Organization name read from {0} are "{1}",')
1306
- if len(_org_names) > 1
1307
- else _('Organization name read from {0} is "{1}", ')
1308
- ).format(wb_fpath, " | ".join(_org_names))
1309
- + _('but organization name of {0} is "{1}".').format(
1310
- f"{self.profile.label}({self.profile.name})",
1311
- self.profile.org_name,
1312
- )
1313
- )
1314
- print_error(
1315
- _("'{wb_fpath}' was discarded.").format(
1316
- wb_fpath=wb_fpath
1317
- )
1318
- )
1319
- if not wb_fpath in self.excluded_purchase_sheets:
1320
- self.excluded_purchase_sheets.append(wb_fpath)
1321
- continue
1322
-
1323
- if not any(
1324
- [(h in self.negligible_col_names) for h in header_names]
1325
- ):
1326
- print_info(
1327
- _(
1328
- "It seems you didn't set the 'negligible' mark "
1329
- + "for workbook '{0}' , update this workbook "
1330
- + "and press ANY key to continue. (Add the "
1331
- + "'negligible' column name even though there "
1332
- + "is no negligible foods)"
1333
- ).format(wb_fpath)
1334
- )
1335
- print_info(
1336
- _(
1337
- "The column names of 'negligible' mark are following:"
1338
- )
1339
- + "\n\t"
1340
- + " | ".join(self.negligible_col_names)
1341
- )
1342
- open_path(wb_fpath)
1343
- input0()
1344
- wb = load_workbook(wb_fpath, read_only=True)
1345
- sheet = wb[sheetnames[0]]
1346
-
1347
- print_info(_("Spreadsheet '%s' was used."))
1348
-
1349
- (
1350
- food_name_index,
1351
- food_count_index,
1352
- food_total_price_index,
1353
- food_unit_index,
1354
- food_xdate_index,
1355
- food_neglect_mark_index,
1356
- food_org_name_index,
1357
- food_residue_mark_index,
1358
- ) = self.get_changsheng_col_indexes([wb_fpath, sheet])
1359
-
1360
- row_index = 1
1361
- col_index = 1
1362
- for row in sheet.iter_rows(
1363
- min_row=2,
1364
- max_row=sheet.max_row,
1365
- min_col=1,
1366
- max_col=sheet.max_column,
1367
- ):
1368
- if row[food_name_index].value:
1369
- xdate = self.clean_quotation_marks(
1370
- row[food_xdate_index].value
1371
- )
1372
-
1373
- xdate = (
1374
- datetime.strptime(xdate, "%Y-%m-%d")
1375
- if "-" in xdate
1376
- else (
1377
- datetime.strptime(xdate, "%Y/%m/%d")
1378
- if "/" in xdate
1379
- else datetime.strptime(xdate, "%Y%d%m")
1380
- )
1381
- )
1382
- org_name = row[food_org_name_index].value
1383
-
1384
- if org_name != self.bill.profile.org_name:
1385
- if not wb_fpath in self.excluded_purchase_sheets:
1386
- self.excluded_purchase_sheets.append(wb_fpath)
1387
- continue
1388
-
1389
- name = row[food_name_index].value
1390
- count = row[food_count_index].value
1391
- if isinstance(count, str):
1392
- count = float(self.clean_quotation_marks(count))
1393
- unit = row[food_unit_index].value
1394
- total_price = row[food_total_price_index].value
1395
- if isinstance(total_price, str):
1396
- total_price = float(
1397
- self.clean_quotation_marks(total_price)
1398
- )
1399
-
1400
- is_negligible = (
1401
- not row[food_neglect_mark_index].value is None
1402
- if food_neglect_mark_index > 0
1403
- else False
1404
- )
1405
- is_residue = (
1406
- not row[food_residue_mark_index].value is None
1407
- if food_residue_mark_index > 0
1408
- else False
1409
- )
1410
-
1411
- count = self.food.clean_count(name, count, unit)
1412
- unit = self.food.clean_unit_name(name)
1413
-
1414
- _food = Food(
1415
- self.bill,
1416
- name=name,
1417
- xdate=xdate,
1418
- count=count,
1419
- is_residue=is_residue,
1420
- total_price=total_price,
1421
- is_negligible=is_negligible,
1422
- unit_name=unit,
1423
- )
1424
-
1425
- if not _food in self.bill._foods:
1426
- self.bill._foods.append(_food)
1427
-
1428
- return self.bill._foods
1429
-
1430
- def read_changsheng_foods_by_time_node(self, fd_path=None, time_node=None):
1431
- global Food
1432
- fd_path = self.purchase_workbook_fd_path or fd_path
1433
- time_node = time_node or self.bill.time_node
1434
- t0, t1 = time_node
1435
- seeking_dpath0 = (Path.home() / "Downloads").as_posix()
1436
- if not fd_path:
1437
- print_info(
1438
- _(
1439
- "Please enter the 'purchase list file path' of "
1440
- + "spreadsheet Changsheng provided, "
1441
- + "or enter the directory path and then {app_name} will "
1442
- + "read all spreadsheets."
1443
- + " (default: '{seeking_dpath0}')"
1444
- ).format(app_name=app_name, seeking_dpath0=seeking_dpath0)
1445
- )
1446
- fd_path = input0()
1447
-
1448
- if fd_path.replace(" ", "") == "":
1449
- fd_path = seeking_dpath0
1450
- self.purchase_workbook_fd_path = fd_path
1451
- if fd_path.startswith("~"):
1452
- fd_path = Path.home().as_posix() + fd_path[1:]
1453
- if not Path(fd_path).exists():
1454
- print_error(_("File or directory '%s' doesn't exist.") % (fd_path))
1455
- return None
1456
-
1457
- chwb = None
1458
- cssheet = None
1459
- ck_t0, ck_t1 = self.bill.get_check_times_of_time_node()
1460
- if Path(fd_path).is_dir():
1461
- print_info(_("Entered directory: %s") % fd_path)
1462
- csproperties = self.get_changsheng_properties_by_dir(fd_path)
1463
- if not csproperties:
1464
- return None
1465
- for csproperty in csproperties:
1466
- file_name, sheet_name, file_path, purchase_times = csproperty
1467
- for ptime in purchase_times:
1468
- if ck_t0 <= ptime <= ck_t1:
1469
- fd_path = file_path
1470
- cssheet = sheet_name
1471
- break
1472
- if cssheet:
1473
- break
1474
- if not cssheet:
1475
- return None
1476
-
1477
- else:
1478
- cssheet = self.get_changsheng_sheet_name(fd_path)
1479
-
1480
- chwb = load_workbook(fd_path, read_only=True)
1481
- cssheet = chwb[cssheet]
1482
-
1483
- food_name_index = 0
1484
- food_count_index = 0
1485
- food_total_price_index = 0
1486
- food_unit_index = 0
1487
- food_xdate_index = 0
1488
- food_neglect_mark_index = 0
1489
- food_residue_mark_index = 0
1490
- food_org_name_index = 0
1491
-
1492
- for _col_index, cell_value in enumerate(
1493
- [
1494
- str(cssheet.cell(1, ci).value)
1495
- for ci in range(1, cssheet.max_column + 1)
1496
- ]
1497
- ):
1498
- if cell_value in ["商品名称"]:
1499
- food_name_index = _col_index
1500
- elif cell_value in ["单位", "订货单位"]:
1501
- food_unit_index = _col_index
1502
- elif cell_value in ["数量", "记账数量"]:
1503
- food_count_index = _col_index
1504
- elif cell_value in ["金额", "折前金额"]:
1505
- food_total_price_index = _col_index
1506
- elif cell_value in self.xdate_col_names:
1507
- food_xdate_index = _col_index
1508
- elif cell_value in self.negligible_col_names:
1509
- food_neglect_mark_index = _col_index
1510
- elif cell_value in self.residue_col_names:
1511
- food_residue_mark_index = _col_index
1512
- elif cell_value in self.org_col_names:
1513
- food_org_name_index = _col_index
1514
-
1515
- csfoods = []
1516
- is_residue = False
1517
-
1518
- row_index = 1
1519
- col_index = 1
1520
- for row in cssheet.iter_rows(
1521
- min_row=2,
1522
- max_row=cssheet.max_row,
1523
- min_col=1,
1524
- max_col=cssheet.max_column,
1525
- ):
1526
- if row[food_name_index].value:
1527
- xdate = row[food_xdate_index].value
1528
- xdate = (
1529
- datetime.strptime(xdate, "%Y-%m-%d")
1530
- if "-" in xdate
1531
- else datetime.strptime(xdate, "%Y%d%m")
1532
- )
1533
- if not (ck_t0 <= xdate <= ck_t1):
1534
- continue
1535
- org_name = row[food_org_name_index].value
1536
- if org_name != self.bill.profile.org_name:
1537
- continue
1538
-
1539
- name = row[food_name_index].value
1540
- count = row[food_count_index].value
1541
- unit = row[food_unit_index].value
1542
- total_price = row[food_total_price_index].value
1543
- is_negligible = (
1544
- not row[food_neglect_mark_index].value is None
1545
- if food_neglect_mark_index > 0
1546
- else False
1547
- )
1548
- is_residue = (
1549
- not row[food_residue_mark_index].value is None
1550
- if food_residue_mark_index > 0
1551
- else False
1552
- )
1553
-
1554
- csfoods.append(
1555
- Food(
1556
- self.bill,
1557
- name=name,
1558
- xdate=xdate,
1559
- count=count,
1560
- is_residue=is_residue,
1561
- total_price=total_price,
1562
- is_negligible=is_negligible,
1563
- unit_name=unit,
1564
- )
1565
- )
1566
-
1567
- chwb.close()
1568
- if len(csfoods) < 1:
1569
- print_warning(
1570
- _("Got no purchased foods of time node %s .").format(
1571
- t0.strftime("%Y.%m.%d") + "->" + t1.strftime("%Y.%m.%d")
1572
- )
1573
- )
1574
- self.update_foods_consuming(csfoods)
1575
- return csfoods
1576
-
1577
- def update_foods_consuming(self, foods):
1578
- t0, t1 = self.bill.get_time_node()
1579
- foods = [f for f in foods if not f.is_negligible]
1580
-
1581
- if foods is None or len(foods) < 1:
1582
- print_warning(
1583
- _(
1584
- "It seems the residue foods from last "
1585
- + "time node are going to be consumed. "
1586
- + "The new foods of this time node ({0})"
1587
- + "aren't purchased."
1588
- ).format(
1589
- self.bill.time_node[0].strftime("%Y.%m.%d")
1590
- + "->"
1591
- + self.bill.time_node[1].strftime("%Y.%m.%d")
1592
- )
1593
- )
1594
-
1595
- residue_foods = self.food.get_residue_foods_of_time_node()
1596
- if residue_foods:
1597
- foods += residue_foods
1598
- if foods is None:
1599
- return
1600
- wb, sheet = self.get_pre_consuming_sheet_of_time_node(foods)
1601
-
1602
- for i, f in enumerate(foods):
1603
- r = i + self.pre_consuming_sheet_row_index_offset
1604
- for c in range(
1605
- self.pre_consuming_sheet_col_index_offset, sheet.max_column + 1
1606
- ):
1607
- cell_value = sheet.cell(r, c).value
1608
- if cell_value:
1609
- cdate = datetime.strptime(
1610
- sheet.cell(1, c).value, "%Y.%m.%d"
1611
- )
1612
- ccount = float(cell_value)
1613
- f.consume(cdate, ccount)
1614
-
1615
- def get_inventory_form_index_of_time_node(self):
1616
- indexes = self.get_inventory_form_indexes()
1617
- tn_index = (
1618
- self.bill.get_time_node_index() + self.inventory_form_index_offset
1619
- )
1620
- indexes_len = len(indexes)
1621
- _index = None
1622
- if indexes_len <= tn_index:
1623
- return None
1624
- _index = indexes[tn_index]
1625
- return _index
1626
-
1627
- def update_inventory_sheet_of_time_node(self, fd_path=None, time_node=None):
1628
- fd_path = self.purchase_workbook_fd_path or fd_path
1629
- time_node = time_node or self.bill.time_node
1630
- t0, t1 = time_node
1631
- isheet = self.get_inventory_sheet()
1632
- foods = self.food.time_node_residue_foods
1633
- (
1634
- iform_index0,
1635
- iform_index1,
1636
- ) = self.get_inventory_form_index_of_time_node()
1637
-
1638
- if not foods:
1639
- print_warning(_("There is no residue foods."))
1640
- return isheet
1641
-
1642
- for food in foods:
1643
- isheet.cell(iform_index0, 1, name)
1644
- isheet.cell(iform_index0, 2, self.food.unit_name)
1645
- isheet.cell(iform_index0, 3, count)
1646
- isheet.cell(iform_index0, 4, total_price)
1647
- isheet.cell(iform_index0, 5, count)
1648
- isheet.cell(iform_index0, 6, total_price)
1649
- if (
1650
- isheet.cell(iform_index0 + 1, 1).value
1651
- and isheet.cell(iform_index0 + 1, 1).value.replace(" ", "")
1652
- == "合计"
1653
- ):
1654
- isheet.insert_rows(iform_index0 + 1, 1)
1655
- r_total_price += total_price
1656
- iform_index0 += 1
1657
- isheet.cell(isht_form_index1, 4, r_total_price)
1658
- isheet.cell(isht_form_index1, 6, r_total_price)
1659
-
1660
- print_info(_("Sheet '%s' was updated.") % self.inventory_sheet_name)
1661
-
1662
- wb = self.get_bill_workbook()
1663
- wb.active = isheet
1664
- print_info(_("Sheet '%s' was updated.") % self.check_sheet_name)
1665
- return isheet
1666
-
1667
- def update_purchase_sum_sheet(self):
1668
- time_nodes = [
1669
- tn
1670
- for tn in self.bill.get_time_nodes()
1671
- if tn[1].month == self.bill.month
1672
- ]
1673
- t0, t1 = time_nodes[-1]
1674
- pssheet = self.get_purchase_sum_sheet()
1675
-
1676
- pssheet.cell(
1677
- 2,
1678
- 1,
1679
- f"编制单位:{self.bill.profile.org_name}"
1680
- + f" "
1681
- + f"单位:元"
1682
- + f" "
1683
- + f"{t1.year}年{t1.month}月{t1.day}日",
1684
- )
1685
- pssheet.cell(
1686
- 20,
1687
- 1,
1688
- f"编制单位:{self.bill.profile.org_name}"
1689
- + f" "
1690
- + f"单位:元"
1691
- + f" "
1692
- + f"{t1.year}年{t1.month}月{t1.day}日",
1693
- )
1694
- foods = [
1695
- f
1696
- for f in self.food.get_foods()
1697
- if (not f.is_residue and f.xdate.month == self.bill.month)
1698
- ]
1699
- wfoods = [f for f in foods if not f.is_negligible]
1700
- uwfoods = [f for f in foods if f.is_negligible]
1701
- total_price = 0.0
1702
- for row in pssheet.iter_rows(
1703
- min_row=4, max_row=10, min_col=1, max_col=3
1704
- ):
1705
- class_name = row[0].value.replace(" ", "")
1706
- _total_price = 0.0
1707
- for food in wfoods:
1708
- if food.class_name == class_name:
1709
- _total_price += food.count * food.unit_price
1710
- pssheet.cell(row[0].row, 2, _total_price)
1711
- total_price += _total_price
1712
- total_price_cn = self.bill.convert_num_to_cnmoney_chars(total_price)
1713
- pssheet.cell(
1714
- 11, 1, f"总金额(大写):{total_price_cn} ¥{total_price:.2f}"
1715
- )
1716
- pssheet.cell(12, 1, f"经办人:{self.bill.profile.name} ")
1717
-
1718
- total_price = sum([f.count * f.unit_price for f in uwfoods])
1719
- total_price_cn = self.bill.convert_num_to_cnmoney_chars(total_price)
1720
- pssheet.cell(27, 2, total_price)
1721
- pssheet.cell(
1722
- 29, 1, f"总金额(大写):{total_price_cn} ¥{total_price:.2f}"
1723
- )
1724
-
1725
- pssheet.cell(30, 1, f"经办人:{self.bill.profile.name} ")
1726
-
1727
- wb = self.get_bill_workbook()
1728
- wb.active = pssheet
1729
-
1730
- print_info(_("Sheet '%s' was updated.") % self.purchase_sum_sheet_name)
1731
-
1732
- def update_consuming_sum_sheet(self):
1733
- cssheet = self.get_consuming_sum_sheet()
1734
- time_nodes = sorted(
1735
- [
1736
- tn
1737
- for tn in self.bill.get_time_nodes()
1738
- if tn[1].month == self.bill.month
1739
- ]
1740
- )
1741
- t0, t1 = time_nodes[-1]
1742
- foods = [
1743
- f
1744
- for f in self.food.get_foods()
1745
- if (self.bill.month in [d.month for d, c in f.consuming_list])
1746
- ]
1747
-
1748
- total_price = 0.0
1749
- for row in cssheet.iter_rows(
1750
- min_row=4, max_row=10, min_col=1, max_col=3
1751
- ):
1752
- class_name = row[0].value.replace(" ", "")
1753
- _total_price = 0.0
1754
- for food in foods:
1755
- if food.class_name == class_name:
1756
- _total_price += sum(
1757
- [
1758
- _count * food.unit_price
1759
- for _date, _count in food.consuming_list
1760
- if _date.month == self.bill.month
1761
- ]
1762
- )
1763
- total_price += _total_price
1764
- cssheet.cell(row[0].row, 2, _total_price)
1765
- cssheet.cell(row[0].row, 2).number_format = numbers.FORMAT_NUMBER_00
1766
-
1767
- total_price_cn = self.bill.convert_num_to_cnmoney_chars(total_price)
1768
- cssheet.cell(
1769
- 2,
1770
- 1,
1771
- f"编制单位:{self.bill.profile.org_name} "
1772
- + f"单位:元 "
1773
- + f"{t1.year}年{t1.month}月{t1.day}日",
1774
- )
1775
- cssheet.cell(
1776
- 11,
1777
- 1,
1778
- (f"总金额(大写):{total_price_cn} " + f"¥{total_price:.2f}"),
1779
- )
1780
- cssheet.cell(12, 1, f"经办人:{self.bill.profile.name} ")
1781
-
1782
- wb = self.get_bill_workbook()
1783
- wb.active = cssheet
1784
-
1785
- print_info(_("Sheet '%s' was updated.") % self.consuming_sum_sheet_name)
1786
-
1787
- def update_consuming_sheet(self):
1788
- foods = self.food.get_foods()
1789
- csheet = self.get_consuming_sheet()
1790
- form_indexes = self.get_consuming_form_indexes()
1791
-
1792
- time_nodes = self.bill.get_time_nodes()
1793
- days = []
1794
- class_names = self.food.get_class_names()
1795
- for t0, t1 in time_nodes:
1796
- days += [
1797
- t0 + timedelta(days=i) for i in range(0, (t1 - t0).days + 1)
1798
- ]
1799
- print_info(
1800
- _("Consuming days:")
1801
- + " "
1802
- + " ".join([d.strftime("%Y.%m.%d") for d in days])
1803
- )
1804
-
1805
- merged_ranges = list(csheet.merged_cells.ranges)
1806
- for cell_group in merged_ranges:
1807
- csheet.unmerge_cells(str(cell_group))
1808
-
1809
- max_day_index = 0
1810
- for day_index in range(0, len(days)):
1811
- max_day_index = day_index + 1
1812
- day = days[day_index]
1813
- form_index = form_indexes[day_index]
1814
- form_index0, form_index1 = form_index
1815
- food_index0 = form_index0 + 2
1816
- food_index1 = form_index1 - 1
1817
- food_index_len = food_index1 - food_index0 + 1
1818
- tfoods = [
1819
- food
1820
- for food in foods
1821
- if day in [_date for _date, _count in food.consuming_list]
1822
- ]
1823
- tfoods_classes = [f.class_name for f in tfoods]
1824
-
1825
- classes_without_food = [
1826
- _name for _name in class_names if not _name in tfoods_classes
1827
- ]
1828
-
1829
- tfoods_len = len(tfoods)
1830
- consuming_n = day_index + 1
1831
- csheet.cell(form_index0, 2, self.bill.profile.org_name)
1832
- csheet.cell(
1833
- form_index0,
1834
- 4,
1835
- f"{day.year}年 {day.month} 月 {day.day} 日 " + f"单位:元",
1836
- )
1837
-
1838
- csheet.cell(
1839
- form_index0,
1840
- 7,
1841
- f"编号:C{day.month:0>2}{consuming_n:0>2}",
1842
- )
1843
-
1844
- csheet.cell(
1845
- form_index1 + 1,
1846
- 1,
1847
- (
1848
- " "
1849
- + "审核人:"
1850
- + " "
1851
- + "经办人:"
1852
- + "  "
1853
- + "过称人:"
1854
- + self.bill.profile.name
1855
- + " "
1856
- + "仓管人:"
1857
- + "  "
1858
- ),
1859
- )
1860
-
1861
- row_difference = (
1862
- tfoods_len + len(classes_without_food) - food_index_len
1863
- )
1864
-
1865
- if row_difference > 0:
1866
- csheet.insert_rows(food_index0 + 1, row_difference)
1867
- form_indexes = self.get_consuming_form_indexes()
1868
- form_index1 += row_difference
1869
- food_index1 += row_difference
1870
- row_difference = 0
1871
-
1872
- for row in csheet.iter_rows(
1873
- min_row=food_index0,
1874
- max_row=food_index1,
1875
- min_col=1,
1876
- max_col=8,
1877
- ):
1878
- for cell in row:
1879
- cell.value = ""
1880
- cell.alignment = self.cell_alignment0
1881
- cell.border = self.cell_border0
1882
-
1883
- fentry_index = food_index0
1884
-
1885
- for class_name in class_names:
1886
- class_foods = [
1887
- food for food in tfoods if (food.class_name == class_name)
1888
- ]
1889
-
1890
- fentry_index_start = fentry_index
1891
- if len(class_foods) < 1:
1892
- csheet.cell(fentry_index_start, 1, class_name)
1893
- fentry_index = fentry_index_start + 1
1894
- continue
1895
-
1896
- class_consuming_count = 0.0
1897
- for food in class_foods:
1898
- for _date, _count in food.consuming_list:
1899
- if _date == day:
1900
- class_consuming_count += _count * food.unit_price
1901
-
1902
- class_foods_len = len(class_foods)
1903
- if class_name == class_names[0] and row_difference < 0:
1904
- class_foods_len += abs(row_difference) - len(
1905
- classes_without_food
1906
- )
1907
- fentry_index_end = fentry_index_start - 1 + class_foods_len
1908
-
1909
- csheet.cell(fentry_index_start, 1, class_name)
1910
- csheet.cell(fentry_index_start, 7, class_consuming_count)
1911
- csheet.cell(fentry_index_start, 7).number_format = (
1912
- numbers.FORMAT_NUMBER_00
1913
- )
1914
-
1915
- for findex, food in enumerate(class_foods):
1916
- consuming_count = [
1917
- _count
1918
- for _date, _count in food.consuming_list
1919
- if _date == day
1920
- ][0]
1921
- frow_index = fentry_index_start + findex
1922
- csheet.cell(frow_index, 2, food.name)
1923
- csheet.cell(frow_index, 3, food.unit_name)
1924
- csheet.cell(frow_index, 4, consuming_count)
1925
- csheet.cell(frow_index, 5, food.unit_price)
1926
- csheet.cell(
1927
- frow_index, 6, consuming_count * food.unit_price
1928
- )
1929
- csheet.cell(frow_index, 4).number_format = (
1930
- numbers.FORMAT_NUMBER
1931
- )
1932
- csheet.cell(frow_index, 5).number_format = (
1933
- numbers.FORMAT_NUMBER_00
1934
- )
1935
- csheet.cell(frow_index, 6).number_format = (
1936
- numbers.FORMAT_NUMBER_00
1937
- )
1938
-
1939
- fentry_index = fentry_index_end + 1
1940
-
1941
- tfoods_total_price = 0.0
1942
- for food in tfoods:
1943
- for _date, _count in food.consuming_list:
1944
- if _date == day:
1945
- tfoods_total_price += _count * food.unit_price
1946
- csheet.cell(form_index1, 6, tfoods_total_price)
1947
- csheet.cell(form_index1, 7, tfoods_total_price)
1948
-
1949
- if len(form_indexes) > max_day_index:
1950
- for time_index in range(max_day_index, len(form_indexes)):
1951
- form_index0, form_index1 = form_indexes[time_index]
1952
- food_index0, food_index1 = (
1953
- form_index0 + 2,
1954
- form_index1 - 1,
1955
- )
1956
- for row in csheet.iter_rows(
1957
- min_row=food_index0,
1958
- max_row=food_index1,
1959
- min_col=2,
1960
- max_col=7,
1961
- ):
1962
- for cell in row:
1963
- cell.value = ""
1964
-
1965
- self.format_consuming_sheet()
1966
-
1967
- wb = self.get_bill_workbook()
1968
- wb.active = csheet
1969
- print_info(_("Sheet '%s' was updated.") % self.consuming_sheet_name)
1970
-
1971
- def design_pre_consuming_sheet(self, new_foods=None):
1972
- t0, t1 = self.bill.time_node
1973
- wb_fpath = self.get_pre_consuming_workbook_fpath()
1974
- wb = load_workbook(wb_fpath)
1975
- sheet = wb[self.pre_consuming_sheet0_name]
1976
-
1977
- foods = new_foods
1978
- foods = [f for f in foods if not f.is_negligible]
1979
- row_index_offset = self.pre_consuming_sheet_row_index_offset
1980
- col_index_offset = self.pre_consuming_sheet_col_index_offset
1981
- rc_index = 0
1982
- days_difference = (t1 - t0).days
1983
-
1984
- for day in range(0, days_difference + 1):
1985
- time_header = (t0 + timedelta(days=day)).strftime("%Y.%m.%d")
1986
- cell = sheet.cell(1, rc_index + col_index_offset)
1987
- cell.value = time_header
1988
- cell.number_format = numbers.FORMAT_TEXT
1989
- rc_index += 1
1990
-
1991
- rc_index = 0
1992
- for row in sheet.iter_rows(
1993
- max_col=5,
1994
- min_row=row_index_offset,
1995
- max_row=row_index_offset + len(foods),
1996
- ):
1997
- if rc_index > len(foods) - 1:
1998
- break
1999
- food = foods[rc_index]
2000
- row[0].value = food.get_name_with_residue_mark()
2001
- row[1].value = food.count
2002
- row[3].value = food.unit_price
2003
- rc_index += 1
2004
-
2005
- wb.active = sheet
2006
- wb.save(wb_fpath)
2007
- wb.close()
2008
- print_warning(
2009
- _(
2010
- "Sheet '{0}' was updated.\n"
2011
- + "Press any key to continue when you have "
2012
- + "completed the foods allocation."
2013
- ).format(sheet.title)
2014
- )
2015
- print_info(
2016
- _("Ok! I have updated spreadsheet '{0}'. (Press any key)").format(
2017
- wb_fpath
2018
- )
2019
- )
2020
- open_path(wb_fpath)
2021
- input0()
2022
-
2023
- def set_warehousing_form_index_offset(self, offset=0):
2024
- self.warehousing_form_index_offset = offset
2025
-
2026
- def set_inventory_form_index_offset(self, offset=0):
2027
- self.inventory_form_index_offset = offset
2028
-
2029
- @property
2030
- def food_list(self):
2031
- return self.bill.get_food_list()
2032
-
2033
- def get_warehousing_sheet(self):
2034
- return self.get_bill_sheet(self.warehousing_sheet_name)
2035
-
2036
- def get_unwarehousing_sheet(self):
2037
- return self.get_bill_sheet(self.unwarehousing_sheet_name)
2038
-
2039
- def get_consuming_sheet(self):
2040
- return self.get_bill_sheet(self.consuming_sheet_name)
2041
-
2042
- def get_inventory_sheet(self):
2043
- return self.get_bill_sheet(self.inventory_sheet_name)
2044
-
2045
- def get_food_sheet0(self):
2046
- return self.get_bill_sheet(self.food_sheet0_name)
2047
-
2048
- def get_consuming_form_indexes(self):
2049
- csheet = self.get_consuming_sheet()
2050
- indexes = []
2051
- row_index = 1
2052
- for row in csheet.iter_rows(max_row=csheet.max_row + 1, max_col=9):
2053
- if row[0].value:
2054
- if row[0].value.replace(" ", "") == "出库单":
2055
- indexes.append([row_index + 1, 0])
2056
- if row[0].value.replace(" ", "") == "合计":
2057
- indexes[-1][1] = row_index
2058
- row_index += 1
2059
-
2060
- if len(indexes) > 0:
2061
- return indexes
2062
-
2063
- return none
2064
-
2065
- def get_unwarehousing_form_indexes(self):
2066
- unwsheet = self.get_unwarehousing_sheet()
2067
- indexes = []
2068
- row_index = 1
2069
- for row in unwsheet.iter_rows(max_row=unwsheet.max_row + 1, max_col=7):
2070
- if row[0].value and "未入库明细表" in row[0].value.replace(" ", ""):
2071
- indexes.append([row_index + 1, 0])
2072
-
2073
- if row[1].value and "合计" in row[1].value.replace(" ", ""):
2074
- indexes[-1][1] = row_index
2075
-
2076
- row_index += 1
2077
-
2078
- if len(indexes) > 0:
2079
- return indexes
2080
-
2081
- return None
2082
-
2083
- def get_inventory_form_indexes(self):
2084
- isheet = self.get_inventory_sheet()
2085
- indexes = []
2086
- row_index = 1
2087
- for row in isheet.iter_rows(max_row=isheet.max_row + 1, max_col=8):
2088
- if row[0].value:
2089
- if row[0].value.replace(" ", "") == "食材盘存表":
2090
- indexes.append([row_index + 1, 0])
2091
- if row[0].value.replace(" ", "") == "合计":
2092
- indexes[-1][1] = row_index
2093
- row_index += 1
2094
-
2095
- if len(indexes) > 0:
2096
- return indexes
2097
-
2098
- return None
2099
-
2100
- def get_warehousing_form_indexes(self):
2101
- wsheet = self.get_warehousing_sheet()
2102
- indexes = []
2103
- row_index = 1
2104
- for row in wsheet.iter_rows(max_row=wsheet.max_row + 1, max_col=8):
2105
- if row[0].value:
2106
- if row[0].value.replace(" ", "") == "入库单":
2107
- indexes.append([row_index + 1, 0])
2108
- if row[0].value.replace(" ", "") == "合计":
2109
- indexes[-1][1] = row_index
2110
- row_index += 1
2111
-
2112
- if len(indexes) > 0:
2113
- return indexes
2114
-
2115
- return None
2116
-
2117
- def format_consuming_sheet(self):
2118
- csheet = self.get_consuming_sheet()
2119
- merged_ranges = list(csheet.merged_cells.ranges)
2120
- for cell_group in merged_ranges:
2121
- csheet.unmerge_cells(str(cell_group))
2122
-
2123
- for row in csheet.iter_rows(
2124
- min_row=1, max_row=csheet.max_row, min_col=1, max_col=8
2125
- ):
2126
- if row[0].value and row[0].value.replace(" ", "") == "出库单":
2127
- csheet.row_dimensions[row[0].row].height = 21
2128
- csheet.merge_cells(
2129
- start_row=row[0].row,
2130
- end_row=row[0].row,
2131
- start_column=1,
2132
- end_column=8,
2133
- )
2134
- csheet.merge_cells(
2135
- start_row=row[0].row + 1,
2136
- end_row=row[0].row + 1,
2137
- start_column=4,
2138
- end_column=6,
2139
- )
2140
- csheet.merge_cells(
2141
- start_row=row[0].row + 1,
2142
- end_row=row[0].row + 1,
2143
- start_column=7,
2144
- end_column=8,
2145
- )
2146
-
2147
- if row[0].value and row[0].value.replace(" ", "").endswith("类"):
2148
- row[6].number_format = numbers.FORMAT_NUMBER_00
2149
- for _row in csheet.iter_rows(
2150
- min_row=row[0].row + 1,
2151
- max_row=csheet.max_row + 1,
2152
- min_col=1,
2153
- max_col=1,
2154
- ):
2155
- if _row[0].value and (
2156
- _row[0].value.replace(" ", "").endswith("类")
2157
- or _row[0].value.replace(" ", "") == "合计"
2158
- ):
2159
- csheet.merge_cells(
2160
- start_row=row[0].row,
2161
- end_row=_row[0].row - 1,
2162
- start_column=1,
2163
- end_column=1,
2164
- )
2165
- csheet.merge_cells(
2166
- start_row=row[0].row,
2167
- end_row=_row[0].row - 1,
2168
- start_column=7,
2169
- end_column=7,
2170
- )
2171
- break
2172
-
2173
- if row[0].value and "审核人" in row[0].value.replace(" ", ""):
2174
- csheet.merge_cells(
2175
- start_row=row[0].row,
2176
- end_row=row[0].row,
2177
- start_column=1,
2178
- end_column=8,
2179
- )
2180
-
2181
- wb = self.get_bill_workbook()
2182
- wb.active = csheet
2183
-
2184
- print_info(_("Sheet '%s' was formatted.") % self.consuming_sheet_name)
2185
-
2186
- def format_warehousing_sheet(self):
2187
- wsheet = self.get_warehousing_sheet()
2188
- merged_ranges = list(wsheet.merged_cells.ranges)
2189
- for cell_group in merged_ranges:
2190
- wsheet.unmerge_cells(str(cell_group))
2191
-
2192
- for row in wsheet.iter_rows(
2193
- min_row=1, max_row=wsheet.max_row, min_col=1, max_col=8
2194
- ):
2195
- if row[0].value and row[0].value.replace(" ", "") == "入库单":
2196
- wsheet.row_dimensions[row[0].row].height = 21
2197
- wsheet.merge_cells(
2198
- start_row=row[0].row,
2199
- end_row=row[0].row,
2200
- start_column=1,
2201
- end_column=8,
2202
- )
2203
- wsheet.merge_cells(
2204
- start_row=row[0].row + 1,
2205
- end_row=row[0].row + 1,
2206
- start_column=4,
2207
- end_column=6,
2208
- )
2209
- wsheet.merge_cells(
2210
- start_row=row[0].row + 1,
2211
- end_row=row[0].row + 1,
2212
- start_column=7,
2213
- end_column=8,
2214
- )
2215
-
2216
- if row[0].value and row[0].value.replace(" ", "").endswith("类"):
2217
- row[6].number_format = numbers.FORMAT_NUMBER_00
2218
- for _row in wsheet.iter_rows(
2219
- min_row=row[0].row + 1,
2220
- max_row=wsheet.max_row + 1,
2221
- min_col=1,
2222
- max_col=1,
2223
- ):
2224
- if _row[0].value and (
2225
- _row[0].value.replace(" ", "").endswith("类")
2226
- or _row[0].value.replace(" ", "") == "合计"
2227
- ):
2228
- wsheet.merge_cells(
2229
- start_row=row[0].row,
2230
- end_row=_row[0].row - 1,
2231
- start_column=1,
2232
- end_column=1,
2233
- )
2234
- wsheet.merge_cells(
2235
- start_row=row[0].row,
2236
- end_row=_row[0].row - 1,
2237
- start_column=7,
2238
- end_column=7,
2239
- )
2240
- break
2241
-
2242
- if row[0].value and "审核人" in row[0].value.replace(" ", ""):
2243
- wsheet.merge_cells(
2244
- start_row=row[0].row,
2245
- end_row=row[0].row,
2246
- start_column=1,
2247
- end_column=8,
2248
- )
2249
-
2250
- wb = self.get_bill_workbook()
2251
- wb.active = wsheet
2252
-
2253
- print_info(_("Sheet '%s' was formatted.") % self.warehousing_sheet_name)
2254
-
2255
- def update_unwarehousing_sheet(self):
2256
- unwsheet = self.get_unwarehousing_sheet()
2257
- form_indexes = self.get_unwarehousing_form_indexes()
2258
- time_nodes = [
2259
- tn
2260
- for tn in self.bill.get_time_nodes()
2261
- if tn[1].month == self.bill.month
2262
- ]
2263
-
2264
- t0, t1 = time_nodes[-1]
2265
- foods = [
2266
- f
2267
- for f in self.food.get_foods()
2268
- if (f.is_negligible and f.xdate.month == self.bill.month)
2269
- ]
2270
- foods = sorted(foods, key=lambda f: f.xdate)
2271
- row_indexes = []
2272
- for form_index in form_indexes:
2273
- form_index0, form_index1 = form_index
2274
- unwsheet.cell(
2275
- form_index0, 1, f" 学校名称:{self.bill.profile.org_name}"
2276
- )
2277
- unwsheet.cell(
2278
- form_index0,
2279
- 4,
2280
- f" "
2281
- + f"{t1.year} 年 {t1.month} 月 "
2282
- + f"{t1.day} 日"
2283
- + f" ",
2284
- )
2285
- row_index_start = form_index0 + 2
2286
- row_index_end = form_index1 - 1
2287
- row_indexes += list(range(row_index_start, row_index_end + 1))
2288
-
2289
- for row_index in row_indexes:
2290
- for col_index in range(1, 7 + 1):
2291
- unwsheet.cell(row_index, col_index, "")
2292
-
2293
- total_price = 0.0
2294
- use_forms = False
2295
-
2296
- for _index, row_index in enumerate(row_indexes):
2297
- food = foods[_index]
2298
- total_price += food.total_price
2299
- unwsheet.cell(row_index, 1, food.xdate.strftime("%Y.%m.%d"))
2300
- unwsheet.cell(row_index, 2, food.name)
2301
- unwsheet.cell(row_index, 3, food.unit_name)
2302
- unwsheet.cell(row_index, 4, food.count)
2303
- unwsheet.cell(row_index, 5, food.unit_price)
2304
- unwsheet.cell(row_index, 6, food.total_price)
2305
- unwsheet.cell(row_index, 5).number_format = numbers.FORMAT_NUMBER_00
2306
- unwsheet.cell(row_index, 6).number_format = numbers.FORMAT_NUMBER_00
2307
- if (
2308
- str(unwsheet.cell(row_index + 1, 2).value)
2309
- .replace(" ", "")
2310
- .endswith("合计")
2311
- and len(foods) - 1 > _index
2312
- ):
2313
- unwsheet.cell(row_index + 1, 2, "合计")
2314
- unwsheet.cell(row_index + 1, 6, total_price)
2315
- use_forms = True
2316
-
2317
- if len(foods) - 1 == _index:
2318
- for row in unwsheet.iter_rows(
2319
- min_row=row_index,
2320
- max_row=unwsheet.max_row,
2321
- min_col=1,
2322
- max_col=7,
2323
- ):
2324
- if row[2].value and str(row[2].value).replace(
2325
- " ", ""
2326
- ).endswith("合计"):
2327
- row[2].value = "总合计" if use_forms else "合计"
2328
- row[6].value = total_price
2329
- break
2330
- break
2331
-
2332
- print_info(_("Sheet '%s' was updated.") % self.unwarehousing_sheet_name)
2333
-
2334
- def update_warehousing_sheet(self):
2335
- wsheet = self.get_warehousing_sheet()
2336
- foods = [
2337
- f
2338
- for f in self.food.get_foods()
2339
- if (
2340
- not f.is_residue
2341
- and not f.is_negligible
2342
- and f.xdate.month == self.bill.month
2343
- )
2344
- ]
2345
- form_indexes = self.get_warehousing_form_indexes()
2346
- class_names = self.food.get_class_names()
2347
- time_nodes = self.bill.get_time_nodes()
2348
-
2349
- self.unmerge_cells_of_sheet(wsheet)
2350
-
2351
- for form_index0, form_index1 in form_indexes:
2352
- food_index0 = form_index0 + 2
2353
- food_index1 = form_index1 - 1
2354
- for row in wsheet.iter_rows(
2355
- min_row=food_index0,
2356
- max_row=food_index1,
2357
- min_col=1,
2358
- max_col=8,
2359
- ):
2360
- for cell in row:
2361
- cell.value = ""
2362
-
2363
- w_times = sorted(
2364
- list(
2365
- set(
2366
- [
2367
- food.xdate
2368
- for food in foods
2369
- if food.xdate.month == self.bill.month
2370
- ]
2371
- )
2372
- )
2373
- )
2374
-
2375
- max_time_index = 0
2376
- for windex, w_time in enumerate(w_times):
2377
- time_point = w_time
2378
- max_time_index = windex + 1
2379
- form_index0, form_index1 = form_indexes[windex]
2380
- food_index0 = form_index0 + 2
2381
- food_index1 = form_index1 - 1
2382
- entry_index = food_index0
2383
- warehousing_n = windex + 1
2384
-
2385
- wfoods = [f for f in foods if (f.xdate == time_point)]
2386
- foods_class_names = [f.class_name for f in wfoods]
2387
- class_names_without_food = [
2388
- _name for _name in class_names if not _name in foods_class_names
2389
- ]
2390
- row_difference = (
2391
- len(wfoods)
2392
- + len(class_names_without_food)
2393
- - (food_index1 - food_index0 + 1)
2394
- )
2395
-
2396
- if row_difference > 0:
2397
- wsheet.insert_rows(food_index0 + 1, row_difference)
2398
- for row in wsheet.iter_rows(
2399
- min_row=food_index0 + 1,
2400
- max_row=food_index0 + 1 + row_difference,
2401
- min_col=1,
2402
- max_col=8,
2403
- ):
2404
- for cell in row:
2405
- cell.alignment = self.cell_alignment0
2406
- self.border = self.cell_border0
2407
-
2408
- form_indexes = self.get_warehousing_form_indexes()
2409
- form_index1 += row_difference
2410
- food_index1 = form_index1 - 1
2411
- row_difference = 0
2412
-
2413
- for row in wsheet.iter_rows(
2414
- min_row=food_index0,
2415
- max_row=food_index1,
2416
- min_col=1,
2417
- max_col=8,
2418
- ):
2419
- for cell in row:
2420
- cell.value = ""
2421
- cell.alignment = self.cell_alignment0
2422
- cell.border = self.cell_border0
2423
-
2424
- wsheet.cell(form_index0, 2, self.bill.profile.org_name)
2425
- wsheet.cell(
2426
- form_index0,
2427
- 4,
2428
- f"{time_point.year}年 {time_point.month} 月 "
2429
- + f"{time_point.day} 日 单位:元",
2430
- )
2431
- wsheet.cell(
2432
- form_index0,
2433
- 7,
2434
- f"编号:R{time_point.month:0>2}{warehousing_n:0>2}",
2435
- )
2436
-
2437
- wsheet.cell(
2438
- form_index1 + 1,
2439
- 1,
2440
- (
2441
- " "
2442
- + "审核人:"
2443
- + " "
2444
- + "经办人:"
2445
- + self.bill.profile.name
2446
- + "   "
2447
- + "过称人:"
2448
- + " "
2449
- + "仓管人:"
2450
- + "  "
2451
- ),
2452
- )
2453
-
2454
- for class_name in class_names:
2455
- cfoods = [f for f in wfoods if f.class_name == class_name]
2456
- cfoods_total_price = sum([f.total_price for f in cfoods])
2457
-
2458
- wsheet.cell(entry_index, 1, class_name)
2459
- wsheet.cell(entry_index, 7, cfoods_total_price)
2460
-
2461
- if len(cfoods) < 1:
2462
- entry_index += 1
2463
- continue
2464
-
2465
- for cfindex, cfood in enumerate(cfoods):
2466
- cfood_row_index = entry_index + cfindex
2467
- wsheet.cell(cfood_row_index, 2, cfood.name)
2468
- wsheet.cell(cfood_row_index, 3, cfood.unit_name)
2469
- wsheet.cell(cfood_row_index, 4, cfood.count)
2470
- wsheet.cell(cfood_row_index, 5, cfood.unit_price)
2471
- wsheet.cell(cfood_row_index, 6, cfood.total_price)
2472
- wsheet.cell(cfood_row_index, 5).number_format = (
2473
- numbers.FORMAT_NUMBER_00
2474
- )
2475
- wsheet.cell(cfood_row_index, 6).number_format = (
2476
- numbers.FORMAT_NUMBER_00
2477
- )
2478
-
2479
- entry_index_end = entry_index + len(cfoods) - 1
2480
-
2481
- if class_name == class_names[0] and row_difference < 0:
2482
- entry_index_end = (
2483
- entry_index_end
2484
- + abs(row_difference)
2485
- - len(class_names_without_food)
2486
- )
2487
-
2488
- entry_index = entry_index_end + 1
2489
- foods_total_price = sum([f.total_price for f in wfoods])
2490
- wsheet.cell(form_index1, 6, foods_total_price)
2491
- wsheet.cell(form_index1, 7, foods_total_price)
2492
-
2493
- if len(form_indexes) > max_time_index:
2494
- for time_index in range(max_time_index, len(form_indexes)):
2495
- form_index0, form_index1 = form_indexes[time_index]
2496
- food_index0, food_index1 = (
2497
- form_index0 + 2,
2498
- form_index1 - 1,
2499
- )
2500
-
2501
- for row in wsheet.iter_rows(
2502
- min_row=food_index0,
2503
- max_row=food_index1,
2504
- min_col=2,
2505
- max_col=7,
2506
- ):
2507
- for cell in row:
2508
- cell.value = ""
2509
-
2510
- self.format_warehousing_sheet()
2511
- wb = self.get_bill_workbook()
2512
- wb.active = wsheet
2513
-
2514
- print_info(_("Sheet '%s' was updated.") % (self.warehousing_sheet_name))
2515
-
2516
- def get_unit_df(self):
2517
- if not self._unit_df is None:
2518
- return self._unit_df
2519
- self._unit_df = pd.read_excel(
2520
- self.get_main_spreadsheet_path(),
2521
- sheet_name=self.unit_sheet_name,
2522
- names=["Name", "Unit"],
2523
- )
2524
- return self._unit_df
2525
-
2526
- def get_check_df_from_spreadsheet(self):
2527
- check_df = pd.DataFrame(self.get_check_sheet().values)
2528
- check_df.columns = check_df.iloc[0]
2529
- check_df = check_df[1:]
2530
- check_df = check_df.dropna(axis=0, how="all")
2531
- if check_df.shape[0] == 0:
2532
- return None
2533
-
2534
- return check_df
2535
-
2536
- def get_check_df(self):
2537
- if not self._check_df is None:
2538
- return self._check_df
2539
- self._check_df = self.get_check_df_from_spreadsheet()
2540
- return self._check_df
2541
-
2542
- def clear_check_df(self):
2543
- self._check_df = None
2544
-
2545
- def get_unit_sheet(self):
2546
- return self.get_bill_sheet(self.unit_sheet_name)
2547
-
2548
- def get_entry_row_index_of_unit_sheet(self):
2549
- unit_sheet = self.get_unit_sheet()
2550
- row_index = 1
2551
- for row in unit_sheet.iter_rows(
2552
- min_row=1, max_row=unit_sheet.max_row + 1, max_col=1
2553
- ):
2554
- cell = row[0]
2555
- if cell.value == None:
2556
- return row_index
2557
- row_index += 1
2558
-
2559
- return None
2560
-
2561
- def add_food_names_to_unit_sheet(self, names):
2562
- unit_sheet = self.get_unit_sheet()
2563
- entry_row_index = self.get_entry_row_index_of_unit_sheet()
2564
- for index, name in enumerate(names):
2565
- unit_sheet.cell(entry_row_index + index, 1, name)
2566
-
2567
- def get_main_spreadsheet_path(self):
2568
- return (
2569
- self._main_spreadsheet_path
2570
- or self.get_main_spreadsheet_path_of_profile()
2571
- )
2572
-
2573
- def get_main_spreadsheet_path_of_profile(self):
2574
- s_fpath = bill0_fpath
2575
- ps_fpath = user_data_dir / self.profile.label / "workbook.xlsx"
2576
- if not ps_fpath.parent.exists():
2577
- os.makedirs(ps_fpath.parent)
2578
- print_info(_("Directory '%s' has been made.") % (ps_fpath.parent))
2579
-
2580
- if not ps_fpath.exists():
2581
- shutil.copy(s_fpath, ps_fpath)
2582
- print_info(
2583
- _("Workbook '{0}' was copied to '{1}'.").format(
2584
- s_fpath, ps_fpath
2585
- )
2586
- )
2587
- print_info(_("Workbook '%s' has been used.") % ps_fpath)
2588
- return ps_fpath
2589
-
2590
- def get_main_spreadsheet0_path(self):
2591
- _path = bill0_fpath
2592
- return _path
2593
-
2594
- def set_main_spreadsheet_path(self, file_path=None):
2595
- if not Path(file_path).exists():
2596
- shutil.copy(self.get_main_spreadsheet0_path(), file_path)
2597
- self._main_spreadsheet_path = file_path
2598
-
2599
- def get_bill_workbook(self):
2600
- if self.bill_workbook:
2601
- return self.bill_workbook
2602
- self.bill_workbook = load_workbook(self.get_main_spreadsheet_path())
2603
- return self.bill_workbook
2604
-
2605
- def clear_workbook(self):
2606
- self.bill_workbook = None
2607
-
2608
- def save_bill_workbook(self, wb_fpath=None, info=None):
2609
- info = info or _("Saving workbook. . .")
2610
- print_info(info)
2611
- wb_fpath = wb_fpath or self.get_main_spreadsheet_path()
2612
- wb = self.get_bill_workbook()
2613
- wb.save(wb_fpath)
2614
- print_info(
2615
- _("Workbook '%s' was saved.") % self.get_main_spreadsheet_path()
2616
- )
2617
-
2618
- def print_dir_was_created_info(self, dir_path):
2619
- print_info(_("Directory %s was created.") % (dir_path))
2620
-
2621
- def get_profile_data_dpath(self):
2622
- dpath = user_data_dir / self.bill.profile.label
2623
- if not dpath.exists():
2624
- os.makedirs(dpath)
2625
- self.print_dir_was_created_info(dpath)
2626
- return dpath
2627
-
2628
- def get_profile_copy_data_dpath(self):
2629
- dpath = self.get_profile_data_dpath()
2630
- dpath = dpath / "copy"
2631
- if not dpath.exists():
2632
- os.makedirs(dpath)
2633
- self.print_dir_was_created_info(dpath)
2634
- return dpath
2635
-
2636
- def get_random_bill_workbook_copy_fpath(self):
2637
- file_path = self.get_main_spreadsheet_path()
2638
- file_path = file_path.as_posix()
2639
- file_path = file_path.split(os.sep)[-1]
2640
- file_path = file_path[:-5] + f".{uuid.uuid4()}.xlsx"
2641
- file_path = self.get_profile_copy_data_dpath() / file_path
2642
-
2643
- return file_path
2644
-
2645
- def copy_bill_workbook(self, wb_fpath=None):
2646
- print_info(_("Copying workbook..."))
2647
- file_path = wb_fpath or self.get_random_bill_workbook_copy_fpath()
2648
- wb = self.get_bill_workbook()
2649
- wb.save(file_path)
2650
- print_info(_("Workbook '%s' was saved.") % file_path)
2651
- return file_path
2652
-
2653
- def get_bill_sheet(self, name):
2654
- wb = self.get_bill_workbook()
2655
- return wb[name]
2656
-
2657
- def get_check_sheet(self):
2658
- return self.get_bill_sheet(self.check_sheet_name)
2659
-
2660
-
2661
- # The end.