feat(transfer): 2-day email filter, trace each mail exit point with full debug

This commit is contained in:
yumoqing 2026-07-17 13:53:31 +08:00
parent 93af2f8c62
commit baffcaa043

View File

@ -45,6 +45,7 @@ class EmailClient:
"mailfrom": msg.get('From'),
"mailto": msg.get('To'),
"subject": msg.get('Subject'),
"date": msg.get('Date'),
"body": self.get_body(msg)
}
return DictObject(**mail)
@ -220,11 +221,14 @@ class TransferGateway(Gateway):
await asyncio.sleep(30)
async def check_transfer(self, tcode: str, env):
"""手动检查指定转账码的邮件并完成入账。
"""扫描最近2天邮件查找指定转账码并完成入账。
返回: (title, message)"""
from datetime import datetime, timedelta
cutoff = datetime.now() - timedelta(days=2)
ec = EmailClient(self.pop3server, self.email, self.password)
count, _ = ec.stat()
debug(f'check_transfer: tcode={tcode}, got {count} mails')
debug(f'check_transfer: tcode={tcode}, total {count} mails, cutoff={cutoff}')
db = DBPools()
dbname = env.get_module_dbname('unipay')
@ -234,48 +238,80 @@ class TransferGateway(Gateway):
recs = await sor.R('transfercode', {'tcode': tcode})
if recs and recs[0].status == '1':
tc = recs[0]
return ('已入账', f'转账码 {tcode} 已入账 {tc.amount}')
return ('已入账', '转账码 ' + tcode + ' 已入账 ' + str(tc.amount) + '')
# 扫描邮件
log_lines = []
matched = None
scanned = 0
for i in range(count, 0, -1):
try:
mail = ec.get_mail(i)
debug(f'check_transfer: mail[{i}] from={mail.mailfrom} body_head={mail.body[:20]}')
if mail.mailfrom != '95555@message.cmbchina.com':
debug(f'check_transfer: mail[{i}] skipped, wrong sender')
scanned += 1
idx = str(i)
# 日期过滤
mail_date_str = getattr(mail, 'date', None)
skip_date = False
if mail_date_str:
try:
from email.utils import parsedate_to_datetime
mail_date = parsedate_to_datetime(mail_date_str)
if mail_date < cutoff:
skip_date = True
except:
pass
if skip_date:
debug('mail[' + idx + '] date=' + str(mail_date_str) + ' older than 2 days, skip')
continue
if not mail.body.startswith('动账业务通知'):
debug(f'check_transfer: mail[{i}] skipped, not 动账业务通知')
from_addr = getattr(mail, 'mailfrom', '?')
subject = getattr(mail, 'subject', '?')
body_head = (getattr(mail, 'body', '') or '')[:50].replace('\n', ' ')
debug('mail[' + idx + '] date=' + str(mail_date_str) + ' from=' + str(from_addr) + ' subj=' + str(subject) + ' body=' + body_head)
if from_addr != '95555@message.cmbchina.com':
debug('mail[' + idx + '] EXIT: wrong sender')
continue
if not (getattr(mail, 'body', '') or '').startswith('动账业务通知'):
debug('mail[' + idx + '] EXIT: not 动账业务通知')
continue
data = self.get_transfer_data(mail)
if data is None:
debug(f'check_transfer: mail[{i}] get_transfer_data returned None')
debug('mail[' + idx + '] EXIT: get_transfer_data returned None')
continue
debug(f'check_transfer: mail[{i}] code={data.code} amount={data.amount}, looking for {tcode}')
if str(data.code) == tcode:
code = str(data.code)
amount = data.amount
debug('mail[' + idx + '] code=' + code + ' amount=' + str(amount) + ' looking_for=' + tcode)
if code == tcode:
matched = data
debug(f'check_transfer: mail[{i}] MATCHED!')
debug('mail[' + idx + '] *** MATCHED tcode=' + tcode + ' amount=' + str(amount) + ' ***')
break
debug(f'check_transfer: mail[{i}] code mismatch: {data.code} != {tcode}')
debug('mail[' + idx + '] EXIT: code mismatch ' + code + ' != ' + tcode)
except Exception as e:
debug(f'check_transfer: skip mail {i}: {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 ('尚未到账', f'暂未收到转账码 {tcode} 的到账通知')
return ('尚未到账', '扫描了 ' + str(scanned) + ' 封邮件,暂未收到转账码 ' + tcode + ' 的到账通知')
# 执行入账
async with db.sqlorContext(dbname) as sor:
recs = await sor.R('transfercode', {'tcode': tcode, 'status': '0'})
if len(recs) < 1:
return ('已处理', f'转账码 {tcode} 已处理或不存在')
return ('已处理', '转账码 ' + tcode + ' 已处理或不存在')
tc = recs[0]
diff = abs(float(matched.amount) - float(tc.amount))
if diff > 0.01:
await sor.U('transfercode', {'id': tc.id, 'status': '9',
'remark': '金额不匹配: 到账' + str(matched.amount) + ' 期望' + str(tc.amount)})
return ('金额不匹配', f'到账金额 {matched.amount} 与充值金额 {tc.amount} 不一致')
return ('金额不匹配', '到账金额 ' + str(matched.amount) + ' 与充值金额 ' + str(tc.amount) + ' 不一致')
biz_date = await env.get_business_date(sor)
await sor.U('transfercode', {'id': tc.id, 'status': '1'})
@ -291,8 +327,9 @@ class TransferGateway(Gateway):
'payment_status': '1',
'payed_timestamp': timestampstr()
})
debug('check_transfer: ACCOUNTING DONE for ' + tcode + ' amount=' + str(matched.amount))
return ('充值成功', f'转账码 {tcode} 已确认到账 {matched.amount}')
return ('充值成功', '转账码 ' + tcode + ' 已确认到账 ' + str(matched.amount) + '')
async def query(self, out_trade_no: str) -> Dict[str, Any]:
pass