feat(transfer): process ALL matching emails, not just current tcode

This commit is contained in:
yumoqing 2026-07-17 13:56:58 +08:00
parent baffcaa043
commit c0c04b2bd0

View File

@ -221,14 +221,15 @@ class TransferGateway(Gateway):
await asyncio.sleep(30) await asyncio.sleep(30)
async def check_transfer(self, tcode: str, env): async def check_transfer(self, tcode: str, env):
"""扫描最近2天邮件查找指定转账码并完成入账。 """扫描最近2天邮件对所有匹配的转账码完成入账。
返回: (title, message)""" 返回: (title, message)"""
from datetime import datetime, timedelta from datetime import datetime, timedelta
from email.utils import parsedate_to_datetime
cutoff = datetime.now() - timedelta(days=2) cutoff = datetime.now() - timedelta(days=2)
ec = EmailClient(self.pop3server, self.email, self.password) ec = EmailClient(self.pop3server, self.email, self.password)
count, _ = ec.stat() count, _ = ec.stat()
debug(f'check_transfer: tcode={tcode}, total {count} mails, cutoff={cutoff}') debug('check_transfer: tcode=' + tcode + ' total=' + str(count) + ' mails, cutoff=' + str(cutoff))
db = DBPools() db = DBPools()
dbname = env.get_module_dbname('unipay') dbname = env.get_module_dbname('unipay')
@ -240,8 +241,8 @@ class TransferGateway(Gateway):
tc = recs[0] tc = recs[0]
return ('已入账', '转账码 ' + tcode + ' 已入账 ' + str(tc.amount) + '') return ('已入账', '转账码 ' + tcode + ' 已入账 ' + str(tc.amount) + '')
log_lines = [] done = []
matched = None failed = []
scanned = 0 scanned = 0
for i in range(count, 0, -1): for i in range(count, 0, -1):
@ -250,12 +251,10 @@ class TransferGateway(Gateway):
scanned += 1 scanned += 1
idx = str(i) idx = str(i)
# 日期过滤
mail_date_str = getattr(mail, 'date', None) mail_date_str = getattr(mail, 'date', None)
skip_date = False skip_date = False
if mail_date_str: if mail_date_str:
try: try:
from email.utils import parsedate_to_datetime
mail_date = parsedate_to_datetime(mail_date_str) mail_date = parsedate_to_datetime(mail_date_str)
if mail_date < cutoff: if mail_date < cutoff:
skip_date = True skip_date = True
@ -284,34 +283,23 @@ class TransferGateway(Gateway):
code = str(data.code) code = str(data.code)
amount = data.amount amount = data.amount
debug('mail[' + idx + '] code=' + code + ' amount=' + str(amount) + ' looking_for=' + tcode) debug('mail[' + idx + '] code=' + code + ' amount=' + str(amount))
if code == tcode: # 在transfercode表中查找 status=0 的记录并入账
matched = data
debug('mail[' + idx + '] *** MATCHED tcode=' + tcode + ' amount=' + str(amount) + ' ***')
break
debug('mail[' + idx + '] EXIT: code mismatch ' + code + ' != ' + tcode)
except Exception as e:
debug('mail[' + str(i) + '] ERROR: ' + str(e))
debug('check_transfer: scanned ' + str(scanned) + ' mails, matched=' + str(matched is not None))
if matched is None:
return ('尚未到账', '扫描了 ' + str(scanned) + ' 封邮件,暂未收到转账码 ' + tcode + ' 的到账通知')
# 执行入账
async with db.sqlorContext(dbname) as sor: async with db.sqlorContext(dbname) as sor:
recs = await sor.R('transfercode', {'tcode': tcode, 'status': '0'}) recs = await sor.R('transfercode', {'tcode': code, 'status': '0'})
if len(recs) < 1: if len(recs) < 1:
return ('已处理', '转账码 ' + tcode + ' 已处理或不存在') debug('mail[' + idx + '] EXIT: code ' + code + ' not in transfercode or already processed')
continue
tc = recs[0] tc = recs[0]
diff = abs(float(matched.amount) - float(tc.amount)) diff = abs(float(amount) - float(tc.amount))
if diff > 0.01: if diff > 0.01:
await sor.U('transfercode', {'id': tc.id, 'status': '9', await sor.U('transfercode', {'id': tc.id, 'status': '9',
'remark': '金额不匹配: 到账' + str(matched.amount) + ' 期望' + str(tc.amount)}) 'remark': '金额不匹配: 到账' + str(amount) + ' 期望' + str(tc.amount)})
return ('金额不匹配', '到账金额 ' + str(matched.amount) + ' 与充值金额 ' + str(tc.amount) + ' 不一致') debug('mail[' + idx + '] amount mismatch: ' + str(amount) + ' != ' + str(tc.amount))
failed.append(code + '(金额不匹配)')
continue
biz_date = await env.get_business_date(sor) biz_date = await env.get_business_date(sor)
await sor.U('transfercode', {'id': tc.id, 'status': '1'}) await sor.U('transfercode', {'id': tc.id, 'status': '1'})
@ -327,9 +315,28 @@ class TransferGateway(Gateway):
'payment_status': '1', 'payment_status': '1',
'payed_timestamp': timestampstr() 'payed_timestamp': timestampstr()
}) })
debug('check_transfer: ACCOUNTING DONE for ' + tcode + ' amount=' + str(matched.amount))
return ('充值成功', '转账码 ' + tcode + ' 已确认到账 ' + str(matched.amount) + '') done.append(code + '(' + str(amount) + '元)')
debug('mail[' + idx + '] ACCOUNTING DONE: code=' + code + ' amount=' + str(amount))
except Exception as e:
debug('mail[' + str(i) + '] ERROR: ' + str(e))
debug('check_transfer: scanned=' + str(scanned) + ' done=' + str(done) + ' failed=' + str(failed))
# 构造返回消息
msg_parts = []
if done:
msg_parts.append('入账成功 ' + str(len(done)) + ' 笔: ' + ', '.join(done))
if failed:
msg_parts.append('失败 ' + str(len(failed)) + ' 笔: ' + ', '.join(failed))
if tcode in [d.split('(')[0] for d in done]:
return ('充值成功', '\n'.join(msg_parts))
if not done and not failed:
return ('尚未到账', '扫描了 ' + str(scanned) + ' 封邮件,暂未收到转账码 ' + tcode + ' 的到账通知')
return ('转账检查结果', '\n'.join(msg_parts) + '\n\n当前转账码 ' + tcode + ' 尚未到账')
async def query(self, out_trade_no: str) -> Dict[str, Any]: async def query(self, out_trade_no: str) -> Dict[str, Any]:
pass pass