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.
- fnschool/__init__.py +2 -2
- fnschool/canteen/bill.py +11 -2
- fnschool/canteen/currency.py +1 -1
- fnschool/canteen/entry.py +7 -1
- fnschool/canteen/spreadsheet/base.py +23 -2
- fnschool/canteen/spreadsheet/consumingsum.py +13 -7
- fnschool/canteen/spreadsheet/ctspreadsheet.py +1 -1
- fnschool/canteen/spreadsheet/food.py +59 -3
- fnschool/canteen/spreadsheet/merging.py +4 -7
- fnschool/canteen/spreadsheet/preconsuming.py +10 -6
- fnschool/canteen/spreadsheet/purchasing.py +8 -8
- fnschool/canteen/spreadsheet/purchasingsum.py +28 -14
- fnschool/canteen/spreadsheet/spreadsheet.py +1 -1
- fnschool/canteen/spreadsheet/translating.py +12 -0
- fnschool/entry.py +15 -9
- fnschool/exam/email.py +3 -3
- fnschool/exam/entry.py +4 -4
- fnschool/exam/score.py +8 -8
- fnschool/external.py +1 -1
- fnschool/{show.py → inoutput.py} +1 -1
- fnschool/locales/en_US/LC_MESSAGES/fnschool.mo +0 -0
- fnschool/locales/zh_CN/LC_MESSAGES/fnschool.mo +0 -0
- fnschool/locales/zh_HK/LC_MESSAGES/fnschool.mo +0 -0
- fnschool/locales/zh_SG/LC_MESSAGES/fnschool.mo +0 -0
- fnschool/locales/zh_TW/LC_MESSAGES/fnschool.mo +0 -0
- fnschool/path.py +1 -1
- fnschool/user.py +5 -5
- {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/METADATA +2 -2
- {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/RECORD +33 -33
- {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/WHEEL +1 -1
- fnschool/canteen/workbook.py +0 -2661
- {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/LICENSE +0 -0
- {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/entry_points.txt +0 -0
- {fnschool-20241126.81759.821.dist-info → fnschool-20250109.80500.803.dist-info}/top_level.txt +0 -0
fnschool/canteen/workbook.py
DELETED
|
@@ -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.
|