qrpa 1.1.79__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 qrpa might be problematic. Click here for more details.

@@ -0,0 +1,599 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ SHEIN台账月报数据模型
5
+ 使用SQLAlchemy定义台账月报表结构
6
+ """
7
+
8
+ from sqlalchemy import create_engine, Column, String, DateTime, Integer, DECIMAL, Date, Index
9
+ from sqlalchemy.orm import sessionmaker, declarative_base
10
+ from datetime import datetime
11
+ import json
12
+
13
+ # 创建基类
14
+ Base = declarative_base()
15
+
16
+ class SheinLedgerMonthReport(Base):
17
+ """
18
+ SHEIN台账月报表
19
+ 存储供应商维度的月度台账汇总数据
20
+ """
21
+ __tablename__ = 'shein_ledger_month_report'
22
+
23
+ # 主键ID (自增)
24
+ id = Column(Integer, primary_key=True, autoincrement=True, comment='主键ID')
25
+
26
+ # 供应商信息
27
+ supplier_id = Column(Integer, nullable=False, comment='供应商ID')
28
+ supplier_name = Column(String(200), nullable=False, comment='供应商名称')
29
+
30
+ # 报表日期(月份的第一天)
31
+ report_date = Column(Date, nullable=False, comment='报表月份(如2025-05-01)')
32
+
33
+ # === 期初期末库存 ===
34
+ begin_balance_cnt = Column(Integer, nullable=True, default=0, comment='期初库存数量')
35
+ begin_balance_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='期初库存金额')
36
+ end_balance_cnt = Column(Integer, nullable=True, default=0, comment='期末库存数量')
37
+ end_balance_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='期末库存金额')
38
+
39
+ # === 入库数据 ===
40
+ # 紧急订单入库
41
+ urgent_order_entry_cnt = Column(Integer, nullable=True, default=0, comment='紧急订单入库数量')
42
+ urgent_order_entry_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='紧急订单入库金额')
43
+
44
+ # 备货订单入库
45
+ prepare_order_entry_cnt = Column(Integer, nullable=True, default=0, comment='备货订单入库数量')
46
+ prepare_order_entry_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='备货订单入库金额')
47
+
48
+ # 收益入库
49
+ in_gain_cnt = Column(Integer, nullable=True, default=0, comment='收益入库数量')
50
+ in_gain_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='收益入库金额')
51
+
52
+ # 退货入库
53
+ in_return_cnt = Column(Integer, nullable=True, default=0, comment='退货入库数量')
54
+ in_return_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='退货入库金额')
55
+
56
+ # 供应变更入库
57
+ supply_change_in_cnt = Column(Integer, nullable=True, default=0, comment='供应变更入库数量')
58
+ in_supply_change_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='供应变更入库金额')
59
+
60
+ # 调整入库
61
+ adjust_in_cnt = Column(Integer, nullable=True, default=0, comment='调整入库数量')
62
+ adjust_in_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='调整入库金额')
63
+
64
+ # 总入库
65
+ in_cnt = Column(Integer, nullable=True, default=0, comment='总入库数量')
66
+ in_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='总入库金额')
67
+
68
+ # === 出库数据(核心字段) ===
69
+ # 总出库(最重要)
70
+ total_customer_cnt = Column(Integer, nullable=True, default=0, comment='总出库数量')
71
+ total_customer_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='总出库金额')
72
+
73
+ # 客户出库
74
+ customer_cnt = Column(Integer, nullable=True, default=0, comment='客户出库数量')
75
+ customer_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='客户出库金额')
76
+
77
+ # 平台客户出库
78
+ platform_customer_cnt = Column(Integer, nullable=True, default=0, comment='平台客户出库数量')
79
+ platform_customer_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='平台客户出库金额')
80
+
81
+ # 亏损出库
82
+ out_loss_cnt = Column(Integer, nullable=True, default=0, comment='亏损出库数量')
83
+ out_loss_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='亏损出库金额')
84
+
85
+ # 供应商出库
86
+ out_supplier_cnt = Column(Integer, nullable=True, default=0, comment='供应商出库数量')
87
+ out_supplier_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='供应商出库金额')
88
+
89
+ # 库存清理
90
+ inventory_clear_cnt = Column(Integer, nullable=True, default=0, comment='库存清理数量')
91
+ inventory_clear_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='库存清理金额')
92
+
93
+ # 报表清理
94
+ report_clear_cnt = Column(Integer, nullable=True, default=0, comment='报表清理数量')
95
+ report_clear_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='报表清理金额')
96
+
97
+ # 报废
98
+ scrap_cnt = Column(Integer, nullable=True, default=0, comment='报废数量')
99
+ scrap_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='报废金额')
100
+
101
+ # 供应变更出库
102
+ supply_change_out_cnt = Column(Integer, nullable=True, default=0, comment='供应变更出库数量')
103
+ out_supply_change_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='供应变更出库金额')
104
+
105
+ # 调整出库
106
+ adjust_out_cnt = Column(Integer, nullable=True, default=0, comment='调整出库数量')
107
+ adjust_out_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='调整出库金额')
108
+
109
+ # 客户损失
110
+ customer_lose_cnt = Column(Integer, nullable=True, default=0, comment='客户损失数量')
111
+ customer_lose_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='客户损失金额')
112
+
113
+ # 总出库
114
+ out_cnt = Column(Integer, nullable=True, default=0, comment='总出库数量')
115
+ out_amount = Column(DECIMAL(12, 2), nullable=True, default=0, comment='总出库金额')
116
+
117
+ # === 扩展字段(用于后续关联店铺信息) ===
118
+ store_username = Column(String(100), nullable=True, comment='店铺账号(预留)')
119
+ store_name = Column(String(200), nullable=True, comment='店铺名称(预留)')
120
+ store_manager = Column(String(100), nullable=True, comment='店长(预留)')
121
+
122
+ # 时间戳
123
+ created_at = Column(DateTime, default=datetime.now, comment='创建时间')
124
+ updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, comment='更新时间')
125
+
126
+ # 定义索引和唯一约束
127
+ __table_args__ = (
128
+ Index('ix_supplier_id', 'supplier_id'),
129
+ Index('ix_report_date', 'report_date'),
130
+ Index('ix_supplier_report', 'supplier_id', 'report_date', unique=True), # 联合唯一索引
131
+ Index('ix_store_username', 'store_username'),
132
+ )
133
+
134
+ def __repr__(self):
135
+ return f"<SheinLedgerMonthReport(id={self.id}, supplier_id={self.supplier_id}, supplier_name='{self.supplier_name}', report_date='{self.report_date}')>"
136
+
137
+
138
+ class SheinLedgerMonthReportManager:
139
+ """
140
+ SHEIN台账月报数据管理器
141
+ 提供数据库操作相关方法
142
+ """
143
+
144
+ def __init__(self, database_url):
145
+ """
146
+ 初始化数据库连接
147
+
148
+ Args:
149
+ database_url (str): 数据库连接URL,例如:
150
+ mysql+pymysql://username:password@localhost:3306/database_name
151
+ """
152
+ self.engine = create_engine(database_url, echo=False)
153
+ self.Session = sessionmaker(bind=self.engine)
154
+
155
+ def create_tables(self):
156
+ """
157
+ 创建数据表
158
+ """
159
+ Base.metadata.create_all(self.engine)
160
+ print("台账月报数据表创建成功!")
161
+
162
+ def drop_tables(self):
163
+ """
164
+ 删除数据表
165
+ """
166
+ Base.metadata.drop_all(self.engine)
167
+ print("台账月报数据表删除成功!")
168
+
169
+ def _parse_date(self, date_str):
170
+ """
171
+ 解析日期字符串(格式:YYYY-MM-DD)
172
+ """
173
+ if not date_str:
174
+ return None
175
+ try:
176
+ return datetime.strptime(date_str, '%Y-%m-%d').date()
177
+ except:
178
+ return None
179
+
180
+ def _parse_decimal(self, value):
181
+ """
182
+ 解析decimal值,如果为None则返回0
183
+ """
184
+ if value is None:
185
+ return 0
186
+ try:
187
+ return float(value)
188
+ except:
189
+ return 0
190
+
191
+ def _parse_int(self, value):
192
+ """
193
+ 解析整数值,如果为None则返回0
194
+ """
195
+ if value is None:
196
+ return 0
197
+ try:
198
+ return int(value)
199
+ except:
200
+ return 0
201
+
202
+ def upsert_month_report_data(self, data_list):
203
+ """
204
+ 从JSON数据中执行upsert操作(插入或更新)
205
+
206
+ Args:
207
+ data_list (list): 月报数据列表
208
+ """
209
+ session = self.Session()
210
+ try:
211
+ insert_count = 0
212
+ update_count = 0
213
+
214
+ for data in data_list:
215
+ supplier_id = data.get('supplierId')
216
+ report_date = self._parse_date(data.get('reportDate'))
217
+
218
+ if not supplier_id or not report_date:
219
+ print(f"警告:跳过无效数据(supplierId={supplier_id}, reportDate={report_date})")
220
+ continue
221
+
222
+ # 查找是否存在记录
223
+ existing_record = session.query(SheinLedgerMonthReport).filter_by(
224
+ supplier_id=supplier_id,
225
+ report_date=report_date
226
+ ).first()
227
+
228
+ if existing_record:
229
+ # 更新现有记录
230
+ self._update_record_from_data(existing_record, data)
231
+ update_count += 1
232
+ else:
233
+ # 插入新记录
234
+ new_record = self._create_record_from_data(data)
235
+ session.add(new_record)
236
+ insert_count += 1
237
+
238
+ session.commit()
239
+ print(f"成功处理 {len(data_list)} 条月报数据")
240
+ print(f"新增记录: {insert_count} 条,更新记录: {update_count} 条")
241
+
242
+ except Exception as e:
243
+ session.rollback()
244
+ print(f"处理数据失败: {e}")
245
+ raise
246
+ finally:
247
+ session.close()
248
+
249
+ def _create_record_from_data(self, data):
250
+ """
251
+ 从JSON数据创建新的记录对象
252
+ """
253
+ return SheinLedgerMonthReport(
254
+ supplier_id=data.get('supplierId'),
255
+ supplier_name=data.get('supplierName'),
256
+ report_date=self._parse_date(data.get('reportDate')),
257
+
258
+ # 期初期末库存
259
+ begin_balance_cnt=self._parse_int(data.get('beginBalanceCnt')),
260
+ begin_balance_amount=self._parse_decimal(data.get('beginBalanceAmount')),
261
+ end_balance_cnt=self._parse_int(data.get('endBalanceCnt')),
262
+ end_balance_amount=self._parse_decimal(data.get('endBalanceAmount')),
263
+
264
+ # 入库数据
265
+ urgent_order_entry_cnt=self._parse_int(data.get('urgentOrderEntryCnt')),
266
+ urgent_order_entry_amount=self._parse_decimal(data.get('urgentOrderEntryAmount')),
267
+ prepare_order_entry_cnt=self._parse_int(data.get('prepareOrderEntryCnt')),
268
+ prepare_order_entry_amount=self._parse_decimal(data.get('prepareOrderEntryAmount')),
269
+ in_gain_cnt=self._parse_int(data.get('inGainCnt')),
270
+ in_gain_amount=self._parse_decimal(data.get('inGainAmount')),
271
+ in_return_cnt=self._parse_int(data.get('inReturnCnt')),
272
+ in_return_amount=self._parse_decimal(data.get('inReturnAmount')),
273
+ supply_change_in_cnt=self._parse_int(data.get('supplyChangeInCnt')),
274
+ in_supply_change_amount=self._parse_decimal(data.get('inSupplyChangeAmount')),
275
+ adjust_in_cnt=self._parse_int(data.get('adjustInCnt')),
276
+ adjust_in_amount=self._parse_decimal(data.get('adjustInAmount')),
277
+ in_cnt=self._parse_int(data.get('inCnt')),
278
+ in_amount=self._parse_decimal(data.get('inAmount')),
279
+
280
+ # 出库数据
281
+ total_customer_cnt=self._parse_int(data.get('totalCustomerCnt')),
282
+ total_customer_amount=self._parse_decimal(data.get('totalCustomerAmount')),
283
+ customer_cnt=self._parse_int(data.get('customerCnt')),
284
+ customer_amount=self._parse_decimal(data.get('customerAmount')),
285
+ platform_customer_cnt=self._parse_int(data.get('platformCustomerCnt')),
286
+ platform_customer_amount=self._parse_decimal(data.get('platformCustomerAmount')),
287
+ out_loss_cnt=self._parse_int(data.get('outLossCnt')),
288
+ out_loss_amount=self._parse_decimal(data.get('outLossAmount')),
289
+ out_supplier_cnt=self._parse_int(data.get('outSupplierCnt')),
290
+ out_supplier_amount=self._parse_decimal(data.get('outSupplierAmount')),
291
+ inventory_clear_cnt=self._parse_int(data.get('inventoryClearCnt')),
292
+ inventory_clear_amount=self._parse_decimal(data.get('inventoryClearAmount')),
293
+ report_clear_cnt=self._parse_int(data.get('reportClearCnt')),
294
+ report_clear_amount=self._parse_decimal(data.get('reportClearAmount')),
295
+ scrap_cnt=self._parse_int(data.get('scrapCnt')),
296
+ scrap_amount=self._parse_decimal(data.get('scrapAmount')),
297
+ supply_change_out_cnt=self._parse_int(data.get('supplyChangeOutCnt')),
298
+ out_supply_change_amount=self._parse_decimal(data.get('outSupplyChangeAmount')),
299
+ adjust_out_cnt=self._parse_int(data.get('adjustOutCnt')),
300
+ adjust_out_amount=self._parse_decimal(data.get('adjustOutAmount')),
301
+ customer_lose_cnt=self._parse_int(data.get('customerLoseCnt')),
302
+ customer_lose_amount=self._parse_decimal(data.get('customerLoseAmount')),
303
+ out_cnt=self._parse_int(data.get('outCnt')),
304
+ out_amount=self._parse_decimal(data.get('outAmount')),
305
+
306
+ # 扩展字段
307
+ store_username=data.get('store_username'),
308
+ store_name=data.get('store_name'),
309
+ store_manager=data.get('store_manager')
310
+ )
311
+
312
+ def _update_record_from_data(self, record, data):
313
+ """
314
+ 使用JSON数据更新现有记录
315
+ """
316
+ record.supplier_name = data.get('supplierName')
317
+
318
+ # 期初期末库存
319
+ record.begin_balance_cnt = self._parse_int(data.get('beginBalanceCnt'))
320
+ record.begin_balance_amount = self._parse_decimal(data.get('beginBalanceAmount'))
321
+ record.end_balance_cnt = self._parse_int(data.get('endBalanceCnt'))
322
+ record.end_balance_amount = self._parse_decimal(data.get('endBalanceAmount'))
323
+
324
+ # 入库数据
325
+ record.urgent_order_entry_cnt = self._parse_int(data.get('urgentOrderEntryCnt'))
326
+ record.urgent_order_entry_amount = self._parse_decimal(data.get('urgentOrderEntryAmount'))
327
+ record.prepare_order_entry_cnt = self._parse_int(data.get('prepareOrderEntryCnt'))
328
+ record.prepare_order_entry_amount = self._parse_decimal(data.get('prepareOrderEntryAmount'))
329
+ record.in_gain_cnt = self._parse_int(data.get('inGainCnt'))
330
+ record.in_gain_amount = self._parse_decimal(data.get('inGainAmount'))
331
+ record.in_return_cnt = self._parse_int(data.get('inReturnCnt'))
332
+ record.in_return_amount = self._parse_decimal(data.get('inReturnAmount'))
333
+ record.supply_change_in_cnt = self._parse_int(data.get('supplyChangeInCnt'))
334
+ record.in_supply_change_amount = self._parse_decimal(data.get('inSupplyChangeAmount'))
335
+ record.adjust_in_cnt = self._parse_int(data.get('adjustInCnt'))
336
+ record.adjust_in_amount = self._parse_decimal(data.get('adjustInAmount'))
337
+ record.in_cnt = self._parse_int(data.get('inCnt'))
338
+ record.in_amount = self._parse_decimal(data.get('inAmount'))
339
+
340
+ # 出库数据
341
+ record.total_customer_cnt = self._parse_int(data.get('totalCustomerCnt'))
342
+ record.total_customer_amount = self._parse_decimal(data.get('totalCustomerAmount'))
343
+ record.customer_cnt = self._parse_int(data.get('customerCnt'))
344
+ record.customer_amount = self._parse_decimal(data.get('customerAmount'))
345
+ record.platform_customer_cnt = self._parse_int(data.get('platformCustomerCnt'))
346
+ record.platform_customer_amount = self._parse_decimal(data.get('platformCustomerAmount'))
347
+ record.out_loss_cnt = self._parse_int(data.get('outLossCnt'))
348
+ record.out_loss_amount = self._parse_decimal(data.get('outLossAmount'))
349
+ record.out_supplier_cnt = self._parse_int(data.get('outSupplierCnt'))
350
+ record.out_supplier_amount = self._parse_decimal(data.get('outSupplierAmount'))
351
+ record.inventory_clear_cnt = self._parse_int(data.get('inventoryClearCnt'))
352
+ record.inventory_clear_amount = self._parse_decimal(data.get('inventoryClearAmount'))
353
+ record.report_clear_cnt = self._parse_int(data.get('reportClearCnt'))
354
+ record.report_clear_amount = self._parse_decimal(data.get('reportClearAmount'))
355
+ record.scrap_cnt = self._parse_int(data.get('scrapCnt'))
356
+ record.scrap_amount = self._parse_decimal(data.get('scrapAmount'))
357
+ record.supply_change_out_cnt = self._parse_int(data.get('supplyChangeOutCnt'))
358
+ record.out_supply_change_amount = self._parse_decimal(data.get('outSupplyChangeAmount'))
359
+ record.adjust_out_cnt = self._parse_int(data.get('adjustOutCnt'))
360
+ record.adjust_out_amount = self._parse_decimal(data.get('adjustOutAmount'))
361
+ record.customer_lose_cnt = self._parse_int(data.get('customerLoseCnt'))
362
+ record.customer_lose_amount = self._parse_decimal(data.get('customerLoseAmount'))
363
+ record.out_cnt = self._parse_int(data.get('outCnt'))
364
+ record.out_amount = self._parse_decimal(data.get('outAmount'))
365
+
366
+ # 扩展字段
367
+ record.store_username = data.get('store_username')
368
+ record.store_name = data.get('store_name')
369
+ record.store_manager = data.get('store_manager')
370
+
371
+ record.updated_at = datetime.now()
372
+
373
+ def get_month_reports(self, supplier_id=None, report_date=None, year=None, month=None, limit=None, offset=None):
374
+ """
375
+ 查询月报记录列表
376
+
377
+ Args:
378
+ supplier_id (int): 供应商ID
379
+ report_date (str): 报表日期(格式:YYYY-MM-DD)
380
+ year (int): 年份
381
+ month (int): 月份
382
+ limit (int): 限制返回数量
383
+ offset (int): 偏移量
384
+
385
+ Returns:
386
+ list: 月报记录列表
387
+ """
388
+ session = self.Session()
389
+ try:
390
+ query = session.query(SheinLedgerMonthReport)
391
+
392
+ if supplier_id:
393
+ query = query.filter(SheinLedgerMonthReport.supplier_id == supplier_id)
394
+
395
+ if report_date:
396
+ query = query.filter(SheinLedgerMonthReport.report_date == report_date)
397
+
398
+ if year and month:
399
+ # 按年月查询
400
+ date_str = f"{year}-{month:02d}-01"
401
+ query = query.filter(SheinLedgerMonthReport.report_date == date_str)
402
+
403
+ # 默认按报表日期降序排列
404
+ query = query.order_by(SheinLedgerMonthReport.report_date.desc())
405
+
406
+ if offset:
407
+ query = query.offset(offset)
408
+ if limit:
409
+ query = query.limit(limit)
410
+
411
+ return query.all()
412
+ finally:
413
+ session.close()
414
+
415
+ def get_statistics_by_supplier(self, supplier_id, start_date=None, end_date=None):
416
+ """
417
+ 按供应商统计多个月的汇总数据
418
+
419
+ Args:
420
+ supplier_id (int): 供应商ID
421
+ start_date (str): 开始日期(格式:YYYY-MM-DD)
422
+ end_date (str): 结束日期(格式:YYYY-MM-DD)
423
+
424
+ Returns:
425
+ dict: 统计结果
426
+ """
427
+ session = self.Session()
428
+ try:
429
+ query = session.query(SheinLedgerMonthReport).filter(
430
+ SheinLedgerMonthReport.supplier_id == supplier_id
431
+ )
432
+
433
+ if start_date:
434
+ query = query.filter(SheinLedgerMonthReport.report_date >= start_date)
435
+ if end_date:
436
+ query = query.filter(SheinLedgerMonthReport.report_date <= end_date)
437
+
438
+ records = query.all()
439
+
440
+ # 统计信息
441
+ total_in_cnt = sum([r.in_cnt for r in records])
442
+ total_in_amount = sum([r.in_amount for r in records])
443
+ total_out_cnt = sum([r.out_cnt for r in records])
444
+ total_out_amount = sum([r.out_amount for r in records])
445
+ total_customer_cnt = sum([r.total_customer_cnt for r in records])
446
+ total_customer_amount = sum([r.total_customer_amount for r in records])
447
+
448
+ return {
449
+ 'supplier_id' : supplier_id,
450
+ 'month_count' : len(records),
451
+ 'total_in_cnt' : total_in_cnt,
452
+ 'total_in_amount' : float(total_in_amount),
453
+ 'total_out_cnt' : total_out_cnt,
454
+ 'total_out_amount' : float(total_out_amount),
455
+ 'total_customer_cnt' : total_customer_cnt,
456
+ 'total_customer_amount' : float(total_customer_amount)
457
+ }
458
+ finally:
459
+ session.close()
460
+
461
+ def get_statistics_by_month(self, report_date):
462
+ """
463
+ 按月份统计所有供应商的汇总数据
464
+
465
+ Args:
466
+ report_date (str): 报表日期(格式:YYYY-MM-DD)
467
+
468
+ Returns:
469
+ dict: 统计结果
470
+ """
471
+ session = self.Session()
472
+ try:
473
+ records = session.query(SheinLedgerMonthReport).filter(
474
+ SheinLedgerMonthReport.report_date == report_date
475
+ ).all()
476
+
477
+ # 统计信息
478
+ supplier_count = len(records)
479
+ total_in_amount = sum([r.in_amount for r in records])
480
+ total_out_amount = sum([r.out_amount for r in records])
481
+ total_customer_amount = sum([r.total_customer_amount for r in records])
482
+
483
+ return {
484
+ 'report_date' : report_date,
485
+ 'supplier_count' : supplier_count,
486
+ 'total_in_amount' : float(total_in_amount),
487
+ 'total_out_amount' : float(total_out_amount),
488
+ 'total_customer_amount' : float(total_customer_amount)
489
+ }
490
+ finally:
491
+ session.close()
492
+
493
+ def import_from_json_file(self, json_file_path):
494
+ """
495
+ 从JSON文件导入数据
496
+
497
+ Args:
498
+ json_file_path (str): JSON文件路径
499
+ """
500
+ with open(json_file_path, 'r', encoding='utf-8') as f:
501
+ data_list = json.load(f)
502
+ self.upsert_month_report_data(data_list)
503
+
504
+ def get_store_month_summary(self, start_date, end_date):
505
+ """
506
+ 按店铺+月份汇总出库数据(用于Excel导出)
507
+
508
+ Args:
509
+ start_date (str): 开始日期(格式:YYYY-MM-DD)
510
+ end_date (str): 结束日期(格式:YYYY-MM-DD)
511
+
512
+ Returns:
513
+ dict: 按店铺分组的月度数据
514
+ {
515
+ 'store_name': {
516
+ 'store_username': 'xxx',
517
+ 'store_manager': 'xxx',
518
+ 'months': {
519
+ 1: {'cnt': xxx, 'amount': xxx}, # 1月
520
+ 2: {'cnt': xxx, 'amount': xxx}, # 2月
521
+ ...
522
+ 12: {'cnt': xxx, 'amount': xxx} # 12月
523
+ }
524
+ }
525
+ }
526
+ """
527
+ from collections import defaultdict
528
+
529
+ session = self.Session()
530
+ try:
531
+ # 查询日期范围内的数据
532
+ records = session.query(SheinLedgerMonthReport).filter(
533
+ SheinLedgerMonthReport.report_date >= start_date,
534
+ SheinLedgerMonthReport.report_date <= end_date
535
+ ).order_by(
536
+ SheinLedgerMonthReport.store_username,
537
+ SheinLedgerMonthReport.report_date
538
+ ).all()
539
+
540
+ # 按店铺+月份组织数据
541
+ store_data = defaultdict(lambda: {
542
+ 'store_username': '',
543
+ 'store_manager': '',
544
+ 'months': defaultdict(lambda: {'cnt': 0, 'amount': 0})
545
+ })
546
+
547
+ for record in records:
548
+ store_key = record.store_name or record.store_username
549
+ month = int(record.report_date.strftime('%m')) # 1-12
550
+
551
+ # 保存店铺账号和店长信息(取第一条记录的值)
552
+ if not store_data[store_key]['store_username']:
553
+ store_data[store_key]['store_username'] = record.store_username or ''
554
+ store_data[store_key]['store_manager'] = record.store_manager or ''
555
+
556
+ # 累加月度数据
557
+ store_data[store_key]['months'][month]['cnt'] += record.total_customer_cnt or 0
558
+ store_data[store_key]['months'][month]['amount'] += float(record.total_customer_amount or 0)
559
+
560
+ return dict(store_data)
561
+
562
+ finally:
563
+ session.close()
564
+
565
+
566
+ def example_usage():
567
+ """
568
+ 使用示例
569
+ """
570
+ # 数据库连接URL(请根据实际情况修改)
571
+ database_url = "mysql+pymysql://root:123wyk@localhost:3306/lz"
572
+
573
+ # 创建管理器实例
574
+ manager = SheinLedgerMonthReportManager(database_url)
575
+
576
+ # 创建数据表
577
+ manager.create_tables()
578
+
579
+ # 从JSON文件导入数据
580
+ json_file = "ledger_month_GS0365305_2025-01-01_2025-12-31.json"
581
+ manager.import_from_json_file(json_file)
582
+
583
+ # 查询示例
584
+ reports = manager.get_month_reports(limit=10)
585
+ for report in reports:
586
+ print(f"供应商: {report.supplier_name}, 月份: {report.report_date}, 出库金额: {report.total_customer_amount}")
587
+
588
+ # 按供应商统计
589
+ stats = manager.get_statistics_by_supplier(supplier_id=5230023)
590
+ print(f"供应商统计: {stats}")
591
+
592
+ # 按月份统计
593
+ month_stats = manager.get_statistics_by_month("2025-05-01")
594
+ print(f"月份统计: {month_stats}")
595
+
596
+
597
+ if __name__ == "__main__":
598
+ pass
599
+ # example_usage()