订单支付-签约支付

一、 订单支付数据库

1.1 订单支付数据库

订单支付的数据库:订单表,交易订单表,交易渠道,退款记录,签约合同表。

数据库如下:

1.2 防止订单多次支付

订单在进行支付过程中可能会发生失败,会记录每一次支付情况;这样查询就有所依据,用户在什么时间支付,支付结果如何。

//用户有可能会多次点击而导致创建多个支付订单,而支付多次的情况,所以需要对当前需要支付的订单进行加 分布式锁;

实现步骤:

复制代码
    //1 获取当前要创建支付订单的订单编号。
    //2 获取分布式锁对象。
    //3 对订单编号添加分布式锁。
    //4 进行统一下单操作,创建交易订单并返回交易订单信息。
    //5 释放分布式锁。否则会出现 出现死锁,无法创建交易订单,进行订单处理。

分布式锁原理:

在并发竞争共享资源的时候,想要对资源正确处理。如果不加分布式锁会出现 超卖 现象。

应用场景:

商品下单扣减库存、消息队列(避免重复处理)、此项目中避免重复支付、优惠券。

Redis分布式锁的实现主要依赖于Redis的SETNX(SET IF NOT EXISTS)命令和过期时间(EXPIRE)机制,或者通过SET命令的扩展参数(SET EX PX NX)来实现。

1.3 退款流程

  • 1.生成退款请求:通过微信支付提供的退款接口,构造退款请求。请求中需包含商户号、商户订单号、微信支付订单号、退款金额、退款原因等必要参数。
  • 2.加密签名:使用商户API密钥对退款请求参数进行签名。
  • 3.发送退款请求:将加密签名后的退款请求通过OkHttp以 POST方式发送给微信支付服务器。
  • 4.微信支付处理:微信支付平台进行退款操作,并更新订单状态。
  • 5.接收退款结果通知:退款操作完成后,微信支付会通过商户设置的通知URL,向商户服务器发送退款结果通知。通知中包含退款状态、退款成功与否、退款金额等信息。商户再更新订单和释放库存。

二、 签约支付

签约支付产品典型场景:会员包月、租赁费用,定期还款。

包括两种形式:独立签约后扣款、支付并签约。

1)独立签约后扣款:

用户首先在独立签约页面进行签约,待签约生效后,商家可以按照协议中的时间进行扣款。

开发文档:https://opendocs.alipay.com/open/00a05b

独立签约时序图:

用户签约时序图:

请求参数:

json 复制代码
bizContent={
    "product_code":"CYCLE_PAY_AUTH",//周期扣款场景固定为 CYCLE_PAY_AUTH
    "personal_product_code":"CYCLE_PAY_AUTH_P",//周期扣款产品时必传签约其它产品时无需传入
    "sign_scene":"INDUSTRY|CARRENTAL",//签约场景
    "external_agreement_no":"dk20220712102811111",//商户签约号
    "sign_validity_period":"2m",//当前用户签约请求的协议有效周期
    "access_params":{//接入渠道
        "channel":"ALIPAYAPP"
    },
    "period_rule_params":{//周期管控规则
        "period_type":"DAY",//周期类型枚举值为DAY和MONTH
        "period":"9",//周期数
        "execute_time":"2022-07-13",//商户发起首次扣款的时间
        "single_amount":"0.01",//每次发起扣款时限制的最大金额单位为元
        "total_amount":"0.02",//周期内允许扣款的总金额,单位为元
        "total_payments":"2"//总扣款次数
    },
    "identity_params":{// 非必填,用户实名信息参数
        "user_name":"\u5f20\u4e09",
        "cert_no":"61102619921108888",
        "identity_hash":"ac8c238bc68fca1c35933db1efa1d79accc014db5dc42fb3a43c421d47c2dbfa",
        "sign_user_id":"2088202888530893","sign_open_id":"031_DfFvT0Ufzk1852BLPnhuSWiztu4NqbkO35ylXPow-Y6"
    }
}

请求代码:

java 复制代码
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2");
AlipayUserAgreementPageSignRequest request = new AlipayUserAgreementPageSignRequest();
request.setBizContent(参考上面bizContent值示例);
request.setNotifyUrl("https://www.notifyURL.com");//设置异步通知地址
request.setReturnUrl("https://www.returnURL.com");//签约完成跳转地址
// 若想获取跳转链接使用pageExecute GET方式转换二维码可使用 alipayClient.pageExecute(request,"get")
// 周期扣款场景使用小程序/h5 接口跳转至签约页面时请使用 alipayClient.sdkExecute
AlipayUserAgreementPageSignResponse response = alipayClient.sdkExecute(request);

签约成功后会进行第一次支付。 周期性支付采用任务调度框架实现。

签约成功后续支付流程图:

签约成功后续支付代码:

java 复制代码
package com.java.sdk.demo;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.domain.PayParams;
import com.alipay.api.domain.PromoParam;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.domain.GoodsDetail;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.domain.AgreementParams;

