# -*- coding: utf-8 -*- # !/usr/bin/env python import logging from typing import TYPE_CHECKING from apilib.utils_string import cn from apps.web.user.conf import PAY_NOTIFY_URL from apps.web.utils import testcase_point from library.alipay import AliPayServiceException from apps.web.core import AlipayMixin from library.alipay import AliPayGatewayException, AliErrorCode, AliException from apilib.monetary import quantize from apilib.monetary import RMB from apps.web.core.payment.base import PaymentGateway, WithdrawGateway from apps.web.core.models import BankCard logger = logging.getLogger(__name__) if TYPE_CHECKING: from apps.web.core.models import AliApp class AliPayGateway(PaymentGateway, AlipayMixin): """ Alipay 支付网关,扩展原库没有的接口 ``alipay.trade.create`` """ @property def notifyUrl(self): return PAY_NOTIFY_URL.ALI_PAY_BACK def __init__(self, app): # type: (AliApp)->None super(AliPayGateway, self).__init__(app) def __repr__(self): return '' % (self.appid, self.debug) def api_trade_query(self, out_trade_no = None, trade_no = None): assert out_trade_no or trade_no, 'must input out_trade_no or trade_no' result = self.client.api_alipay_trade_query(out_trade_no = out_trade_no, trade_no = trade_no) if result['code'] == u'10000': return result elif result['code'] == u'40004': raise AliPayServiceException(errCode = result['sub_code'], errMsg = result['sub_msg'], client = self) else: raise AliPayGatewayException(errCode = result['sub_code'], errMsg = result['sub_msg'], client = self) def unified_order(self, out_trade_no, openId, money, subject, notifyUrl, **kwargs): total_amount = quantize(money.amount) if total_amount != money.amount: raise AliException( errCode=AliErrorCode.MY_INVALID_PARAMETER, errMsg=u'无效的交易金额', client=self.client ) extras = { "buyer_id": openId, "timeout_express": kwargs.pop("timeout_express", '2m'), "body": kwargs.pop('body', '') } kwargs.update(extras) return self.client.api_alipay_trade_create( out_trade_no=out_trade_no, total_amount=str(total_amount), subject=subject, notify_url=notifyUrl, **kwargs ) def alipay_trade_precreate(self, out_trade_no, money, subject, buyer_id, timeout_express = '2m', body = '', **kwargs): """ 当面付的预下单 :param out_trade_no: :param money: :param subject: :param buyer_id: :param timeout_express: :param body: :param kwargs: :return: """ total_amount = str(quantize(money.amount, places = '0.01')) return self.client.api_alipay_trade_precreate(out_trade_no = out_trade_no, total_amount = total_amount, subject = subject, **{"buyer_id": buyer_id, "timeout_express": timeout_express, "body": body}) def api_alipay_trade_create(self, out_trade_no, money, subject, buyer_id, notify_url, timeout_express = '2m', body = '', **kwargs): # type:(str, RMB, basestring, str, str, str, str, dict)->dict """ 手机扫码创建订单 :param body: :param timeout_express: 订单关闭超时时间 :param out_trade_no: 因需要保存到rechargeRecord里,所以需要在方法外生成 :param money: 交易数额 [0.01,100000000] :param subject: 标题: 支付宝充值1元 :param buyer_id: 正在扫码准备充值的用户 :param kwargs: :return: """ total_amount = quantize(money.amount, places = '0.01') if total_amount != money.amount: raise AliException( errCode = AliErrorCode.MY_INVALID_PARAMETER, errMsg = u'无效的交易金额', client = self.client) extras = { "buyer_id": buyer_id, "timeout_express": timeout_express, "body": body } extras.update(**kwargs) logger.debug('alipay kwargs = {}'.format(extras)) logger.debug('alipay kwargs2,out_trade_no=%s,total_amount=%s,subject=%s,notify_url=%s' % ( out_trade_no, str(total_amount), subject, notify_url)) return self.client.api_alipay_trade_create(out_trade_no = out_trade_no, total_amount = str(total_amount), subject = subject, notify_url = notify_url, **extras) @testcase_point() def refund_to_user(self, out_trade_no, out_refund_no, refund_fee, total_fee, refund_reason, **kwargs): """ :param out_trade_no: :param out_refund_no: :param refund_fee: :param total_fee: :param refund_reason: :return: """ return self.client.api_alipay_trade_refund(out_trade_no = out_trade_no, out_request_no = out_refund_no, refund_amount = str(refund_fee), refund_reason = refund_reason) def download_bill(self, bill_type = 'trade', bill_date = None): """ 下载支付宝订单用于对账 """ return self.client.api_alipay_data_dataservice_bill_downloadurl_query(bill_type=bill_type, bill_date=bill_date) def api_refund_query(self, trade_no, out_trade_no, out_request_no): return self.client.api_alipay_trade_refund_order_query(trade_no, out_trade_no, out_request_no, ["gmt_refund_pay"]) class AliPayWithdrawGateway(WithdrawGateway, AlipayMixin): def __init__(self, app, is_ledger = True): # type: (AliApp, bool)->None super(AliPayWithdrawGateway, self).__init__(app, is_ledger) def __repr__(self): return '' % (self.appid, self.debug) def withdraw_via_bank(self, order_no, total_amount, bank_card, order_title = u'提现到银行卡'): # type:(str, RMB, BankCard, str)->dict """ 经销商提现通过银行卡提现 .. 参考文档 https://opendocs.alipay.com/open/common/transfertocard :param total_amount: :param order_no: 商户企业付款单号(本平台订单号) len(order_no) (- [8-32] :return: """ payee_info = { 'identity': bank_card.cardNo, 'identity_type': 'BANKCARD_ACCOUNT', 'name': cn(bank_card.holderName) } if bank_card.accountType == BankCard.AccountType.PUBLIC: payee_info['bankcard_ext_info'] = { 'inst_name': cn(bank_card.bankName), 'account_type': 1 } if bank_card.cnapsCode: payee_info['bankcard_ext_info'].update({ 'bank_code': bank_card.cnapsCode }) else: payee_info['bankcard_ext_info'].update({ 'inst_province': cn(bank_card.province), 'inst_city': cn(bank_card.city), 'inst_branch_name': cn(bank_card.branchName) }) else: payee_info['bankcard_ext_info'] = { 'account_type': 2 } result = self.client.api_alipay_fund_trans_uni_transfer( out_biz_no = order_no, trans_amount = str(total_amount), payee_info = payee_info, order_title = order_title) if result['code'] == u'10000': return result elif result['code'] == u'40004': raise AliPayServiceException(errCode = result['sub_code'], errMsg = result['sub_msg'], client = self) else: raise AliPayGatewayException(errCode = result['sub_code'], errMsg = result['sub_msg'], client = self) def get_transfer_result_via_bank(self, order_no): """ 查询银行卡提现的返回结果 :return: """ result = self.client.api_alipay_fund_trans_common_query(out_biz_no = order_no) if result['code'] == u'10000': return result elif result['code'] == u'40004': raise AliPayServiceException(errCode = result['sub_code'], errMsg = result['sub_msg'], client = self) else: raise AliPayGatewayException(errCode = result['sub_code'], errMsg = result['sub_msg'], client = self)