feat(transfer): 2-day email filter, trace each mail exit point with full debug
This commit is contained in:
parent
93af2f8c62
commit
baffcaa043
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user