qrpa 1.0.34__py3-none-any.whl → 1.1.50__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.
@@ -0,0 +1,569 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ SHEIN退货订单数据模型
5
+ 使用SQLAlchemy定义退货单表和退货明细表结构
6
+ """
7
+
8
+ from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime, JSON, Date, DECIMAL, ForeignKey, Index
9
+ from sqlalchemy.ext.declarative import declarative_base
10
+ from sqlalchemy.orm import sessionmaker, relationship
11
+ from datetime import datetime
12
+ import json
13
+ import os
14
+
15
+ # 创建基类
16
+ Base = declarative_base()
17
+
18
+ class SheinReturnOrder(Base):
19
+ """
20
+ SHEIN退货单表
21
+ 存储退货单的基本信息
22
+ """
23
+ __tablename__ = 'shein_return_order'
24
+
25
+ # 主键ID
26
+ id = Column(Integer, primary_key=True, autoincrement=True, comment='主键ID')
27
+
28
+ # 原始数据中的ID作为return_id
29
+ return_id = Column(Integer, nullable=False, unique=True, comment='原始退货单ID')
30
+
31
+ # 退货单号(也可作为唯一标识)
32
+ return_order_no = Column(String(50), nullable=False, unique=True, comment='退货单号')
33
+
34
+ # 商家信息
35
+ seller_id = Column(Integer, nullable=True, comment='商家ID')
36
+ supplier_id = Column(Integer, nullable=True, comment='供应商ID')
37
+ store_type = Column(Integer, nullable=True, comment='店铺类型')
38
+ store_code = Column(String(50), nullable=True, comment='店铺编码')
39
+ store_username = Column(String(50), nullable=True, comment='店铺账号')
40
+ store_name = Column(String(50), nullable=True, comment='店铺别名')
41
+ store_manager = Column(String(50), nullable=True, comment='店长')
42
+
43
+ # 退货方式和物流信息
44
+ return_way_type = Column(Integer, nullable=True, comment='退货方式类型')
45
+ return_way_type_name = Column(String(50), nullable=True, comment='退货方式名称')
46
+ return_express_company_code = Column(String(50), nullable=True, comment='退货快递公司编码')
47
+ return_express_company_name = Column(String(100), nullable=True, comment='退货快递公司名称')
48
+ express_no_list = Column(Text, nullable=True, comment='快递单号列表')
49
+
50
+ # 地址信息
51
+ return_address = Column(Text, nullable=True, comment='退货地址')
52
+ take_parcel_address = Column(Text, nullable=True, comment='取件地址')
53
+
54
+ # 仓库信息
55
+ warehouse_id = Column(Integer, nullable=True, comment='仓库ID')
56
+ warehouse_name = Column(String(100), nullable=True, comment='仓库名称')
57
+ warehouse_en_name = Column(String(100), nullable=True, comment='仓库英文名称')
58
+ warehouse_in_charge_phone = Column(String(50), nullable=True, comment='仓库负责人电话')
59
+ warehouse_in_charge_person = Column(String(50), nullable=True, comment='仓库负责人')
60
+ warehouse_detail_address = Column(Text, nullable=True, comment='仓库详细地址')
61
+
62
+ # 退货计划和状态
63
+ return_plan_no = Column(String(50), nullable=True, comment='退货计划号')
64
+ return_order_type = Column(Integer, nullable=True, comment='退货单类型')
65
+ return_order_type_name = Column(String(50), nullable=True, comment='退货单类型名称')
66
+ return_order_status = Column(Integer, nullable=True, comment='退货单状态')
67
+ return_order_status_name = Column(String(50), nullable=True, comment='退货单状态名称')
68
+
69
+ # 数量和金额
70
+ wait_return_quantity = Column(Integer, nullable=True, comment='待退货数量')
71
+ return_quantity = Column(Integer, nullable=True, comment='退货数量')
72
+ return_amount = Column(DECIMAL(10, 2), nullable=True, comment='退货金额')
73
+ pricing_currency_id = Column(Integer, nullable=True, comment='定价货币ID')
74
+ currency_code = Column(String(10), nullable=True, comment='货币代码')
75
+
76
+ # 退货原因
77
+ return_reason_type = Column(Integer, nullable=True, comment='退货原因类型')
78
+ return_reason_type_name = Column(String(100), nullable=True, comment='退货原因类型名称')
79
+ return_reason = Column(Text, nullable=True, comment='退货原因')
80
+ reject_pic_url_list = Column(JSON, nullable=True, comment='拒绝图片URL列表')
81
+
82
+ # 商品信息
83
+ skc_name_list = Column(JSON, nullable=True, comment='SKC名称列表')
84
+ supplier_code_list = Column(JSON, nullable=True, comment='供应商编码列表')
85
+ goods_thumb = Column(Text, nullable=True, comment='商品缩略图')
86
+
87
+ # 联系人信息
88
+ seller_contract = Column(String(50), nullable=True, comment='卖家联系人')
89
+ seller_contract_phone = Column(String(50), nullable=True, comment='卖家联系电话')
90
+
91
+ # 订单相关
92
+ seller_order_no = Column(String(50), nullable=True, comment='卖家订单号')
93
+ seller_order_no_list = Column(JSON, nullable=True, comment='卖家订单号列表')
94
+ seller_delivery_no = Column(String(50), nullable=True, comment='卖家发货单号')
95
+
96
+ # 报废和质检
97
+ return_scrap_type = Column(Integer, nullable=True, comment='退货报废类型')
98
+ return_scrap_type_name = Column(String(50), nullable=True, comment='退货报废类型名称')
99
+ return_dimensions = Column(Integer, nullable=True, comment='退货维度')
100
+
101
+ # 其他标识
102
+ stock_mode = Column(Integer, nullable=True, comment='库存模式')
103
+ order_type = Column(Integer, nullable=True, comment='订单类型')
104
+ skc_num = Column(Integer, nullable=True, comment='SKC数量')
105
+ has_package = Column(Integer, nullable=True, comment='是否有包裹')
106
+ has_report_url = Column(Integer, nullable=True, comment='是否有报告')
107
+ is_sign = Column(Integer, nullable=True, comment='是否签收')
108
+ is_increase = Column(Integer, nullable=True, comment='是否增长')
109
+ can_apply_reconsider = Column(Integer, nullable=True, comment='是否可申请复议')
110
+
111
+ # 报告链接
112
+ qc_report_url = Column(Text, nullable=True, comment='质检报告URL')
113
+ report_url = Column(Text, nullable=True, comment='报告URL')
114
+
115
+ # 时间字段
116
+ add_time = Column(DateTime, nullable=True, comment='添加时间')
117
+ sign_time = Column(DateTime, nullable=True, comment='签收时间(物流)')
118
+ complete_time = Column(DateTime, nullable=True, comment='出库完成时间')
119
+
120
+ # 系统时间戳
121
+ created_at = Column(DateTime, default=datetime.now, comment='创建时间')
122
+ updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, comment='更新时间')
123
+
124
+ # 用户备注字段(供后续web界面使用)
125
+ user_notes = Column(Text, nullable=True, comment='用户备注')
126
+
127
+ return_factotry_status = Column(Integer, nullable=True, comment='退回工厂状态,1已退回,2未退回')
128
+ return_factotry_by = Column(String(50), nullable=True, comment='退回工厂操作人')
129
+ financial_settlement_status = Column(Integer, nullable=True, comment='财务结算状态,1已结算,2未结算')
130
+
131
+ # 定义索引
132
+ __table_args__ = (
133
+ Index('ix_return_order_no', 'return_order_no'),
134
+ Index('ix_return_id', 'return_id'),
135
+ Index('ix_seller_order_no', 'seller_order_no'),
136
+ )
137
+
138
+ def __repr__(self):
139
+ return f"<SheinReturnOrder(id={self.id}, return_order_no='{self.return_order_no}', status='{self.return_order_status_name}')>"
140
+
141
+ class SheinReturnOrderDetail(Base):
142
+ """
143
+ SHEIN退货包裹明细表
144
+ 存储退货包裹中具体商品的详细信息
145
+ """
146
+ __tablename__ = 'shein_return_order_detail'
147
+
148
+ # 主键ID
149
+ id = Column(Integer, primary_key=True, autoincrement=True, comment='主键ID')
150
+
151
+ # 关联退货单ID
152
+ return_order_id = Column(Integer, nullable=False, comment='关联退货单ID')
153
+
154
+ # 包裹信息
155
+ express_code = Column(String(50), nullable=True, comment='快递编码')
156
+ delivery_time = Column(DateTime, nullable=True, comment='发货时间')
157
+ self_pick_start_time = Column(DateTime, nullable=True, comment='自提开始时间')
158
+ supplier_category_type_flag = Column(Integer, nullable=True, comment='供应商分类类型标志')
159
+
160
+ # 包裹基本信息
161
+ package_name = Column(String(50), nullable=True, comment='包裹名称')
162
+ return_box_no = Column(String(50), nullable=True, comment='退货箱号')
163
+
164
+ # 商品信息
165
+ img_path = Column(Text, nullable=True, comment='商品图片路径')
166
+ skc = Column(String(50), nullable=True, comment='SKC编码')
167
+ skc_copy_flag = Column(Integer, nullable=True, comment='SKC复制标志')
168
+ supplier_code = Column(String(100), nullable=True, comment='供应商编码')
169
+
170
+ # SKU详细信息
171
+ platform_sku = Column(String(50), nullable=True, comment='平台SKU')
172
+ supplier_sku = Column(String(100), nullable=True, comment='供应商SKU')
173
+ suffix_zh = Column(String(100), nullable=True, comment='中文后缀')
174
+ return_quantity = Column(Integer, nullable=True, comment='退货数量')
175
+
176
+ # 时间戳
177
+ created_at = Column(DateTime, default=datetime.now, comment='创建时间')
178
+ updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, comment='更新时间')
179
+
180
+ # 用户备注字段
181
+ detail_notes = Column(Text, nullable=True, comment='明细备注')
182
+
183
+ erp_supplier_name = Column(String(50), nullable=True, comment='erp默认供货商')
184
+ erp_cost_price = Column(DECIMAL(10, 2), nullable=True, comment='erp成本价')
185
+
186
+ sign_quantity = Column(Integer, nullable=True, comment='仓库签收数量')
187
+ sign_at = Column(DateTime, nullable=True, comment='仓库签收时间,sign_quantity字段变动时更新')
188
+ return_factotry_status = Column(Integer, nullable=True, comment='退回工厂状态,1已退回,2未退回')
189
+ return_factotry_by = Column(String(50), nullable=True, comment='退回工厂操作人')
190
+ financial_settlement_status = Column(Integer, nullable=True, comment='财务结算状态,1已结算,2未结算')
191
+
192
+ # 定义索引
193
+ __table_args__ = (
194
+ Index('ix_supplier_sku', 'supplier_sku'),
195
+ Index('ix_return_order_id', 'return_order_id'),
196
+ )
197
+
198
+ def __repr__(self):
199
+ return f"<SheinReturnOrderDetail(id={self.id}, skc='{self.skc}', return_quantity={self.return_quantity})>"
200
+
201
+ class SheinReturnOrderManager:
202
+ """
203
+ SHEIN退货订单数据管理器
204
+ 提供数据库操作相关方法
205
+ """
206
+
207
+ def __init__(self, database_url):
208
+ """
209
+ 初始化数据库连接
210
+
211
+ Args:
212
+ database_url (str): 数据库连接URL,例如:
213
+ mysql+pymysql://username:password@localhost:3306/database_name
214
+ """
215
+ self.engine = create_engine(database_url, echo=False)
216
+ self.Session = sessionmaker(bind=self.engine)
217
+
218
+ def create_tables(self):
219
+ """
220
+ 创建数据表
221
+ """
222
+ Base.metadata.create_all(self.engine)
223
+ print("数据表创建成功!")
224
+
225
+ def drop_tables(self):
226
+ """
227
+ 删除数据表
228
+ """
229
+ Base.metadata.drop_all(self.engine)
230
+ print("数据表删除成功!")
231
+
232
+ def _parse_datetime(self, datetime_str):
233
+ """
234
+ 解析datetime字符串
235
+ """
236
+ if not datetime_str:
237
+ return None
238
+ try:
239
+ return datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S')
240
+ except:
241
+ return None
242
+
243
+ def upsert_return_order_data(self, store_username, data_list):
244
+ """
245
+ 从JSON文件中读取数据并执行upsert操作(插入或更新)
246
+
247
+ Args:
248
+ json_file_path (str): JSON文件路径
249
+ """
250
+ session = self.Session()
251
+ try:
252
+
253
+ for data in data_list:
254
+ data['store_username'] = store_username
255
+ # 检查是否已存在该退货单
256
+ existing_order = session.query(SheinReturnOrder).filter_by(
257
+ return_id=data.get('id')
258
+ ).first()
259
+
260
+ if existing_order:
261
+ # 更新现有记录(只更新非备注字段,保留用户添加的备注)
262
+ self._update_return_order(session, existing_order, data)
263
+ else:
264
+ # 插入新记录
265
+ self._insert_return_order(session, data)
266
+
267
+ session.commit()
268
+ print(f"成功处理 {len(data_list)} 条退货单数据")
269
+
270
+ except Exception as e:
271
+ session.rollback()
272
+ print(f"处理数据失败: {e}")
273
+ raise
274
+ finally:
275
+ session.close()
276
+
277
+ def _insert_return_order(self, session, data):
278
+ """
279
+ 插入新的退货单记录
280
+ """
281
+ # 创建退货单主记录
282
+ return_order = SheinReturnOrder(
283
+ return_id=data.get('id'),
284
+ return_order_no=data.get('returnOrderNo'),
285
+ seller_id=data.get('sellerId'),
286
+ supplier_id=data.get('supplierId'),
287
+ store_username=data.get('store_username'),
288
+ store_name=data.get('store_name'),
289
+ store_manager=data.get('store_manager'),
290
+ store_type=data.get('storeType'),
291
+ store_code=data.get('storeCode'),
292
+ return_way_type=data.get('returnWayType'),
293
+ return_way_type_name=data.get('returnWayTypeName'),
294
+ return_express_company_code=data.get('returnExpressCompanyCode'),
295
+ return_express_company_name=data.get('returnExpressCompanyName'),
296
+ express_no_list=data.get('expressNoList'),
297
+ return_address=data.get('returnAddress'),
298
+ take_parcel_address=data.get('takeParcelAddress'),
299
+ warehouse_id=data.get('warehouseId'),
300
+ warehouse_name=data.get('warehouseName'),
301
+ warehouse_en_name=data.get('warehouseEnName'),
302
+ warehouse_in_charge_phone=data.get('warehouseInChargePhone'),
303
+ warehouse_in_charge_person=data.get('warehouseInChargePerson'),
304
+ warehouse_detail_address=data.get('warehouseDetailAddress'),
305
+ return_plan_no=data.get('returnPlanNo'),
306
+ return_order_type=data.get('returnOrderType'),
307
+ return_order_type_name=data.get('returnOrderTypeName'),
308
+ return_order_status=data.get('returnOrderStatus'),
309
+ return_order_status_name=data.get('returnOrderStatusName'),
310
+ wait_return_quantity=data.get('waitReturnQuantity'),
311
+ return_quantity=data.get('returnQuantity'),
312
+ return_amount=data.get('returnAmount'),
313
+ pricing_currency_id=data.get('pricingCurrencyId'),
314
+ currency_code=data.get('currencyCode'),
315
+ return_reason_type=data.get('returnReasonType'),
316
+ return_reason_type_name=data.get('returnReasonTypeName'),
317
+ return_reason=data.get('returnReason'),
318
+ reject_pic_url_list=data.get('rejectPicUrlList'),
319
+ skc_name_list=data.get('skcNameList'),
320
+ supplier_code_list=data.get('supplierCodeList'),
321
+ goods_thumb=data.get('goodsThumb'),
322
+ seller_contract=data.get('sellerContract'),
323
+ seller_contract_phone=data.get('sellerContractPhone'),
324
+ seller_order_no=data.get('sellerOrderNo'),
325
+ seller_order_no_list=data.get('sellerOrderNoList'),
326
+ seller_delivery_no=data.get('sellerDeliveryNo'),
327
+ return_scrap_type=data.get('returnScrapType'),
328
+ return_scrap_type_name=data.get('returnScrapTypeName'),
329
+ return_dimensions=data.get('returnDimensions'),
330
+ stock_mode=data.get('stockMode'),
331
+ order_type=data.get('orderType'),
332
+ skc_num=data.get('skcNum'),
333
+ has_package=data.get('hasPackage'),
334
+ has_report_url=data.get('hasReportUrl'),
335
+ is_sign=data.get('isSign'),
336
+ is_increase=data.get('isIncrease'),
337
+ can_apply_reconsider=data.get('canApplyReconsider'),
338
+ qc_report_url=data.get('qc_report_url'),
339
+ report_url=data.get('report_url'),
340
+ add_time=self._parse_datetime(data.get('addTime')),
341
+ sign_time=self._parse_datetime(data.get('signTime')),
342
+ complete_time=self._parse_datetime(data.get('completeTime'))
343
+ )
344
+
345
+ session.add(return_order)
346
+ session.flush() # 获取主键ID
347
+
348
+ # 插入明细记录
349
+ self._insert_return_order_details(session, return_order.id, data.get('return_box_detail', []))
350
+
351
+ def _update_return_order(self, session, existing_order, data):
352
+ """
353
+ 更新现有的退货单记录(保留用户备注,只更新下面这些替换的)
354
+ """
355
+
356
+ # 更新主记录字段(除了用户备注)
357
+ existing_order.return_order_no = data.get('returnOrderNo')
358
+ existing_order.seller_id = data.get('sellerId')
359
+ existing_order.supplier_id = data.get('supplierId')
360
+ existing_order.store_type = data.get('storeType')
361
+ existing_order.store_code = data.get('storeCode')
362
+ existing_order.return_way_type = data.get('returnWayType')
363
+ existing_order.return_way_type_name = data.get('returnWayTypeName')
364
+ existing_order.return_express_company_code = data.get('returnExpressCompanyCode')
365
+ existing_order.return_express_company_name = data.get('returnExpressCompanyName')
366
+ existing_order.express_no_list = data.get('expressNoList')
367
+ existing_order.return_address = data.get('returnAddress')
368
+ existing_order.take_parcel_address = data.get('takeParcelAddress')
369
+ existing_order.warehouse_id = data.get('warehouseId')
370
+ existing_order.warehouse_name = data.get('warehouseName')
371
+ existing_order.warehouse_en_name = data.get('warehouseEnName')
372
+ existing_order.warehouse_in_charge_phone = data.get('warehouseInChargePhone')
373
+ existing_order.warehouse_in_charge_person = data.get('warehouseInChargePerson')
374
+ existing_order.warehouse_detail_address = data.get('warehouseDetailAddress')
375
+ existing_order.return_plan_no = data.get('returnPlanNo')
376
+ existing_order.return_order_type = data.get('returnOrderType')
377
+ existing_order.return_order_type_name = data.get('returnOrderTypeName')
378
+ existing_order.return_order_status = data.get('returnOrderStatus')
379
+ existing_order.return_order_status_name = data.get('returnOrderStatusName')
380
+ existing_order.wait_return_quantity = data.get('waitReturnQuantity')
381
+ existing_order.return_quantity = data.get('returnQuantity')
382
+ existing_order.return_amount = data.get('returnAmount')
383
+ existing_order.pricing_currency_id = data.get('pricingCurrencyId')
384
+ existing_order.currency_code = data.get('currencyCode')
385
+ existing_order.return_reason_type = data.get('returnReasonType')
386
+ existing_order.return_reason_type_name = data.get('returnReasonTypeName')
387
+ existing_order.return_reason = data.get('returnReason')
388
+ existing_order.reject_pic_url_list = data.get('rejectPicUrlList')
389
+ existing_order.skc_name_list = data.get('skcNameList')
390
+ existing_order.supplier_code_list = data.get('supplierCodeList')
391
+ existing_order.goods_thumb = data.get('goodsThumb')
392
+ existing_order.seller_contract = data.get('sellerContract')
393
+ existing_order.seller_contract_phone = data.get('sellerContractPhone')
394
+ existing_order.seller_order_no = data.get('sellerOrderNo')
395
+ existing_order.seller_order_no_list = data.get('sellerOrderNoList')
396
+ existing_order.seller_delivery_no = data.get('sellerDeliveryNo')
397
+ existing_order.return_scrap_type = data.get('returnScrapType')
398
+ existing_order.return_scrap_type_name = data.get('returnScrapTypeName')
399
+ existing_order.return_dimensions = data.get('returnDimensions')
400
+ existing_order.stock_mode = data.get('stockMode')
401
+ existing_order.order_type = data.get('orderType')
402
+ existing_order.skc_num = data.get('skcNum')
403
+ existing_order.has_package = data.get('hasPackage')
404
+ existing_order.has_report_url = data.get('hasReportUrl')
405
+ existing_order.is_sign = data.get('isSign')
406
+ existing_order.is_increase = data.get('isIncrease')
407
+ existing_order.can_apply_reconsider = data.get('canApplyReconsider')
408
+ existing_order.qc_report_url = data.get('qc_report_url')
409
+ existing_order.report_url = data.get('report_url')
410
+ existing_order.add_time = self._parse_datetime(data.get('addTime'))
411
+ existing_order.sign_time = self._parse_datetime(data.get('signTime'))
412
+ existing_order.complete_time = self._parse_datetime(data.get('completeTime'))
413
+ existing_order.updated_at = datetime.now()
414
+
415
+ # 不更新 明细记录
416
+ # # 删除旧的明细记录
417
+ # session.query(SheinReturnOrderDetail).filter_by(return_order_id=existing_order.id).delete()
418
+
419
+ # # 插入新的明细记录
420
+ # self._insert_return_order_details(session, existing_order.id, data.get('return_box_detail', []))
421
+
422
+ def _insert_return_order_details(self, session, return_order_id, return_box_details):
423
+ """
424
+ 插入退货明细记录
425
+ """
426
+ for box_detail in return_box_details:
427
+ express_code = box_detail.get('expressCode')
428
+ delivery_time = self._parse_datetime(box_detail.get('deliveryTime'))
429
+ self_pick_start_time = self._parse_datetime(box_detail.get('selfPickStartTime'))
430
+ supplier_category_type_flag = 1 if box_detail.get('supplierCategoryTypeFlag') else 0
431
+
432
+ for box in box_detail.get('boxList', []):
433
+ package_name = box.get('packageName')
434
+ return_box_no = box.get('returnBoxNo')
435
+
436
+ for goods in box.get('goods', []):
437
+ img_path = goods.get('imgPath')
438
+ skc = goods.get('skc')
439
+ skc_copy_flag = goods.get('skcCopyFlag')
440
+ supplier_code = goods.get('supplierCode')
441
+
442
+ for detail in goods.get('details', []):
443
+ detail_record = SheinReturnOrderDetail(
444
+ return_order_id=return_order_id,
445
+ express_code=express_code,
446
+ delivery_time=delivery_time,
447
+ self_pick_start_time=self_pick_start_time,
448
+ supplier_category_type_flag=supplier_category_type_flag,
449
+ package_name=package_name,
450
+ return_box_no=return_box_no,
451
+ img_path=img_path,
452
+ skc=skc,
453
+ skc_copy_flag=skc_copy_flag,
454
+ supplier_code=supplier_code,
455
+ platform_sku=detail.get('platformSku'),
456
+ supplier_sku=detail.get('supplierSku'),
457
+ suffix_zh=detail.get('suffixZh'),
458
+ return_quantity=detail.get('returnQuantity'),
459
+ erp_supplier_name=detail.get('erp_supplier_name'),
460
+ erp_cost_price=detail.get('erp_cost_price')
461
+ )
462
+ session.add(detail_record)
463
+
464
+ def get_return_orders(self, limit=None, offset=None):
465
+ """
466
+ 查询退货单列表
467
+
468
+ Args:
469
+ limit (int): 限制返回数量
470
+ offset (int): 偏移量
471
+
472
+ Returns:
473
+ list: 退货单列表
474
+ """
475
+ session = self.Session()
476
+ try:
477
+ query = session.query(SheinReturnOrder)
478
+ if offset:
479
+ query = query.offset(offset)
480
+ if limit:
481
+ query = query.limit(limit)
482
+ return query.all()
483
+ finally:
484
+ session.close()
485
+
486
+ def search_return_orders(self, **kwargs):
487
+ """
488
+ 根据条件搜索退货单
489
+
490
+ Args:
491
+ **kwargs: 搜索条件,如return_order_no, seller_id等
492
+
493
+ Returns:
494
+ list: 符合条件的退货单列表
495
+ """
496
+ session = self.Session()
497
+ try:
498
+ query = session.query(SheinReturnOrder)
499
+
500
+ # 根据传入的条件进行过滤
501
+ for key, value in kwargs.items():
502
+ if hasattr(SheinReturnOrder, key) and value is not None:
503
+ query = query.filter(getattr(SheinReturnOrder, key) == value)
504
+
505
+ return query.all()
506
+ finally:
507
+ session.close()
508
+
509
+ def update_user_notes(self, return_order_id, notes):
510
+ """
511
+ 更新用户备注
512
+
513
+ Args:
514
+ return_order_id (int): 退货单ID
515
+ notes (str): 备注内容
516
+ """
517
+ session = self.Session()
518
+ try:
519
+ order = session.query(SheinReturnOrder).filter_by(id=return_order_id).first()
520
+ if order:
521
+ order.user_notes = notes
522
+ order.updated_at = datetime.now()
523
+ session.commit()
524
+ return True
525
+ return False
526
+ except Exception as e:
527
+ session.rollback()
528
+ raise
529
+ finally:
530
+ session.close()
531
+
532
+ def example_usage():
533
+ """
534
+ 使用示例
535
+ """
536
+ # 数据库连接URL(请根据实际情况修改)
537
+ database_url = "mysql+pymysql://root:123wyk@localhost:3306/lz"
538
+
539
+ # 创建管理器实例
540
+ manager = SheinReturnOrderManager(database_url)
541
+
542
+ # 创建数据表
543
+ manager.create_tables()
544
+
545
+ # 从JSON文件导入数据
546
+ json_file = "shein_return_order_list_2025-08-17_2025-08-19.json"
547
+
548
+ # 读取JSON文件
549
+ with open(json_file, 'r', encoding='utf-8') as f:
550
+ dict = json.load(f)
551
+ for store_username, data_list in dict.items():
552
+ manager.upsert_return_order_data(store_username, data_list)
553
+
554
+ # 查询示例
555
+ orders = manager.get_return_orders(limit=10)
556
+ for order in orders:
557
+ print(f"退货单号: {order.return_order_no}, 状态: {order.return_order_status_name}")
558
+
559
+ # 搜索示例
560
+ search_results = manager.search_return_orders(return_order_status=4)
561
+ print(f"已全部出库的订单数量: {len(search_results)}")
562
+
563
+ # 更新备注示例
564
+ # if orders:
565
+ # manager.update_user_notes(orders[0].id, "这是一个测试备注")
566
+
567
+ if __name__ == "__main__":
568
+ pass
569
+ example_usage()