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,638 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ 希音钱包与提现数据模型
5
+ 使用SQLAlchemy定义钱包余额表和提现记录表
6
+ 优化:使用 ON DUPLICATE KEY UPDATE 批量 upsert 提高插入效率
7
+ """
8
+
9
+ from sqlalchemy import create_engine, Column, Integer, String, BigInteger, DateTime, Text, Index, DECIMAL
10
+ from sqlalchemy.ext.declarative import declarative_base
11
+ from sqlalchemy.dialects.mysql import insert
12
+ from sqlalchemy.exc import OperationalError
13
+ from sqlalchemy.orm import sessionmaker
14
+ from datetime import datetime
15
+ import json
16
+ import time
17
+
18
+ # 创建基类
19
+ Base = declarative_base()
20
+
21
+
22
+ class SheinStoreWallet(Base):
23
+ """
24
+ 希音店铺钱包余额表
25
+ 存储钱包余额信息(来自 /mws/mwms/sso/balance/query 接口)
26
+ """
27
+ __tablename__ = 'shein_store_wallet'
28
+
29
+ # 主键ID
30
+ id = Column(BigInteger, primary_key=True, autoincrement=True, comment='主键ID')
31
+
32
+ # 关联店铺账号(唯一)
33
+ store_username = Column(String(100), nullable=False, unique=True, comment='店铺账号')
34
+ store_name = Column(String(200), nullable=True, comment='店铺名称')
35
+ supplier_id = Column(BigInteger, nullable=True, comment='供应商ID')
36
+
37
+ # ==================== 账户状态 ====================
38
+ is_fp_account = Column(Integer, nullable=True, default=0, comment='是否FP账户(0-否,1-是)')
39
+ deposit_flag = Column(Integer, nullable=True, comment='验证密码标志(1-需要验证,0-已验证)')
40
+
41
+ # ==================== 余额信息 ====================
42
+ currency = Column(String(20), nullable=True, comment='币种')
43
+ withdrawable_amount = Column(DECIMAL(18, 2), nullable=True, comment='可提现金额')
44
+ no_withdrawable_amount = Column(DECIMAL(18, 2), nullable=True, comment='不可提现金额')
45
+ withdrawing_amount = Column(DECIMAL(18, 2), nullable=True, comment='提现中金额')
46
+ balance_last_update_time = Column(BigInteger, nullable=True, comment='余额最后更新时间戳')
47
+ auto_withdraw_state = Column(Integer, nullable=True, default=0, comment='自动提现状态(0-关闭,1-开启)')
48
+ can_withdraw = Column(Integer, nullable=True, default=1, comment='是否可提现(0-否,1-是)')
49
+ no_withdraw_reasons = Column(Text, nullable=True, comment='不可提现原因列表(JSON)')
50
+
51
+ # ==================== 保证金信息 ====================
52
+ deposit_currency = Column(String(20), nullable=True, comment='保证金币种')
53
+ deposit_amount_paid = Column(DECIMAL(18, 2), nullable=True, comment='已缴保证金')
54
+ deposit_amount_unpaid = Column(DECIMAL(18, 2), nullable=True, comment='未缴保证金')
55
+ deposit_last_update_time = Column(BigInteger, nullable=True, comment='保证金最后更新时间戳')
56
+
57
+ # ==================== 原始数据 ====================
58
+ raw_balance_json = Column(Text, nullable=True, comment='余额原始数据(JSON)')
59
+ raw_deposit_json = Column(Text, nullable=True, comment='保证金原始数据(JSON)')
60
+
61
+ # ==================== 管理字段 ====================
62
+ is_deleted = Column(Integer, nullable=True, default=0, comment='软删除标志(0-未删除,1-已删除)')
63
+ remark = Column(String(500), nullable=True, comment='备注')
64
+
65
+ # 时间戳
66
+ created_at = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间')
67
+ updated_at = Column(DateTime, nullable=True, default=datetime.now, onupdate=datetime.now, comment='更新时间')
68
+
69
+ # 创建索引
70
+ __table_args__ = (
71
+ Index('idx_wallet_supplier_id', 'supplier_id'),
72
+ Index('idx_wallet_currency', 'currency'),
73
+ )
74
+
75
+ def __repr__(self):
76
+ return f"<SheinStoreWallet(id={self.id}, store_username='{self.store_username}', withdrawable={self.withdrawable_amount})>"
77
+
78
+
79
+
80
+ class SheinStoreWithdraw(Base):
81
+ """
82
+ 希音店铺提现记录表
83
+ 存储提现成功记录(来自 /mws/mwms/sso/withdraw/transferRecordList 接口)
84
+ """
85
+ __tablename__ = 'shein_store_withdraw'
86
+
87
+ # 主键ID
88
+ id = Column(BigInteger, primary_key=True, autoincrement=True, comment='主键ID')
89
+
90
+ # 关联店铺账号
91
+ store_username = Column(String(100), nullable=False, comment='店铺账号')
92
+ store_name = Column(String(200), nullable=True, comment='店铺名称')
93
+ supplier_id = Column(BigInteger, nullable=True, comment='供应商ID')
94
+
95
+ # ==================== 提现单信息 ====================
96
+ withdraw_no = Column(String(100), nullable=True, comment='提现单号')
97
+ transfer_no = Column(String(100), nullable=True, unique=True, comment='转账单号(唯一)')
98
+
99
+ # ==================== 金额信息 ====================
100
+ currency = Column(String(20), nullable=True, comment='币种')
101
+ net_amount = Column(DECIMAL(18, 2), nullable=True, comment='净金额')
102
+ deposit_amount = Column(DECIMAL(18, 2), nullable=True, comment='保证金金额')
103
+ commission_amount = Column(DECIMAL(18, 2), nullable=True, comment='手续费金额')
104
+ receiving_currency = Column(String(20), nullable=True, comment='收款币种')
105
+ receiving_amount = Column(DECIMAL(18, 2), nullable=True, comment='收款金额')
106
+ exchange_rate = Column(String(50), nullable=True, comment='汇率')
107
+
108
+ # ==================== 账户信息 ====================
109
+ source_account_value = Column(String(100), nullable=True, comment='来源账户(脱敏)')
110
+ account_area_code = Column(String(20), nullable=True, comment='账户地区代码')
111
+
112
+ # ==================== 状态信息 ====================
113
+ withdraw_status = Column(Integer, nullable=True, comment='提现状态(30-提现成功)')
114
+ withdraw_status_desc = Column(String(50), nullable=True, comment='提现状态描述')
115
+ fail_reason = Column(String(500), nullable=True, comment='失败原因')
116
+ retry_flag = Column(Integer, nullable=True, default=0, comment='重试标志')
117
+
118
+ # ==================== 提现来源 ====================
119
+ withdraw_source = Column(Integer, nullable=True, comment='提现来源(0-人工提现)')
120
+ withdraw_source_desc = Column(String(50), nullable=True, comment='提现来源描述')
121
+
122
+ # ==================== 电子回单 ====================
123
+ ele_ticket_status_code = Column(Integer, nullable=True, comment='电子回单状态码')
124
+ ele_ticket_status_desc = Column(String(50), nullable=True, comment='电子回单状态描述')
125
+ ele_ticket_button_code = Column(Integer, nullable=True, comment='电子回单按钮码')
126
+ ele_ticket_button_desc = Column(String(50), nullable=True, comment='电子回单按钮描述')
127
+
128
+ # ==================== 时间信息 ====================
129
+ create_time = Column(BigInteger, nullable=True, comment='创建时间戳')
130
+ last_update_time = Column(BigInteger, nullable=True, comment='最后更新时间戳')
131
+ transfer_success_time = Column(BigInteger, nullable=True, comment='转账成功时间戳')
132
+
133
+ # ==================== 管理字段 ====================
134
+ is_deleted = Column(Integer, nullable=True, default=0, comment='软删除标志(0-未删除,1-已删除)')
135
+ remark = Column(String(500), nullable=True, comment='备注')
136
+
137
+ # 时间戳
138
+ created_at = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间')
139
+ updated_at = Column(DateTime, nullable=True, default=datetime.now, onupdate=datetime.now, comment='更新时间')
140
+
141
+ # 创建索引
142
+ __table_args__ = (
143
+ Index('idx_withdraw_supplier_id', 'supplier_id'),
144
+ Index('idx_withdraw_store_username', 'store_username'),
145
+ Index('idx_withdraw_no', 'withdraw_no'),
146
+ Index('idx_withdraw_status', 'withdraw_status'),
147
+ Index('idx_withdraw_create_time', 'create_time'),
148
+ )
149
+
150
+ def __repr__(self):
151
+ return f"<SheinStoreWithdraw(id={self.id}, transfer_no='{self.transfer_no}', amount={self.net_amount})>"
152
+
153
+
154
+ class SheinStoreWalletManager:
155
+ """
156
+ 钱包余额数据管理器
157
+ 使用 ON DUPLICATE KEY UPDATE 批量 upsert 提高效率
158
+ """
159
+
160
+ def __init__(self, database_url):
161
+ print(f"连接数据库: {database_url}")
162
+ self.engine = create_engine(
163
+ database_url,
164
+ echo=False,
165
+ pool_size=20,
166
+ max_overflow=10,
167
+ pool_recycle=3600,
168
+ pool_pre_ping=True,
169
+ )
170
+ self.Session = sessionmaker(bind=self.engine, autoflush=False)
171
+
172
+ def create_table(self):
173
+ Base.metadata.create_all(self.engine)
174
+ print("钱包余额表创建成功")
175
+
176
+ def upsert_data(self, data_list, batch_size=500):
177
+ """
178
+ 批量插入/更新钱包余额数据(幂等性)
179
+ 使用 ON DUPLICATE KEY UPDATE 实现
180
+
181
+ Args:
182
+ data_list (list): 钱包数据列表
183
+ batch_size (int): 每批次插入的记录数
184
+ """
185
+ if not data_list:
186
+ print("没有钱包余额数据需要插入")
187
+ return 0
188
+
189
+ # 准备数据,添加时间戳
190
+ records = []
191
+ for data in data_list:
192
+ record = data.copy()
193
+ record['created_at'] = datetime.now()
194
+ record['updated_at'] = datetime.now()
195
+ records.append(record)
196
+
197
+ # 批量 upsert(带死锁重试)
198
+ max_retries = 3
199
+ total_count = 0
200
+
201
+ with self.engine.connect() as conn:
202
+ for i in range(0, len(records), batch_size):
203
+ batch = records[i:i + batch_size]
204
+ stmt = insert(SheinStoreWallet).values(batch)
205
+ # ON DUPLICATE KEY UPDATE(store_username 是唯一键)
206
+ stmt = stmt.on_duplicate_key_update(
207
+ store_name=stmt.inserted.store_name,
208
+ supplier_id=stmt.inserted.supplier_id,
209
+ is_fp_account=stmt.inserted.is_fp_account,
210
+ deposit_flag=stmt.inserted.deposit_flag,
211
+ currency=stmt.inserted.currency,
212
+ withdrawable_amount=stmt.inserted.withdrawable_amount,
213
+ no_withdrawable_amount=stmt.inserted.no_withdrawable_amount,
214
+ withdrawing_amount=stmt.inserted.withdrawing_amount,
215
+ balance_last_update_time=stmt.inserted.balance_last_update_time,
216
+ auto_withdraw_state=stmt.inserted.auto_withdraw_state,
217
+ can_withdraw=stmt.inserted.can_withdraw,
218
+ no_withdraw_reasons=stmt.inserted.no_withdraw_reasons,
219
+ deposit_currency=stmt.inserted.deposit_currency,
220
+ deposit_amount_paid=stmt.inserted.deposit_amount_paid,
221
+ deposit_amount_unpaid=stmt.inserted.deposit_amount_unpaid,
222
+ deposit_last_update_time=stmt.inserted.deposit_last_update_time,
223
+ raw_balance_json=stmt.inserted.raw_balance_json,
224
+ raw_deposit_json=stmt.inserted.raw_deposit_json,
225
+ updated_at=datetime.now()
226
+ )
227
+ # 死锁重试
228
+ for retry in range(max_retries):
229
+ try:
230
+ conn.execute(stmt)
231
+ total_count += len(batch)
232
+ break
233
+ except OperationalError as e:
234
+ if 'Deadlock' in str(e) and retry < max_retries - 1:
235
+ print(f"[WARN] 死锁,重试 {retry + 1}/{max_retries}...")
236
+ time.sleep(1)
237
+ continue
238
+ raise
239
+ conn.commit()
240
+
241
+ print(f"[OK] 钱包余额: 成功 upsert {total_count} 条记录")
242
+ return total_count
243
+
244
+ def insert_data(self, data_list):
245
+ """兼容旧接口,内部调用 upsert_data"""
246
+ return self.upsert_data(data_list)
247
+
248
+ def import_from_api_response(self, store_username, store_name, supplier_id, api_response):
249
+ """
250
+ 从API响应导入钱包余额信息
251
+
252
+ Args:
253
+ store_username (str): 店铺账号
254
+ store_name (str): 店铺名称
255
+ supplier_id (int): 供应商ID
256
+ api_response (dict): get_wallet_balance_detail 返回的数据
257
+
258
+ Returns:
259
+ dict: 解析后的记录数据(用于批量导入)
260
+ """
261
+ record = {
262
+ 'store_username': store_username,
263
+ 'store_name': store_name,
264
+ 'supplier_id': supplier_id,
265
+ 'is_fp_account': 1 if api_response.get('isFpAccount') else 0,
266
+ 'deposit_flag': api_response.get('depositFlag', 1),
267
+ }
268
+
269
+ # 解析余额信息(取第一个)
270
+ balance_list = api_response.get('balanceList', [])
271
+ if balance_list:
272
+ balance = balance_list[0]
273
+ record.update({
274
+ 'currency': balance.get('currency'),
275
+ 'withdrawable_amount': balance.get('withdrawableAmount'),
276
+ 'no_withdrawable_amount': balance.get('noWithdrawableAmount'),
277
+ 'withdrawing_amount': balance.get('withdrawingAmount'),
278
+ 'balance_last_update_time': balance.get('lastUpdateTime'),
279
+ 'auto_withdraw_state': balance.get('autoWithdrawState', 0),
280
+ 'can_withdraw': 1 if balance.get('canWithdraw') else 0,
281
+ 'no_withdraw_reasons': json.dumps(balance.get('noWithdrawReasons', []), ensure_ascii=False),
282
+ })
283
+
284
+ # 解析保证金信息(取第一个)
285
+ deposit_list = api_response.get('depositList', [])
286
+ if deposit_list:
287
+ deposit = deposit_list[0]
288
+ record.update({
289
+ 'deposit_currency': deposit.get('currency'),
290
+ 'deposit_amount_paid': deposit.get('depositAmountPaid'),
291
+ 'deposit_amount_unpaid': deposit.get('depositAmountUnPaid'),
292
+ 'deposit_last_update_time': deposit.get('lastUpdateTime'),
293
+ })
294
+
295
+ # 保存原始数据
296
+ record['raw_balance_json'] = json.dumps(balance_list, ensure_ascii=False) if balance_list else None
297
+ record['raw_deposit_json'] = json.dumps(deposit_list, ensure_ascii=False) if deposit_list else None
298
+
299
+ return record
300
+
301
+ def batch_import(self, wallet_data_list):
302
+ """
303
+ 批量导入钱包余额数据
304
+
305
+ Args:
306
+ wallet_data_list (list): 包含 store_username, store_name, supplier_id, data 的字典列表
307
+
308
+ Returns:
309
+ int: 成功导入的记录数
310
+ """
311
+ if not wallet_data_list:
312
+ print("没有钱包余额数据需要导入")
313
+ return 0
314
+
315
+ records = []
316
+ for item in wallet_data_list:
317
+ record = self.import_from_api_response(
318
+ store_username=item['store_username'],
319
+ store_name=item['store_name'],
320
+ supplier_id=item['supplier_id'],
321
+ api_response=item['data']
322
+ )
323
+ records.append(record)
324
+
325
+ return self.upsert_data(records)
326
+
327
+ def get_by_store_username(self, store_username, include_deleted=False):
328
+ session = self.Session()
329
+ try:
330
+ query = session.query(SheinStoreWallet).filter(
331
+ SheinStoreWallet.store_username == store_username
332
+ )
333
+ if not include_deleted:
334
+ query = query.filter(SheinStoreWallet.is_deleted == 0)
335
+ return query.first()
336
+ finally:
337
+ session.close()
338
+
339
+ def get_all(self, include_deleted=False):
340
+ session = self.Session()
341
+ try:
342
+ query = session.query(SheinStoreWallet)
343
+ if not include_deleted:
344
+ query = query.filter(SheinStoreWallet.is_deleted == 0)
345
+ return query.all()
346
+ finally:
347
+ session.close()
348
+
349
+
350
+
351
+ class SheinStoreWithdrawManager:
352
+ """
353
+ 提现记录数据管理器
354
+ 使用 ON DUPLICATE KEY UPDATE 批量 upsert 提高效率
355
+ """
356
+
357
+ def __init__(self, database_url):
358
+ print(f"连接数据库: {database_url}")
359
+ self.engine = create_engine(
360
+ database_url,
361
+ echo=False,
362
+ pool_size=20,
363
+ max_overflow=10,
364
+ pool_recycle=3600,
365
+ pool_pre_ping=True,
366
+ )
367
+ self.Session = sessionmaker(bind=self.engine, autoflush=False)
368
+
369
+ def create_table(self):
370
+ Base.metadata.create_all(self.engine)
371
+ print("提现记录表创建成功")
372
+
373
+ def upsert_data(self, data_list, batch_size=500):
374
+ """
375
+ 批量插入/更新提现记录数据(幂等性)
376
+ 使用 ON DUPLICATE KEY UPDATE 实现
377
+
378
+ Args:
379
+ data_list (list): 提现记录数据列表
380
+ batch_size (int): 每批次插入的记录数
381
+ """
382
+ if not data_list:
383
+ print("没有提现记录数据需要插入")
384
+ return 0
385
+
386
+ # 准备数据,添加时间戳
387
+ records = []
388
+ for data in data_list:
389
+ record = data.copy()
390
+ record['created_at'] = datetime.now()
391
+ record['updated_at'] = datetime.now()
392
+ records.append(record)
393
+
394
+ # 批量 upsert(带死锁重试)
395
+ max_retries = 3
396
+ total_count = 0
397
+
398
+ with self.engine.connect() as conn:
399
+ for i in range(0, len(records), batch_size):
400
+ batch = records[i:i + batch_size]
401
+ stmt = insert(SheinStoreWithdraw).values(batch)
402
+ # ON DUPLICATE KEY UPDATE(transfer_no 是唯一键)
403
+ stmt = stmt.on_duplicate_key_update(
404
+ store_name=stmt.inserted.store_name,
405
+ supplier_id=stmt.inserted.supplier_id,
406
+ withdraw_no=stmt.inserted.withdraw_no,
407
+ currency=stmt.inserted.currency,
408
+ net_amount=stmt.inserted.net_amount,
409
+ deposit_amount=stmt.inserted.deposit_amount,
410
+ commission_amount=stmt.inserted.commission_amount,
411
+ receiving_currency=stmt.inserted.receiving_currency,
412
+ receiving_amount=stmt.inserted.receiving_amount,
413
+ exchange_rate=stmt.inserted.exchange_rate,
414
+ source_account_value=stmt.inserted.source_account_value,
415
+ account_area_code=stmt.inserted.account_area_code,
416
+ withdraw_status=stmt.inserted.withdraw_status,
417
+ withdraw_status_desc=stmt.inserted.withdraw_status_desc,
418
+ fail_reason=stmt.inserted.fail_reason,
419
+ retry_flag=stmt.inserted.retry_flag,
420
+ withdraw_source=stmt.inserted.withdraw_source,
421
+ withdraw_source_desc=stmt.inserted.withdraw_source_desc,
422
+ ele_ticket_status_code=stmt.inserted.ele_ticket_status_code,
423
+ ele_ticket_status_desc=stmt.inserted.ele_ticket_status_desc,
424
+ ele_ticket_button_code=stmt.inserted.ele_ticket_button_code,
425
+ ele_ticket_button_desc=stmt.inserted.ele_ticket_button_desc,
426
+ create_time=stmt.inserted.create_time,
427
+ last_update_time=stmt.inserted.last_update_time,
428
+ transfer_success_time=stmt.inserted.transfer_success_time,
429
+ updated_at=datetime.now()
430
+ )
431
+ # 死锁重试
432
+ for retry in range(max_retries):
433
+ try:
434
+ conn.execute(stmt)
435
+ total_count += len(batch)
436
+ break
437
+ except OperationalError as e:
438
+ if 'Deadlock' in str(e) and retry < max_retries - 1:
439
+ print(f"[WARN] 死锁,重试 {retry + 1}/{max_retries}...")
440
+ time.sleep(1)
441
+ continue
442
+ raise
443
+ conn.commit()
444
+
445
+ print(f"[OK] 提现记录: 成功 upsert {total_count} 条记录")
446
+ return total_count
447
+
448
+ def insert_data(self, data_list):
449
+ """兼容旧接口,内部调用 upsert_data"""
450
+ return self.upsert_data(data_list)
451
+
452
+ def import_from_api_response(self, store_username, store_name, supplier_id, api_response):
453
+ """
454
+ 从API响应解析提现记录(不直接插入,返回记录列表)
455
+
456
+ Args:
457
+ store_username (str): 店铺账号
458
+ store_name (str): 店铺名称
459
+ supplier_id (int): 供应商ID
460
+ api_response (dict): get_withdraw_success_list 返回的数据
461
+
462
+ Returns:
463
+ list: 解析后的记录列表(用于批量导入)
464
+ """
465
+ withdraw_list = api_response.get('list', [])
466
+
467
+ if not withdraw_list:
468
+ return []
469
+
470
+ records = []
471
+ for item in withdraw_list:
472
+ record = {
473
+ 'store_username': store_username,
474
+ 'store_name': store_name,
475
+ 'supplier_id': supplier_id,
476
+
477
+ # 提现单信息
478
+ 'withdraw_no': item.get('withdrawNo'),
479
+ 'transfer_no': item.get('transferNo'),
480
+
481
+ # 金额信息
482
+ 'currency': item.get('currency'),
483
+ 'net_amount': item.get('netAmount'),
484
+ 'deposit_amount': item.get('depositAmount'),
485
+ 'commission_amount': item.get('commissionAmount'),
486
+ 'receiving_currency': item.get('receivingCurrency'),
487
+ 'receiving_amount': item.get('receivingAmount'),
488
+ 'exchange_rate': item.get('exchangeRate'),
489
+
490
+ # 账户信息
491
+ 'source_account_value': item.get('sourceAccountValue'),
492
+ 'account_area_code': item.get('accountAreaCode'),
493
+
494
+ # 状态信息
495
+ 'withdraw_status': item.get('withdrawStatus'),
496
+ 'withdraw_status_desc': item.get('withdrawStatusDesc'),
497
+ 'fail_reason': item.get('failReason'),
498
+ 'retry_flag': item.get('retryFlag', 0),
499
+
500
+ # 提现来源
501
+ 'withdraw_source': item.get('withdrawSource'),
502
+ 'withdraw_source_desc': item.get('withdrawSourceDesc'),
503
+
504
+ # 电子回单
505
+ 'ele_ticket_status_code': item.get('eleTicketStatusCode'),
506
+ 'ele_ticket_status_desc': item.get('eleTicketStatusDesc'),
507
+ 'ele_ticket_button_code': item.get('eleTicketButtonCode'),
508
+ 'ele_ticket_button_desc': item.get('eleTicketButtonDesc'),
509
+
510
+ # 时间信息
511
+ 'create_time': item.get('createTime'),
512
+ 'last_update_time': item.get('lastUpdateTime'),
513
+ 'transfer_success_time': item.get('transferSuccessTime'),
514
+ }
515
+ records.append(record)
516
+
517
+ return records
518
+
519
+ def batch_import(self, withdraw_data_list):
520
+ """
521
+ 批量导入提现记录数据
522
+
523
+ Args:
524
+ withdraw_data_list (list): 包含 store_username, store_name, supplier_id, data 的字典列表
525
+
526
+ Returns:
527
+ int: 成功导入的记录数
528
+ """
529
+ if not withdraw_data_list:
530
+ print("没有提现记录数据需要导入")
531
+ return 0
532
+
533
+ all_records = []
534
+ for item in withdraw_data_list:
535
+ records = self.import_from_api_response(
536
+ store_username=item['store_username'],
537
+ store_name=item['store_name'],
538
+ supplier_id=item['supplier_id'],
539
+ api_response=item['data']
540
+ )
541
+ all_records.extend(records)
542
+
543
+ if not all_records:
544
+ print("没有提现记录数据需要导入")
545
+ return 0
546
+
547
+ return self.upsert_data(all_records)
548
+
549
+ def get_by_store_username(self, store_username, include_deleted=False):
550
+ session = self.Session()
551
+ try:
552
+ query = session.query(SheinStoreWithdraw).filter(
553
+ SheinStoreWithdraw.store_username == store_username
554
+ )
555
+ if not include_deleted:
556
+ query = query.filter(SheinStoreWithdraw.is_deleted == 0)
557
+ return query.all()
558
+ finally:
559
+ session.close()
560
+
561
+ def get_by_transfer_no(self, transfer_no, include_deleted=False):
562
+ session = self.Session()
563
+ try:
564
+ query = session.query(SheinStoreWithdraw).filter(
565
+ SheinStoreWithdraw.transfer_no == transfer_no
566
+ )
567
+ if not include_deleted:
568
+ query = query.filter(SheinStoreWithdraw.is_deleted == 0)
569
+ return query.first()
570
+ finally:
571
+ session.close()
572
+
573
+ def get_all(self, include_deleted=False):
574
+ session = self.Session()
575
+ try:
576
+ query = session.query(SheinStoreWithdraw)
577
+ if not include_deleted:
578
+ query = query.filter(SheinStoreWithdraw.is_deleted == 0)
579
+ return query.all()
580
+ finally:
581
+ session.close()
582
+
583
+ def get_by_date_range(self, store_username, start_time, end_time, include_deleted=False):
584
+ """
585
+ 按时间范围查询提现记录
586
+
587
+ Args:
588
+ store_username (str): 店铺账号
589
+ start_time (int): 开始时间戳(毫秒)
590
+ end_time (int): 结束时间戳(毫秒)
591
+ """
592
+ session = self.Session()
593
+ try:
594
+ query = session.query(SheinStoreWithdraw).filter(
595
+ SheinStoreWithdraw.store_username == store_username,
596
+ SheinStoreWithdraw.create_time >= start_time,
597
+ SheinStoreWithdraw.create_time <= end_time
598
+ )
599
+ if not include_deleted:
600
+ query = query.filter(SheinStoreWithdraw.is_deleted == 0)
601
+ return query.order_by(SheinStoreWithdraw.create_time.desc()).all()
602
+ finally:
603
+ session.close()
604
+
605
+
606
+ # ==================== 便捷函数 ====================
607
+
608
+ _wallet_manager = None
609
+ _withdraw_manager = None
610
+
611
+
612
+ def get_wallet_manager(database_url):
613
+ global _wallet_manager
614
+ if _wallet_manager is None:
615
+ _wallet_manager = SheinStoreWalletManager(database_url)
616
+ return _wallet_manager
617
+
618
+
619
+ def get_withdraw_manager(database_url):
620
+ global _withdraw_manager
621
+ if _withdraw_manager is None:
622
+ _withdraw_manager = SheinStoreWithdrawManager(database_url)
623
+ return _withdraw_manager
624
+
625
+
626
+ if __name__ == '__main__':
627
+ # 测试代码
628
+ database_url = "mysql+pymysql://root:123wyk@47.83.212.3:3306/lz"
629
+
630
+ # 创建钱包余额表
631
+ wallet_manager = SheinStoreWalletManager(database_url)
632
+ wallet_manager.create_table()
633
+
634
+ # 创建提现记录表
635
+ withdraw_manager = SheinStoreWithdrawManager(database_url)
636
+ withdraw_manager.create_table()
637
+
638
+ print("表创建完成")