This commit is contained in:
yumoqing 2025-12-16 18:29:59 +08:00
parent 08f1939601
commit 0b8d9f4bd6
5 changed files with 144 additions and 2 deletions

15
json/transfercode.json Normal file
View File

@ -0,0 +1,15 @@
{
"tblname": "transfercode",
"title": "转账码",
"params": {
"sortby": "id",
"browserfields": {
"exclouded": ["id"],
"alters": {
}
},
"editexclouded": [
"id"
]
}
}

BIN
models/transfercode.xlsx Normal file

Binary file not shown.

View File

@ -8,6 +8,12 @@ from .payfee import get_pay_fee, sor_get_pay_fee, get_paychannels, get_pay_feera
# 从 env 或配置载入 provider conf这里只示例
CONF = {
"transfer":{
"pop3server": os.getenv("POP3SERVER", ""),
"mail": os.getenv("MAIL", ""),
"password": os.getenv("PASSWORD", "")
"from_mail": os.getenv("FROM_MAIL", "")
}
"wechat": {
"mchid": os.getenv("WXP_MCHID",""),
"appid": os.getenv("WXP_APPID", ""),
@ -132,6 +138,7 @@ async def payment_notify(request, callback, params_kw=None):
# callback url= "/unipay/notify/{provider}"
def load_unipay():
PROVIDERS["transfer"] = get_provider("transfer", CONF["transfer"]),
PROVIDERS["wechat"] = get_provider("wechat", CONF["wechat"]),
PROVIDERS["paypal"] = get_provider("paypal", CONF["paypal"]),
PROVIDERS["alipay"] = get_provider("alipay", CONF["alipay"]),

View File

@ -1,5 +1,7 @@
# unipay/notify.py
from typing import Dict
from appPublic.log import exception
from .providers.transfer import TransferGateway
from .providers.wechat import WechatGateway
from .providers.paypal import PaypalGateway
from .providers.alipay import AlipayGateway
@ -12,12 +14,15 @@ def get_provider_channel(name:str):
"wechat":"0",
"paypal":"1",
"alipay":"2",
"stripe":"3"
"stripe":"3",
"transfer":"4"
}
return channels.get(name, '9')
def get_provider(name: str, conf: Dict):
try:
if name == "transfer":
return TransferGateway(**conf)
if name == "wechat":
return WechatGateway(**conf)
if name == "paypal":
@ -26,7 +31,8 @@ def get_provider(name: str, conf: Dict):
return AlipayGateway(**conf)
if name == "stripe":
return StripeGateway(**conf)
except:
except Exception as e:
exception(f'get_proveder() error {name=}, {conf=}, {e}')
return None
raise ValueError("unknown provider")

View File

@ -0,0 +1,114 @@
import re
from random import randint
import poplib
from appPublic.log import debug
from appPublic.dictObject import DictObject
from appPublic.timeUtils import curDateString, timestampstr
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
from ..core import Gateway
def guess_charset(msg):
charset = msg.get_charset()
if charset is None:
content_type = msg.get('Content-Type', '').lower()
pos = content_type.find('charset=')
if pos >= 0:
charset = content_type[pos + 8:].strip()
return charset
class EmailClient:
def __init__(self, pop3_server, emailaddress, password):
self.client = poplib.POP3(pop3_server)
self.client.user(emailaddress)
self.client.pass_(password)
def stat(self):
return self.client.stat()
def mail_list(self):
resp, mails, octets = self.client.list()
def get_mail(self, index):
resp, lines, octets = self.client.retr(index)
debug(f'{resp=}, {octets=}')
msg_content = b'\r\n'.join(lines).decode('utf-8')
msg = Parser().parsestr(msg_content)
mail = {
"mailfrom": msg.get('From'),
"mailto": msg.get('To'),
"subject": msg.get('Subject'),
"body": self.get_body(msg)
}
return DictObject(**mail)
def get_body(self, msg):
if msg.is_multipart():
parts = msg.get_payload()
content = ''
for part in parts:
content += self.get_body(part)
return content
else:
content_type = msg.get_content_type()
content = msg.get_payload(decode=True)
charset = guess_charset(msg)
if charset:
content = content.decode(charset)
else:
content = content.decode('utf-8')
return content
class TransferPay(Gateway):
def __init__(self, from_mail="", pop3server="", email="", password=""):
self.from_email = from_email
self.pop3server = pop3server
self.email = email
self.password = password
self.running = False
async def create_payment(self, payload: Dict[str, Any]) -> str:
"""
返回一个可以在 H5 里直接重定向的支付宝支付 URL
"""
ns = {
"id": payload["out_trade_no"],
"customerid": payload['customerid'],
"amount": payload["amount"],
"tcode": self.gen_mailcode(),
"curdate": curDateString(),
"curtime": timestampstr(),
"status": '0'
}
return
def get_transfer_data(self, mail):
assert mail.mailfrom == '95555@message.cmbchina.com'
assert mail.mailto == self.email
assert mail.body.startswith('动账业务通知')
ns = DictObject()
match = re.search(r'交易金额\s*[:]?\s*(\d+(?:\.\d+)?)', mail.body)
if match:
ns.amount = float(match.group(1))
p = r'摘要[:]\s*(\d{7})(?!\d)'
match = re.search(r'摘要[:]\s*(\d{7})(?!\d)', mail.body)
if match:
ns.code = match.group(1)
assert ns.amount
assert ns.code
return ns
def gen_mailcode(self):
c = '1'
for range(6):
c += randint(0,9)
return c
def run(self):
self.running = True
while self.running:
ec = EmailClient(self.pop3server, self.email, self.password)
mail = ec.get_mail(1)