import com.alipay.api.FileItem;
import java.util.Base64;
import java.util.ArrayList;
import java.util.List;

public class AlipayTradePay {

    public static void main(String[] args) throws AlipayApiException {
        // 初始化SDK
        AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());

        // 构造请求参数以调用接口
        AlipayTradePayRequest request = new AlipayTradePayRequest();
        AlipayTradePayModel model = new AlipayTradePayModel();
        
        // 设置商户订单号
        model.setOutTradeNo("20150320010101001");
        
        // 设置订单总金额
        model.setTotalAmount("88.88");
        
        // 设置订单标题
        model.setSubject("Iphone6 16G");
        
        // 设置产品码
        model.setProductCode("CYCLE_PAY_AUTH");
        
        // 设置代扣信息
        AgreementParams agreementParams = new AgreementParams();
        agreementParams.setAgreementNo("20170322450983769228");
        agreementParams.setApplyToken("MDEDUCT0068292ca377d1d44b65fa24ec9cd89132f");
        agreementParams.setAuthConfirmNo("423979");
        model.setAgreementParams(agreementParams);
        
        // 设置卖家支付宝用户ID
        model.setSellerId("2088102146225135");
        
        // 设置订单包含的商品列表信息
        List<GoodsDetail> goodsDetail = new ArrayList<GoodsDetail>();
        GoodsDetail goodsDetail0 = new GoodsDetail();
        goodsDetail0.setGoodsName("ipad");
        goodsDetail0.setQuantity(1L);
        goodsDetail0.setPrice("2000");
        goodsDetail0.setGoodsId("apple-01");
        goodsDetail0.setGoodsCategory("34543238");
        goodsDetail0.setCategoriesTree("124868003|126232002|126252004");
        goodsDetail0.setShowUrl("http://www.alipay.com/xxx.jpg");
        goodsDetail.add(goodsDetail0);
        model.setGoodsDetail(goodsDetail);
        
        // 设置业务扩展参数
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId("2088511833207846");
        extendParams.setSpecifiedSellerName("XXX的跨境小铺");
        extendParams.setCardType("S0JP0000");
        model.setExtendParams(extendParams);
        
        // 设置优惠明细参数
        PromoParam promoParams = new PromoParam();
        promoParams.setActualOrderTime("2018-09-25 22:47:33");
        model.setPromoParams(promoParams);
        
        // 设置支付相关参数
        PayParams payParams = new PayParams();
        payParams.setAsyncType("NORMAL_ASYNC");
        model.setPayParams(payParams);
        
        // 设置返回参数选项
        List<String> queryOptions = new ArrayList<String>();
        queryOptions.add("voucher_detail_list");
        model.setQueryOptions(queryOptions);
        
        request.setBizModel(model);
        // 第三方代调用模式下请设置app_auth_token
        // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->");

        AlipayTradePayResponse response = alipayClient.execute(request);
        System.out.println(response.getBody());

        if (response.isSuccess()) {
            System.out.println("调用成功");
        } else {
            System.out.println("调用失败");
            // sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
            // String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
            // System.out.println(diagnosisUrl);
        }
    }

    private static AlipayConfig getAlipayConfig() {
        String privateKey  = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->";
        String alipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->";
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
        alipayConfig.setAppId("<-- 请填写您的AppId,例如:2019091767145019 -->");
        alipayConfig.setPrivateKey(privateKey);
        alipayConfig.setFormat("json");
        alipayConfig.setAlipayPublicKey(alipayPublicKey);
        alipayConfig.setCharset("UTF-8");
        alipayConfig.setSignType("RSA2");
        return alipayConfig;
      }
}    

2)支付并签约

用户在支付流程中,同时完成支付和签约。待签约生效后,商家可以按照协议中的时间进行扣款。

开发文档:https://opendocs.alipay.com/open/041bxs

签约支付时序图:

三、支付结果同步

3.1 支付回调地址

  • 更新交易订单状态(交易微服务)。
  • 发送MQ消息。
    1)更新订单的状态。
    2)更新合同的状态。
相关推荐
青茶36022 天前
支付宝支付 报错 invalid [default store dir]: /tmp/
支付·支付宝
Tancenter2 个月前
支付宝小程序的用户登录/注册流程
小程序·登录·注册·支付宝
支付宝体验科技4 个月前
支付宝闪退治理:混合渲染场景下的 “no surface” 崩溃分析
支付宝
睡不着的可乐5 个月前
uniapp 支付宝小程序 扩展组件 component 节点的class不生效
前端·微信小程序·支付宝
xw55 个月前
uni-app项目支付宝端Input不受控
前端·uni-app·支付宝
闲人编程5 个月前
Flask 前后端分离架构实现支付宝电脑网站支付功能
python·架构·flask·支付宝·前后端·网站支付·apl
xw56 个月前
uni-app支付宝端彻底禁掉下拉刷新效果
前端·支付宝
xw56 个月前
支付宝小程序IDE突然极不稳定
前端·支付宝
悟空码字7 个月前
支付宝,让AI智能体更方便支付
aigc·agent·支付宝