Files
Pine f1147dced3 feat(pay): 微信支付V3子应用与算力充值
- app/pay 独立支付子应用(config/wxpay/models/repository/service/routers),便于后期拆分微服务
- 充值订单表 0026_compute_recharge;套餐支持折扣(discount)与上架开关(enabled),DB system_configs 优先、env 兜底
- 统一小程序支付:桌面端出小程序码→扫码进小程序确认页按 openid 发起 JSAPI→回调幂等到账(引擎 adjust_user_quota+镜像回写)
- 内嵌 wechatpayv3(含 async_),响应验签失败降级告警;新增 aiofiles 依赖

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-30 22:29:44 +08:00

202 lines
9.4 KiB
Python

# -*- coding: utf-8 -*-
from .type import RequestType
def parking_service_find(self, plate_number, plate_color, openid, sub_mchid=None):
"""查询车牌服务开通信息
:param plate_number: 车牌号,示例值:'粤B888888'
:param plate_color: 车牌颜色,车牌颜色,枚举值:BLUE:蓝色,GREEN:绿色,YELLOW:黄色,BLACK:黑色,WHITE:白色,LIMEGREEN:黄绿色
:param openid: 用户标识,示例值:'oUpF8uMuAJOM2pxb1Q'
:param sub_mchid: (服务商模式)子商户的商户号,由微信支付生成并下发。示例值:'1900000109'
"""
path = '/v3/vehicle/parking/services/find?appid=%s' % self._appid
if plate_number:
path = '%s&plate_number=%s' % (path, plate_number)
else:
raise Exception('plate_number is not assigned.')
if plate_color:
path = '%s&plate_color=%s' % (path, plate_color)
else:
raise Exception('plate_color is not assigned.')
if openid:
path = '%s&openid=%s' % (path, openid)
else:
raise Exception('openid is not assigned.')
if self._partner_mode:
if sub_mchid:
path = '%s&sub_mchid=%s' % (path, sub_mchid)
else:
raise Exception('sub_mchid is not assigned.')
return self._core.request(path)
def parking_enter(self, out_parking_no, plate_number, plate_color, start_time, parking_name, free_duration, notify_url=None, sub_mchid=None):
"""创建停车入场
:param out_parking_no: 商户入场id,商户侧入场标识id,在同一个商户号下唯一,示例值:'1231243'
:param plate_number: 车牌号,示例值:'粤B888888'
:param plate_color: 车牌颜色,车牌颜色,枚举值:BLUE:蓝色,GREEN:绿色,YELLOW:黄色,BLACK:黑色,WHITE:白色,LIMEGREEN:黄绿色
:param notify_url: 回调通知url,接受入场状态变更回调通知的url,只接受https,示例值:https://yoursite.com/wxpay.html
:param start_time: 入场时间,示例值:'2017-08-26T10:43:39+08:00'
:param parking_name: 停车场名称,示例值:'欢乐海岸停车场'
:param free_duration: 免费时长,单位为秒,示例值:3600
:param sub_mchid: (服务商模式)子商户的商户号,由微信支付生成并下发。示例值:'1900000109'
"""
params = {}
if out_parking_no:
params.update({'out_parking_no': out_parking_no})
else:
raise Exception('out_parking_no is not assigned')
if plate_number:
params.update({'plate_number': plate_number})
else:
raise Exception('plate_number is not assigned')
if plate_color:
params.update({'plate_color': plate_color})
else:
raise Exception('plate_color is not assigned')
if not (notify_url or self._notify_url):
raise Exception('notify_url is not assigned.')
params.update({'notify_url': notify_url or self._notify_url})
if start_time:
params.update({'start_time': start_time})
else:
raise Exception('start_time is not assigned')
if parking_name:
params.update({'parking_name': parking_name})
else:
raise Exception('parking_name is not assigned')
if free_duration:
params.update({'free_duration': free_duration})
else:
raise Exception('free_duration is not assigned')
if self._partner_mode:
if sub_mchid:
params.update({'sub_mchid': sub_mchid})
else:
raise Exception('sub_mchid is not assigned.')
path = '/v3/vehicle/parking/parkings'
return self._core.request(path, method=RequestType.POST, data=params)
def parking_order(self, description, out_trade_no, total, parking_id, plate_number, plate_color, start_time,
end_time, parking_name, charging_duration, device_id, trade_scene='PARKING', profit_sharing='N',
currency='CNY', attach=None, goods_tag=None, notify_url=None, appid=None, sub_appid=None, sub_mchid=None):
"""停车扣费受理
:param description: 服务描述,商户自定义字段,用于交易账单中对扣费服务的描述。示例值:'停车场扣费'
:param out_trade_no: 商户订单号,商户系统内部订单号,只能是数字、大小写字母,且在同一个商户号下唯一,示例值:'20150806125346'
:param notify_url: 回调通知url,只接受https,示例值:'https://yoursite.com/wxpay.html'
:param total: 订单总金额,单位为分,只能为整数,示例值:888
:param parking_id: 停车入场id,通过入场通知接口获取的入场id,示例值:'5K8264ILTKCH16CQ250'
:param plate_number: 车牌号,仅包括省份+车牌,不包括特殊字符。示例值:'粤B888888'
:param plate_color: 车牌颜色,枚举值:BLUE:蓝色,GREEN:绿色,YELLOW:黄色,BLACK:黑色,WHITE:白色,LIMEGREEN:黄绿色,示例值:BLUE
:param start_time: 入场时间,示例值:'2017-08-26T10:43:39+08:00'
:param end_time: 出场时间,示例值:'2017-08-26T10:43:39+08:00'
:param parking_name: 停车场名称,示例值:'欢乐海岸停车场'
:param charging_duration: 计费时长,单位为秒,示例值:3600
:param device_id: 停车场设备id,示例值:'12313'
:param trade_scene: 交易场景值,目前支持'PARKING':车场停车场景
:param profit_sharing: 分账标识,枚举值:'Y':是,需要分账,'N':否,不分账,字母要求大写,不传默认不分账。
:param currency: 货币类型,目前只支持人民币:'CNY'
:param attach: 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,示例值:'深圳分店'
:param goods_tag: 订单优惠标记,代金券或立减优惠功能的参数,示例值:WXG
:param appid: 应用ID,可不填,默认传入初始化时的appid,示例值:'wx1234567890abcdef'
:param sub_appid: (服务商模式)子商户应用ID,示例值:'wxd678efh567hg6999'
:param sub_mchid: (服务商模式)子商户的商户号,由微信支付生成并下发。示例值:'1900000109'
"""
params = {}
amount = {}
parking_info = {}
params.update({'appid': appid or self._appid})
if description:
params.update({'description': description})
else:
raise Exception('description is not assigned')
if out_trade_no:
params.update({'out_trade_no': out_trade_no})
else:
raise Exception('out_trade_no is not assigned')
params.update({'notify_url': notify_url or self._notify_url})
if total:
amount.update({'total': total})
else:
raise Exception('total is not assigned')
if parking_id:
parking_info.update({'parking_id': parking_id})
else:
raise Exception('parking_id is not assigned')
if plate_number:
parking_info.update({'plate_number': plate_number})
else:
raise Exception('plate_number is not assigned')
if plate_color:
parking_info.update({'plate_color': plate_color})
else:
raise Exception('plate_color is not assigned')
if start_time:
parking_info.update({'start_time': start_time})
else:
raise Exception('start_time is not assigned')
if end_time:
parking_info.update({'end_time': end_time})
else:
raise Exception('end_time is not assigned')
if parking_name:
parking_info.update({'parking_name': parking_name})
else:
raise Exception('parking_name is not assigned')
if charging_duration:
parking_info.update({'charging_duration': charging_duration})
else:
raise Exception('charging_duration is not assigned')
if device_id:
parking_info.update({'device_id': device_id})
else:
raise Exception('device_id is not assigned')
if trade_scene:
params.update({'trade_scene': trade_scene})
else:
raise Exception('trade_scene is not assigned')
if profit_sharing:
params.update({'profit_sharing': profit_sharing})
else:
raise Exception('profit_sharing is not assigned')
if currency:
amount.update({'currency': currency})
else:
raise Exception('currency is not assigned')
if attach:
params.update({'attach': attach})
if goods_tag:
params.update({'goods_tag': goods_tag})
params.update({'amount': amount})
params.update({'parking_info': parking_info})
if self._partner_mode:
if sub_appid:
params.update({'sub_appid': sub_appid})
else:
raise Exception('sub_appid is not assigned.')
if sub_mchid:
params.update({'sub_mchid': sub_mchid})
else:
raise Exception('sub_mchid is not assigned.')
path = '/v3/vehicle/transactions/parking'
return self._core.request(path, method=RequestType.POST, data=params)
def parking_order_query(self, out_trade_no, sub_mchid=None):
"""停车扣费订单查询
:param out_trade_no: 商户订单号,商户系统内部订单号,只能是数字、大小写字母,且在同一个商户号下唯一,示例值:'20150806125346'
:param sub_mchid: (服务商模式)子商户的商户号,由微信支付生成并下发。示例值:'1900000109'
"""
if out_trade_no:
path = '/v3/vehicle/transactions/out-trade-no/%s' % out_trade_no
else:
raise Exception('out_trade_no is not assigned')
if self._partner_mode:
if sub_mchid:
path = '%s?sub_mchid=%s' % (path, sub_mchid)
else:
raise Exception('sub_mchid is not assigned.')
return self._core.request(path)