diff --git a/weixin4j-mp/pom.xml b/weixin4j-mp/pom.xml index 2c9ef8f3..c7e9bea1 100644 --- a/weixin4j-mp/pom.xml +++ b/weixin4j-mp/pom.xml @@ -25,6 +25,13 @@ weixin4j-base ${project.version} + + + javax.xml.bind + jaxb-api + 2.2.11 + provided + junit junit diff --git a/weixin4j-pay/pom.xml b/weixin4j-pay/pom.xml index 34f28c52..629862b7 100644 --- a/weixin4j-pay/pom.xml +++ b/weixin4j-pay/pom.xml @@ -10,7 +10,7 @@ 4.0.0 weixin4j-pay weixin4j-pay - 1.0.1-SNAPSHOT + 1.1.0 https://github.com/foxinmy/weixin4j/tree/master/weixin4j-pay 微信支付商户平台API diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/PayPackageBuilder.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/PayPackageBuilder.java new file mode 100644 index 00000000..0b820600 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/PayPackageBuilder.java @@ -0,0 +1,246 @@ +package com.foxinmy.weixin4j.pay; + +import com.alibaba.fastjson.JSON; +import com.foxinmy.weixin4j.pay.payment.mch.MchPayPackage; +import com.foxinmy.weixin4j.pay.payment.mch.SceneInfo; +import com.foxinmy.weixin4j.pay.payment.mch.SceneInfoApp; +import com.foxinmy.weixin4j.pay.payment.mch.SceneInfoStore; +import com.foxinmy.weixin4j.pay.type.TradeType; + +import java.util.Date; + +/** + * MchPayPackage生成器 + * + * 微信支付中很多新增的支付产品或功能不定期的在原来各种支付API中添加参数项,导致MchPayPackage类会不断更新 + * MchPayPackage构造方法参数会越来越多,不断增加的参数项也不好继续改构造方法。 + * PayApi中一些特定的支付api(如JSAPI、MACROPAY)等都是直接传入参数,然后在API内构造MchPayPackage,而不是传入MchPayPackage, + * 一旦增加新参数就需要改API,影响正在使用SDK的工程,但如果改为直接使用MchPayPackag的createPayRequest方法, + * MchPayPackage的构造方式又太难看,开发者需要对着微信文档然后看着构造函数里边一大堆的参数一一匹配 + * 所以最终有了PayPackageBuilder这个类,通过一些链式的API构造MchPayPackage,既提供最小参数的各种支付构造方法,又能让代码看上去直观一些 + * + * @author kit (kit.li@qq.com) + * @date 2020年06月02日 + */ +public class PayPackageBuilder { + private static final String Y = "Y"; + private MchPayPackage mchPayPackage; + + private PayPackageBuilder(){ + } + + /** + * 使用MchPayPackage初始化 + * + * @param payPackage + * @return + */ + public static PayPackageBuilder init(MchPayPackage payPackage){ + PayPackageBuilder instance = new PayPackageBuilder(); + instance.mchPayPackage = payPackage; + return instance; + } + + /** + * 付款码支付/人脸支付 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户订单号 + * @param totalFee + * 支付金额 + * @param createIp + * 终端IP + * @param authCode + * 用户付款码 + * @return + */ + public static PayPackageBuilder microPay(String body, String outTradeNo, double totalFee, String createIp, + String authCode){ + PayPackageBuilder instance = new PayPackageBuilder(); + instance.mchPayPackage = new MchPayPackage(body, outTradeNo, totalFee, null, createIp, TradeType.MICROPAY, + null, authCode, null, null); + return instance; + } + + /** + * JSAPI支付/小程序支付 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户订单号 + * @param totalFee + * 支付金额 + * @param createIp + * 终端IP + * @param notifyUrl + * 回调通知地址 + * @param openid + * 用户标识 + * @return + */ + public static PayPackageBuilder jsapiPay(String body, String outTradeNo, double totalFee, String createIp, + String notifyUrl, String openid){ + PayPackageBuilder instance = new PayPackageBuilder(); + instance.mchPayPackage = new MchPayPackage(body, outTradeNo, totalFee, notifyUrl, createIp, TradeType.JSAPI, + openid, null, null, null); + return instance; + } + + /** + * native支付 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户订单号 + * @param totalFee + * 支付金额 + * @param createIp + * 终端IP + * @param notifyUrl + * 回调通知地址 + * @param productId + * 产品ID + * @return + */ + public static PayPackageBuilder nativePay(String body, String outTradeNo, double totalFee, String createIp, + String notifyUrl, String productId){ + PayPackageBuilder instance = new PayPackageBuilder(); + instance.mchPayPackage = new MchPayPackage(body, outTradeNo, totalFee, notifyUrl, createIp, TradeType.NATIVE, + null, null, productId, null); + return instance; + } + + /** + * APP支付 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户订单号 + * @param totalFee + * 支付金额 + * @param createIp + * 终端IP + * @param notifyUrl + * 回调通知地址 + * @return + */ + public static PayPackageBuilder appPay(String body, String outTradeNo, double totalFee, String createIp, String notifyUrl){ + PayPackageBuilder instance = new PayPackageBuilder(); + instance.mchPayPackage = new MchPayPackage(body, outTradeNo, totalFee, notifyUrl, createIp, TradeType.APP, + null, null, null, null); + return instance; + } + + /** + * H5支付 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户订单号 + * @param totalFee + * 支付金额 + * @param createIp + * 终端IP + * @param notifyUrl + * 回调通知地址 + * @param wapUrl + * wap网站URL地址 + * @param wapName + * wap网站名 + * @return + */ + public static PayPackageBuilder h5Pay(String body, String outTradeNo, double totalFee, String createIp, + String notifyUrl, String wapUrl, String wapName){ + PayPackageBuilder instance = new PayPackageBuilder(); + instance.mchPayPackage = new MchPayPackage(body, outTradeNo, totalFee, notifyUrl, createIp, TradeType.APP, + null, null, null, null); + SceneInfoApp app = SceneInfoApp.createWapAPP(wapName, wapUrl); + instance.mchPayPackage.setSceneInfo(String.format("{\"h5_info\":\"%s\"}", app.getSceneInfo())); + return instance; + } + + public PayPackageBuilder detail(String detail){ + this.mchPayPackage.setDetail(detail); + return this; + } + + public PayPackageBuilder attach(String attach){ + this.mchPayPackage.setAttach(attach); + return this; + } + + public PayPackageBuilder goodsTag(String goodsTag){ + this.mchPayPackage.setGoodsTag(goodsTag); + return this; + } + + public PayPackageBuilder limitPay(){ + this.mchPayPackage.setLimitPay("no_credit"); + return this; + } + + public PayPackageBuilder timeStart(Date date){ + this.mchPayPackage.setTimeStart(date); + return this; + } + + public PayPackageBuilder timeStart(String date){ + this.mchPayPackage.setTimeStart(date); + return this; + } + + public PayPackageBuilder timeExpire(Date date){ + this.mchPayPackage.setTimeExpire(date); + return this; + } + + public PayPackageBuilder timeExpire(String date){ + this.mchPayPackage.setTimeExpire(date); + return this; + } + + public PayPackageBuilder receipt(){ + this.mchPayPackage.setReceipt(Y); + return this; + } + + public PayPackageBuilder sceneInfo(SceneInfo info){ + this.mchPayPackage.setSceneInfo(info.toJson()); + return this; + } + + public PayPackageBuilder deposit(){ + this.mchPayPackage.setDeposit(Y); + return this; + } + + public PayPackageBuilder profitSharing(){ + this.mchPayPackage.setProfitSharing(Y); + return this; + } + + public PayPackageBuilder subOpenId(String subOpenId){ + this.mchPayPackage.setSubOpenId(subOpenId); + return this; + } + + public PayPackageBuilder totalFee(double totalFee){ + this.mchPayPackage.setTotalFee(totalFee); + return this; + } + + public PayPackageBuilder totalFee(int totalFee){ + this.mchPayPackage.setTotalFee(totalFee); + return this; + } + + public MchPayPackage build(){ + return this.mchPayPackage; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md index 1792dfa0..d3c46924 100644 --- a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/README.md @@ -1,47 +1,30 @@ 支付模块【JSAPI】【NATIVE】【MICROPAY】 -微信公众平台[V2版本支付](https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course2_tmpl&lang=zh_CN)文档 +目前只支持商户平台v2版本的支付API -微信公众平台[V3版本支付](https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course3_tmpl&lang=zh_CN)文档 - -**在`2014年10月9号`之前申请并审核通过的支付接口应该属于`V2版本`支付,而之后申请的接口则为`V3版本(商户平台)`支付** +**V3版在计划中,但目前因V3版针对的电商平台、微信支付分两类商户目前都是邀请制的,所以具体什么时候开展还未知。有能力的朋友可以帮忙贡献代码** -[WeixinPayProxy](WeixinPayProxy.java) +[WeixinPayProxy](https://github.com/foxinmy/weixin4j/blob/master/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java) ------------------------- - -* createPayJsRequestJson: 创建V3版本(商户平台)的JSAPI支付串 - -* createNativePayRequestURL: 创建V3版本(商户平台)的扫码支付链接 - -* createPrePay: 调用V3版本(商户平台)的统一订单接口生成预订单数据 - -* createMicroPay: 创建刷卡支付(商户平台)请求 - -* orderQuery: 订单查询接口 - -* refundOrder: 退款申请接口 - -* reverseOrder: 冲正订单接口 - -* closeOrder: 关闭订单接口 - -* downloadBill: 下载对账单接口 - -* refundQuery: 退款查询接口 +这是所有支付平台所有API的代理类,入参是一个WeixinPayAccount,建议调用API都通过代理类去调用,会相对简单些。 -[Pay2Api](https://github.com/foxinmy/weixin4j/blob/master/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/Pay2Api.java) + +[PayApi](https://github.com/foxinmy/weixin4j/blob/master/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java) ------------------------- +微信支付API -* createPayJsRequestJson: 创建V2版本的JSAPI支付串 +[CashApi](https://github.com/foxinmy/weixin4j/blob/master/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CashApi.java) +------------------------- +微信现金红包API -* createNativePayRequestURL: 创建V2版本的扫码支付链接 +[CouponApi](https://github.com/foxinmy/weixin4j/blob/master/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/CouponApi.java) +------------------------- +微信代金券API -* orderQuery: 订单查询接口 +[ProfitSharingApi](https://github.com/foxinmy/weixin4j/blob/master/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/ProfitSharingApi.java) +------------------------- +微信分帐API -* refundOrder: 退款申请接口 -* downloadBill: 下载对账单接口 - -* refundQuery: 退款查询接口 diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java index 563d62d4..7686b5ba 100644 --- a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/WeixinPayProxy.java @@ -10,10 +10,12 @@ import com.foxinmy.weixin4j.pay.payment.coupon.*; import com.foxinmy.weixin4j.pay.payment.face.PayfaceAuthinfo; import com.foxinmy.weixin4j.pay.payment.face.PayfaceAuthinfoRequest; import com.foxinmy.weixin4j.pay.payment.mch.*; +import com.foxinmy.weixin4j.pay.profitsharing.*; import com.foxinmy.weixin4j.pay.sign.WeixinSignature; import com.foxinmy.weixin4j.pay.type.*; import com.foxinmy.weixin4j.pay.type.mch.BillType; import com.foxinmy.weixin4j.pay.type.mch.RefundAccountType; +import com.foxinmy.weixin4j.pay.type.profitsharing.ReturnAccountType; import com.foxinmy.weixin4j.util.Consts; import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; @@ -53,6 +55,10 @@ public class WeixinPayProxy { * 商户信息 */ private final WeixinPayAccount weixinPayAccount; + /** + * 分帐接口 + */ + private final ProfitSharingApi profitSharingApi; /** * 微信支付接口实现(使用weixin4j.properties配置的account商户信息) @@ -78,6 +84,7 @@ public class WeixinPayProxy { this.couponApi = new CouponApi(weixinPayAccount); this.cashApi = new CashApi(weixinPayAccount); this.customsApi = new CustomsApi(weixinPayAccount); + this.profitSharingApi = new ProfitSharingApi(weixinPayAccount); } /** @@ -272,7 +279,7 @@ public class WeixinPayProxy { * @param attach * 附加数据 非必填 * @param store - * 门店信息 非必填 + * APP支付已无门店信息,不需要再传 * @return APP支付对象 * @see PayApi * @see SceneInfoStore @@ -359,41 +366,9 @@ public class WeixinPayProxy { totalFee, createIp, attach, store); } - /** - * 旧版刷脸支付接口 - * - * @param faceCode - * 人脸凭证 - * @param body - * 商品或支付单简要描述,格式要求:门店品牌名-城市分店名-实际商品名称 - * @param outTradeNo - * 商户系统内部的订单号,32个字符内、可包含字母;更换授权码必须要换新的商户订单号 - * @param totalFee - * 订单总金额,单位元 - * @param createIp - * 调用微信支付API的机器IP - * @param openId - * 用户在商户appid 下的唯一标识 - * @param attach - * 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 - * @return - * @throws WeixinException - * @see - * 刷脸支付后端接口 - * @see - */ - public MchPayRequest createFacePayRequest(String faceCode, String body, - String outTradeNo, double totalFee, String createIp, String openId, - String attach) throws WeixinException { - return payApi.createFacePayRequest(faceCode, body, outTradeNo, - totalFee, createIp, openId, attach); - } - /** * 押金支付请求 + * 注意:(此功能微信已下架,改为邀请开通,因此暂未使用) * * @param code * 授权码/人脸凭证 @@ -886,5 +861,142 @@ public class WeixinPayProxy { return payApi.getWxPayfaceAuthinfo(request); } + /** + * 添加分账接收方 + * 服务商代子商户发起添加分账接收方请求,后续可通过发起分账请求将结算后的钱分到该分账接收方。 + * + * @param receiver + * 分帐接收方 + * @return + * @throws WeixinException + * @see Receiver + * @see ReceiverResult + * @see 添加分账接收方 + * @since weixin4j-pay 1.1.0 + * + */ + public ReceiverResult addProfitSharingReceiver(Receiver receiver) throws WeixinException { + return profitSharingApi.addReceiver(receiver); + } + + /** + * 删除分账接收方 + * 商户发起删除分账接收方请求,删除后不支持将结算后的钱分到该分账接收方。 + * + * @param receiver + * 分帐接收方 + * @return + * @throws WeixinException + * @see Receiver + * @see ReceiverResult + * @see 删除分账接收方 + * @since weixin4j-pay 1.1.0 + */ + public ReceiverResult removeProfitSharingReceiver(Receiver receiver) throws WeixinException { + return profitSharingApi.removeReceiver(receiver); + } + + /** + * 请求分帐 + * + * @param transactionId + * 微信订单号 + * @param outOrderNo + * 商户分帐单号 + * @param receivers + * 分帐接收方列表 + * @param multi + * 是否多次分帐,默认为单次分帐,即调用分帐成功后马上解冻剩余金额给商户,不需要完结分帐。多次分帐可多次调用分帐API,需调完结分帐结束分帐 + * @return + * @throws WeixinException + * @see 请求单次分帐 + * @since weixin4j-pay 1.1.0 + */ + public ProfitSharingResult profitSharing(String transactionId, String outOrderNo, List receivers, + Boolean multi) throws WeixinException{ + return profitSharingApi.profitSharing(transactionId, outOrderNo, receivers, multi); + } + + /** + * 分帐查询 + * + * @param transactionId + * 微信订单号 + * @param outOrderNo + * 商户分帐单号 + * @return + * @throws WeixinException + * @see 分帐查询 + * @since weixin4j-pay 1.1.0 + */ + public ProfitSharingResult profitSharingQuery(String transactionId, String outOrderNo) throws WeixinException{ + return profitSharingApi.profitSharingQuery(transactionId, outOrderNo); + } + + /** + * 完结分账 + * 1、不需要进行分账的订单,可直接调用本接口将订单的金额全部解冻给本商户 + * 2、调用多次分账接口后,需要解冻剩余资金时,调用本接口将剩余的分账金额全部解冻给特约商户 + * 3、已调用请求单次分账后,剩余待分账金额为零,不需要再调用此接口。 + * + * @param transactionId + * 微信订单号 + * @param outOrderNo + * 商户分帐单号 + * @param description + * 分帐完结描述 + * @return + * @throws WeixinException + * @see 完结分账 + * @since weixin4j-pay 1.1.0 + */ + public ProfitSharingResult profitSharingFinish(String transactionId, String outOrderNo, String description) + throws WeixinException{ + return profitSharingApi.profitSharingFinish(transactionId, outOrderNo, description); + } + + /** + * 分账回退 + * + * @param id + * 分帐单号 + * @param outReturnNo + * 商户回退单号 + * @param returnAccountType + * 回退方类型 + * @param returnAccount + * 回退方账号 + * @param description + * 回退描述 + * @return + * @throws WeixinException + * @see ProfitSharingReturnRequest + * @see 分账回退 + * @since weixin4j-pay 1.1.0 + */ + public ProfitSharingReturnResult profitSharingReturn(ProfitId id, String outReturnNo, + ReturnAccountType returnAccountType, String returnAccount, + int returnAmount, String description) + throws WeixinException{ + return profitSharingApi.profitSharingReturn(id, outReturnNo, returnAccountType, returnAccount, returnAmount, + description); + } + + /** + * 回退结果查询 + * + * @param id + * 分帐单号 + * @param outReturnNo + * 商户回退单号 + * @return + * @throws WeixinException + * @see ProfitSharingReturnRequest + * @see 回退结果查询 + */ + public ProfitSharingReturnResult profitSharingReturnQuery(ProfitId id, String outReturnNo) throws WeixinException{ + return profitSharingApi.profitSharingReturnQuery(id, outReturnNo); + } + public final static String VERSION = Consts.VERSION; } diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java index 104efa19..10102c3f 100644 --- a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java @@ -35,7 +35,7 @@ public class MchApi extends BaseApi { private final static String PEM_CERT_PREFIX = "-----BEGIN CERTIFICATE-----"; static { - WEIXIN_BUNDLE = ResourceBundle.getBundle("com/foxinmy/weixin4j/payment/weixin"); + WEIXIN_BUNDLE = ResourceBundle.getBundle("com/foxinmy/weixin4j/pay/weixin"); } protected final WeixinPayAccount weixinAccount; diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java index 4ad38149..07f16308 100644 --- a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java @@ -10,7 +10,6 @@ import com.foxinmy.weixin4j.pay.payment.face.PayfaceAuthinfo; import com.foxinmy.weixin4j.pay.payment.face.PayfaceAuthinfoRequest; import com.foxinmy.weixin4j.pay.payment.mch.*; import com.foxinmy.weixin4j.pay.type.mch.BillType; -import com.foxinmy.weixin4j.pay.type.mch.DepositType; import com.foxinmy.weixin4j.pay.type.mch.RefundAccountType; import com.foxinmy.weixin4j.pay.type.*; import com.foxinmy.weixin4j.util.*; @@ -34,6 +33,8 @@ import java.util.Map; */ public class PayApi extends MchApi { + private final static String Y = "Y"; + public PayApi(WeixinPayAccount weixinAccount) { super(weixinAccount); } @@ -88,14 +89,14 @@ public class PayApi extends MchApi { null, payPackage.getCreateIp(), null, payPackage.getOpenId(), payPackage.getAuthCode(), null, payPackage.getAttach(), null, null, payPackage.getGoodsTag(), - payPackage.getLimitPay(), payPackage.getSubAppId(), payPackage.getFaceCode(), - payPackage.getDeposit()); + payPackage.getLimitPay(), payPackage.getSubAppId(), payPackage.getReceipt(), + payPackage.getDeposit(), payPackage.getProfitSharing()); // 默认为MD5签名 SignType signType= SignType.MD5; super.declareMerchant(_payPackage); // 默认为刷卡支付(付款码支付)的API地址 String url = getRequestUri("micropay_uri"); - if(payPackage.getDeposit()==DepositType.Y){ + if(Y.equals(payPackage.getDeposit())){ // 押金支付只支持HMAC-SHA256签名 signType = SignType.HMAC$SHA256; _payPackage.setSignType("HMAC-SHA256"); @@ -276,7 +277,7 @@ public class PayApi extends MchApi { * @param attach * 附加数据 非必填 * @param store - * 门店信息 非必填 + * APP支付已无门店信息,不需要再传 * @return APP支付对象 * @see SceneInfoStore * @see APPPayRequest @@ -291,11 +292,6 @@ public class PayApi extends MchApi { MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, totalFee, notifyUrl, createIp, TradeType.APP, null, null, null, attach); - if (store != null) { - payPackage.setSceneInfo(String.format( - "{\"store_id\": \"%s\", \"store_name\":\"%s\"}", - store.getId(), store.getName())); - } return createPayRequest(payPackage); } @@ -332,8 +328,7 @@ public class PayApi extends MchApi { totalFee, notifyUrl, createIp, TradeType.MWEB, null, null, null, attach); if (app != null) { - payPackage.setSceneInfo(String.format("{\"h5_info\":\"%s\"}", - app.getSceneInfo())); + payPackage.setSceneInfo(app.toJson()); } return createPayRequest(payPackage); } @@ -371,8 +366,7 @@ public class PayApi extends MchApi { totalFee, null, createIp, TradeType.MICROPAY, null, authCode, null, attach); if (store != null) { - payPackage.setSceneInfo(String.format("{\"store_info\":\"%s\"}", - JSON.toJSONString(store))); + payPackage.setSceneInfo(store.toJson()); } return createPayRequest(payPackage); } @@ -769,28 +763,22 @@ public class PayApi extends MchApi { } /** - * 微信旧版刷脸支付 + * 创建押金支付 * - * @param faceCode + * @param code * @param body * @param outTradeNo * @param totalFee * @param createIp * @param openId * @param attach + * @param store + * @param isFacePay * @return * @throws WeixinException + * @see 支付押金(付款码支付) + * @see 支付押金(人脸支付) */ - public MchPayRequest createFacePayRequest(String faceCode, String body, - String outTradeNo, double totalFee, String createIp, String openId, - String attach) throws WeixinException { - MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, - totalFee, null, createIp, TradeType.FACEPAY, openId, null, - null, attach); - payPackage.setFaceCode(faceCode); - return createPayRequest(payPackage); - } - public MchPayRequest createDepositPayRequest(String code, String body, String outTradeNo, double totalFee, String createIp, String openId, String attach, SceneInfoStore store, boolean isFacePay) throws WeixinException { @@ -798,16 +786,15 @@ public class PayApi extends MchApi { if(isFacePay) { payPackage = new MchPayPackage(body, outTradeNo, totalFee, null, createIp, TradeType.FACEPAY, openId, null, null, attach); - payPackage.setFaceCode(code); - payPackage.setDeposit(DepositType.Y); + payPackage.setAuthCode(code); + payPackage.setDeposit(Y); return createPayRequest(payPackage); }else{ payPackage = new MchPayPackage(body, outTradeNo, totalFee, null, createIp, TradeType.MICROPAY, openId, code, null, attach); - payPackage.setDeposit(DepositType.Y); + payPackage.setDeposit(Y); if (store != null) { - payPackage.setSceneInfo(String.format("{\"store_info\":\"%s\"}", - JSON.toJSONString(store))); + payPackage.setSceneInfo(store.toJson()); } return createPayRequest(payPackage); } diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/ProfitSharingApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/ProfitSharingApi.java new file mode 100644 index 00000000..b1882b91 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/ProfitSharingApi.java @@ -0,0 +1,216 @@ +package com.foxinmy.weixin4j.pay.api; + +import com.alibaba.fastjson.TypeReference; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.profitsharing.*; +import com.foxinmy.weixin4j.pay.type.ProfitIdType; +import com.foxinmy.weixin4j.pay.type.SignType; +import com.foxinmy.weixin4j.pay.type.profitsharing.ReturnAccountType; +import com.foxinmy.weixin4j.util.RandomUtil; +import com.foxinmy.weixin4j.xml.XmlStream; + +import java.util.List; + +/** + * 微信商户平台分账接口(直连商户/服务商) + * + * @author kit (kit.li@qq.com) + * @date 2020年05月20日 + * @since weixin4j-pay 1.1.0 + */ +public class ProfitSharingApi extends MchApi { + + public ProfitSharingApi(WeixinPayAccount weixinAccount) { + super(weixinAccount); + } + + /** + * 添加分账接收方 + * 服务商代子商户发起添加分账接收方请求,后续可通过发起分账请求将结算后的钱分到该分账接收方。 + * + * @param receiver + * 分帐接收方 + * @return + * @see Receiver + * @see ReceiverResult + * @see 添加分账接收方 + * + */ + public ReceiverResult addReceiver(Receiver receiver) throws WeixinException { + ReceiverRequest receiverRequest = new ReceiverRequest(receiver); + super.declareMerchant(receiverRequest); + String url = getRequestUri("profit_sharing_add_receiver_uri"); + receiverRequest.setSign(weixinSignature.sign(receiverRequest, SignType.HMAC$SHA256)); + String para = XmlStream.toXML(receiverRequest); + WeixinResponse response = weixinExecutor.post(url, para); + return response.getAsObject(new TypeReference(){}); + } + + /** + * 删除分账接收方 + * 商户发起删除分账接收方请求,删除后不支持将结算后的钱分到该分账接收方。 + * + * @param receiver + * 分帐接收方 + * @return + * @throws WeixinException + * @see Receiver + * @see ReceiverResult + * @see 删除分账接收方 + */ + public ReceiverResult removeReceiver(Receiver receiver) throws WeixinException { + ReceiverRequest receiverRequest = new ReceiverRequest(receiver); + super.declareMerchant(receiverRequest); + String url = getRequestUri("profit_sharing_remove_receiver_uri"); + receiverRequest.setSign(weixinSignature.sign(receiverRequest, SignType.HMAC$SHA256)); + String para = XmlStream.toXML(receiverRequest); + WeixinResponse response = weixinExecutor.post(url, para); + return response.getAsObject(new TypeReference(){}); + } + + /** + * 请求分帐 + * + * @param transactionId + * 微信订单号 + * @param outOrderNo + * 商户分帐单号 + * @param receivers + * 分帐接收方 + * @param multi + * 是否多次分帐,默认为单次分帐,即调用分帐成功后马上解冻剩余金额给商户,不需要完结分帐。多次分帐可多次调用分帐API,需调完结分帐结束分帐 + * @return + * @throws WeixinException + * @see 请求单次分帐 + */ + public ProfitSharingResult profitSharing(String transactionId, String outOrderNo, List receivers, + Boolean multi) throws WeixinException { + ProfitSharingRequest request = new ProfitSharingRequest(transactionId, outOrderNo, receivers); + super.declareMerchant(request); + String url = multi==null || multi.booleanValue()==false ? getRequestUri("profit_sharing_uri") : + getRequestUri("multi_profit_sharing_uri"); + request.setSign(weixinSignature.sign(request, SignType.HMAC$SHA256)); + String para = XmlStream.toXML(request); + WeixinResponse response = getWeixinSSLExecutor().post(url, para); + return response.getAsObject(new TypeReference(){}); + } + + /** + * 分帐查询 + * + * @param transactionId + * 微信订单号 + * @param outOrderNo + * 商户分帐单号 + * @return + * @throws WeixinException + * @see 分帐查询 + */ + public ProfitSharingResult profitSharingQuery(String transactionId, String outOrderNo) throws WeixinException { + ProfitSharingRequest request = new ProfitSharingRequest(transactionId, outOrderNo, null); + request.setMchId(weixinAccount.getMchId()); + request.setNonceStr(RandomUtil.generateString(16)); + request.setSubMchId(weixinAccount.getSubMchId()); + String url = getRequestUri("profit_sharing_query_uri"); + request.setSign(weixinSignature.sign(request, SignType.HMAC$SHA256)); + String para = XmlStream.toXML(request); + WeixinResponse response = weixinExecutor.post(url, para); + return response.getAsObject(new TypeReference(){}); + } + + /** + * 完结分账 + * 1、不需要进行分账的订单,可直接调用本接口将订单的金额全部解冻给本商户 + * 2、调用多次分账接口后,需要解冻剩余资金时,调用本接口将剩余的分账金额全部解冻给特约商户 + * 3、已调用请求单次分账后,剩余待分账金额为零,不需要再调用此接口。 + * + * @param transactionId + * 微信订单号 + * @param outOrderNo + * 商户分帐单号 + * @param description + * 分帐完结描述 + * @return + * @throws WeixinException + * @see 完结分账 + */ + public ProfitSharingResult profitSharingFinish(String transactionId, String outOrderNo, String description) + throws WeixinException { + ProfitSharingRequest request = new ProfitSharingRequest(transactionId, outOrderNo, null); + request.setDescription(description); + super.declareMerchant(request); + String url = getRequestUri("profit_sharing_finish_uri"); + request.setSign(weixinSignature.sign(request, SignType.HMAC$SHA256)); + String para = XmlStream.toXML(request); + WeixinResponse response = getWeixinSSLExecutor().post(url, para); + return response.getAsObject(new TypeReference(){}); + } + + /** + * 分账回退 + * + * @param id + * 分帐单号 + * @param outReturnNo + * 商户回退单号 + * @param returnAccountType + * 回退方类型 + * @param returnAccount + * 回退方账号 + * @param returnAmount + * 回退金额 + * @param description + * 回退描述 + * @return + * @throws WeixinException + * @see ProfitSharingReturnRequest + * @see 分账回退 + */ + public ProfitSharingReturnResult profitSharingReturn(ProfitId id, String outReturnNo, + ReturnAccountType returnAccountType, String returnAccount, + int returnAmount, String description) throws WeixinException{ + ProfitSharingReturnRequest request; + if(id.getIdType()== ProfitIdType.ORDER_ID){ + request = new ProfitSharingReturnRequest(id.getId(), null, outReturnNo, returnAccountType, + returnAccount, returnAmount, description); + }else{ + request = new ProfitSharingReturnRequest(null, id.getId(), outReturnNo, returnAccountType, + returnAccount, returnAmount, description); + } + super.declareMerchant(request); + String url = getRequestUri("profit_sharing_return_uri"); + request.setSign(weixinSignature.sign(request, SignType.HMAC$SHA256)); + String para = XmlStream.toXML(request); + WeixinResponse response = getWeixinSSLExecutor().post(url, para); + return response.getAsObject(new TypeReference(){}); + } + + /** + * 回退结果查询 + * + * @param id + * 分帐单号 + * @param outReturnNo + * 商户回退单号 + * @return + * @throws WeixinException + * @see ProfitSharingReturnRequest + * @see 回退结果查询 + */ + public ProfitSharingReturnResult profitSharingReturnQuery(ProfitId id, String outReturnNo) throws WeixinException{ + ProfitSharingReturnRequest request; + if(id.getIdType()== ProfitIdType.ORDER_ID){ + request = new ProfitSharingReturnRequest(id.getId(), null, outReturnNo); + }else{ + request = new ProfitSharingReturnRequest(null, id.getId(), outReturnNo); + } + super.declareMerchant(request); + String url = getRequestUri("profit_sharing_return_query_uri"); + request.setSign(weixinSignature.sign(request, SignType.HMAC$SHA256)); + String para = XmlStream.toXML(request); + WeixinResponse response = weixinExecutor.post(url, para); + return response.getAsObject(new TypeReference(){}); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java index e081b23c..6feabea7 100644 --- a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java @@ -4,7 +4,6 @@ import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.pay.payment.PayPackage; import com.foxinmy.weixin4j.pay.type.CurrencyType; import com.foxinmy.weixin4j.pay.type.TradeType; -import com.foxinmy.weixin4j.pay.type.mch.DepositType; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -77,18 +76,23 @@ public class MchPayPackage extends PayPackage { @XmlElement(name = "scene_info") @JSONField(name = "scene_info") private String sceneInfo; + /** - * 人脸凭证,用于旧版人脸支付。 + * 电子发票入口开放标识 */ - @XmlElement(name = "face_code") - @JSONField(name = "face_code") - private String faceCode; + private String receipt; /** * 是否押金人脸支付,Y-是,N-普通人脸支付 */ - @XmlElement(name = "deposit") - @JSONField(name = "deposit") - private DepositType deposit; + private String deposit; + + /** + * 是否需要分帐,非必传,默认为不分帐 + * Y-是,需要分账,N-否,不分账 + */ + @XmlElement(name = "profit_sharing") + @JSONField(name = "profit_sharing") + private String profitSharing; protected MchPayPackage() { // jaxb required @@ -123,7 +127,7 @@ public class MchPayPackage extends PayPackage { String openId, String authCode, String productId, String attach) { this(body, null, outTradeNo, totalFee, CurrencyType.CNY, notifyUrl, createIp, tradeType, openId, authCode, productId, attach, null, - null, null, null, null, null, null); + null, null, null, null, null, null, null); } /** @@ -164,29 +168,31 @@ public class MchPayPackage extends PayPackage { * @param subOpenId * 用户在子商户appid下的唯一标识 非必填 * openid和sub_openid可以选传其中之一,如果选择传sub_openid ,则必须传sub_appid - * @param faceCode - * 人脸凭证,用于旧版刷脸支付。 - * @param depositType + * @param receipt + * 电子发票入口开放标识 + * @param deposit * 是否押金支付 + * @param profitSharing + * 是否需要分账 */ public MchPayPackage(String body, String detial, String outTradeNo, double totalFee, CurrencyType feeType, String notifyUrl, String createIp, TradeType tradeType, String openId, String authCode, String productId, String attach, Date timeStart, - Date timeExpire, String goodsTag, String limitPay, String subOpenId, String faceCode, - DepositType depositType) { + Date timeExpire, String goodsTag, String limitPay, String subOpenId, String receipt, + String deposit, String profitSharing) { super(body, detial, outTradeNo, totalFee, notifyUrl, createIp, attach, timeStart, timeExpire, goodsTag); this.tradeType = tradeType != null ? tradeType.name() : null; - this.feeType = feeType == null ? CurrencyType.CNY.name() : feeType - .name(); + this.feeType = feeType == null ? CurrencyType.CNY.name() : feeType.name(); this.openId = openId; this.authCode = authCode; this.productId = productId; this.limitPay = limitPay; this.subOpenId = subOpenId; - this.faceCode = faceCode; - this.deposit = depositType; + this.receipt = receipt; + this.deposit = deposit; + this.profitSharing = profitSharing; } public String getTradeType() { @@ -253,22 +259,30 @@ public class MchPayPackage extends PayPackage { this.sceneInfo = sceneInfo; } - public String getFaceCode() { - return faceCode; + public String getReceipt() { + return receipt; } - public void setFaceCode(String faceCode) { - this.faceCode = faceCode; + public void setReceipt(String receipt) { + this.receipt = receipt; } - public DepositType getDeposit() { + public String getDeposit() { return deposit; } - public void setDeposit(DepositType deposit) { + public void setDeposit(String deposit) { this.deposit = deposit; } + public String getProfitSharing() { + return profitSharing; + } + + public void setProfitSharing(String profitSharing) { + this.profitSharing = profitSharing; + } + @Override public String toString() { return "MchPayPackage{" + @@ -280,8 +294,9 @@ public class MchPayPackage extends PayPackage { ", limitPay='" + limitPay + '\'' + ", subOpenId='" + subOpenId + '\'' + ", sceneInfo='" + sceneInfo + '\'' + - ", faceCode='" + faceCode + '\'' + + ", receipt='" + receipt + '\'' + ", deposit=" + deposit + + ", profitSharing=" + profitSharing + '}'; } } diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfo.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfo.java new file mode 100644 index 00000000..0af0c6d5 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfo.java @@ -0,0 +1,16 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +/** + * 支付场景信息接口 + * + * @author kit + * @date 2020年06月03日 + */ +public interface SceneInfo { + /** + * 格式化为Json字符串 + * + * @return + */ + String toJson(); +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java index 7c708e5f..9523b7f0 100644 --- a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java @@ -1,24 +1,34 @@ package com.foxinmy.weixin4j.pay.payment.mch; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) -public class SceneInfoApp { +public class SceneInfoApp implements SceneInfo { /** * 终端类型 */ private String type; /** - * 应用名称 + * WAP 网站名 */ + @XmlElement(name = "wap_name") + @JSONField(name = "wap_name") private String name; /** - * 应用路径 + * WAP网站URL地址 */ + @XmlElement(name = "wap_url") + @JSONField(name = "wap_url") private String path; + + @JSONField(serialize = false) private String sceneInfo; protected SceneInfoApp(){ @@ -55,21 +65,25 @@ public class SceneInfoApp { this.path = path; } + @Deprecated public String getSceneInfo() { return sceneInfo; } - + @Deprecated public void setSceneInfo(String sceneInfo) { this.sceneInfo = sceneInfo; } /** * IOS应用 + * APP环境直接使用APP支付,此方法将作废 * * @param appName 应用名 * @param bundleId 模块ID * @return + * @deprecated */ + @Deprecated public static SceneInfoApp createIOSAPP(String appName, String bundleId) { SceneInfoApp app = new SceneInfoApp("IOS", appName, bundleId); String sceneInfo = String @@ -81,11 +95,14 @@ public class SceneInfoApp { /** * Android应用 + * APP环境直接使用APP支付,此方法将作废 * * @param appName 应用名 * @param packageName 包名 * @return + * @deprecated */ + @Deprecated public static SceneInfoApp createAndroidAPP(String appName, String packageName) { SceneInfoApp app = new SceneInfoApp("Android", appName, packageName); String sceneInfo = String @@ -112,4 +129,9 @@ public class SceneInfoApp { app.setSceneInfo(sceneInfo); return app; } + + @Override + public String toJson() { + return String.format("{\"h5_info\": %s}", JSON.toJSONString(this)); + } } diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java index 550e9edd..bf7921f4 100644 --- a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java @@ -1,5 +1,6 @@ package com.foxinmy.weixin4j.pay.payment.mch; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.annotation.JSONField; import javax.xml.bind.annotation.XmlAccessType; @@ -9,7 +10,7 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) -public class SceneInfoStore { +public class SceneInfoStore implements SceneInfo { /** * SZTX001 门店唯一标识 */ @@ -67,9 +68,22 @@ public class SceneInfoStore { this.name = name; } + public SceneInfoStore(String id, String name, String areaCode, String address) { + super(); + this.id = id; + this.name = name; + this.areaCode = areaCode; + this.address = address; + } + @Override public String toString() { return "SceneInfoStore [id=" + id + ", name=" + name + ", areaCode=" + areaCode + ", address=" + address + "]"; } + + @Override + public String toJson() { + return String.format("{\"store_info\": %s}", JSON.toJSONString(this)); + } } \ No newline at end of file diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitId.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitId.java new file mode 100644 index 00000000..55379450 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitId.java @@ -0,0 +1,36 @@ +package com.foxinmy.weixin4j.pay.profitsharing; + +import com.foxinmy.weixin4j.pay.type.ProfitIdType; + +/** + * 分帐单单号 + * + * @author kit + * @date 2020年05月25日 + * @since weixin4j-pay 1.1.0 + */ +public class ProfitId { + private String id; + private ProfitIdType idType; + + public ProfitId(String id, ProfitIdType type){ + this.id = id; + this.idType = type; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public ProfitIdType getIdType() { + return idType; + } + + public void setIdType(ProfitIdType idType) { + this.idType = idType; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingRequest.java new file mode 100644 index 00000000..22c2be35 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingRequest.java @@ -0,0 +1,87 @@ +package com.foxinmy.weixin4j.pay.profitsharing; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; + +import javax.xml.bind.annotation.XmlElement; +import java.util.List; + +/** + * 单次分帐的请求内容 + * + * @author kit(kit.li@qq.com) + * @date 2020年5月25日 + * @since weixin4j-pay 1.1.0 + */ +public class ProfitSharingRequest extends MerchantResult { + /** + * 只支持HMAC-SHA256 + */ + @XmlElement(name = "sign_type") + @JSONField(name = "sign_type") + private final String signType = "HMAC-SHA256"; + /** + * 微信支付订单号 + */ + @XmlElement(name = "transaction_id") + @JSONField(name = "transaction_id") + private String transactionId; + /** + * 商户订单号 + */ + @XmlElement(name = "out_order_no") + @JSONField(name = "out_order_no") + private String outOrderNo; + /** + * 分账接收方列表,不超过50个 + */ + private String receivers; + /** + * 分账完结描述 + */ + private String description; + + public ProfitSharingRequest(String transactionId, String outOrderNo, List receivers){ + this.transactionId = transactionId; + this.outOrderNo = outOrderNo; + this.receivers = receivers!=null && receivers.size()>0 ? JSON.toJSONString(receivers) : null; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public String getOutOrderNo() { + return outOrderNo; + } + + public void setOutOrderNo(String outOrderNo) { + this.outOrderNo = outOrderNo; + } + + public String getReceivers() { + return receivers; + } + + public void setReceivers(String receivers) { + this.receivers = receivers; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String getSignType() { + return signType; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingResult.java new file mode 100644 index 00000000..0f2bc0b4 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingResult.java @@ -0,0 +1,134 @@ +package com.foxinmy.weixin4j.pay.profitsharing; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; + +import javax.xml.bind.annotation.XmlElement; +import java.util.List; + +/** + * 单次分帐返回结果 + * + * @author kit + * @date 2020年05月25日 + * @since weixin4j-pay 1.1.0 + */ +public class ProfitSharingResult extends MerchantResult { + /** + * 微信支付订单号 + */ + @XmlElement(name = "transaction_id") + @JSONField(name = "transaction_id") + private String transactionId; + /** + * 商户订单号 + */ + @XmlElement(name = "out_trade_no") + @JSONField(name = "out_trade_no") + private String outOrderNo; + /** + * 微信分帐单号 + */ + @XmlElement(name = "order_id") + @JSONField(name = "order_id") + private String orderId; + /** + * 分账单状态(分帐查询) + * ACCEPTED—受理成功 + * PROCESSING—处理中 + * FINISHED—处理完成 + * CLOSED—处理失败,已关单 + */ + private String status; + /** + * 关单原因(分帐查询),非必传,默认值:NO_AUTH----分账授权已解除 + */ + @XmlElement(name = "close_reason") + @JSONField(name = "close_reason") + private String closeReason; + /** + * 分账接收方列表(分帐查询) + */ + @JSONField(serialize = false) + private String receivers; + /** + * 分账金额(分帐查询) + * 分账完结的分账金额,单位为分, 仅当查询分账完结的执行结果时,存在本字段 + */ + private Integer amount; + /** + * 分帐描述(分帐查询) + * 分账完结的原因描述,仅当查询分账完结的执行结果时,存在本字段 + */ + private String description; + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public String getOutOrderNo() { + return outOrderNo; + } + + public void setOutOrderNo(String outOrderNo) { + this.outOrderNo = outOrderNo; + } + + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCloseReason() { + return closeReason; + } + + public void setCloseReason(String closeReason) { + this.closeReason = closeReason; + } + + public String getReceivers() { + return receivers; + } + + public void setReceivers(String receivers) { + this.receivers = receivers; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @JSONField(name = "receivers") + public List getProfitResult(){ + return JSON.parseArray(this.receivers, ReceiverProfitResult.class); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingReturnRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingReturnRequest.java new file mode 100644 index 00000000..9fab9edc --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingReturnRequest.java @@ -0,0 +1,169 @@ +package com.foxinmy.weixin4j.pay.profitsharing; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; +import com.foxinmy.weixin4j.pay.type.profitsharing.ReturnAccountType; + +import javax.xml.bind.annotation.XmlElement; + +/** + * 分帐回退API请求内容 + * + * @author kit (kit.li@qq.com) + * @date 2020年05月25日 + * @since weixin4j-pay 1.1.0 + */ +public class ProfitSharingReturnRequest extends MerchantResult { + /** + * 只支持HMAC-SHA256 + */ + @XmlElement(name = "sign_type") + @JSONField(name = "sign_type") + private final String signType = "HMAC-SHA256"; + /** + * 微信分帐单号 + * 原发起分账请求时,微信返回的微信分账单号,与商户分账单号一一对应。微信分账单号与商户分账单号二选一填写 + */ + private String orderId; + /** + * 商户订单号 + * 原发起分账请求时使用的商户系统内部的分账单号。微信分账单号与商户分账单号二选一填写 + */ + @XmlElement(name = "out_trade_no") + @JSONField(name = "out_trade_no") + private String outOrderNo; + /** + * 商户回退单号 + */ + @XmlElement(name = "out_return_no") + @JSONField(name = "out_return_no") + private String outReturnNo; + /** + * 回退方类型 + */ + @XmlElement(name = "return_account_type") + @JSONField(name = "return_account_type") + private ReturnAccountType returnAccountType = ReturnAccountType.MERCHANT_ID; + /** + * 回退方账号 + * 当回退方类型为商户ID时,填写商户ID + */ + @XmlElement(name = "return_account") + @JSONField(name = "return_account") + private String returnAccount; + /** + * 回退金额 + */ + @XmlElement(name = "return_amount") + @JSONField(name = "return_amount") + private int returnAmount; + /** + * 回退描述 + */ + private String description; + + /** + * 用于回退查询的参数构造方法 + * + * @param orderId + * 微信分帐单号 + * @param outOrderNo + * 商户分帐单号 + * @param outReturnNo + * 商户回退单号 + */ + public ProfitSharingReturnRequest(String orderId, String outOrderNo, String outReturnNo) { + this.orderId = orderId; + this.outOrderNo = outOrderNo; + this.outReturnNo = outReturnNo; + } + + /** + * 用于回退请求的参数构造方法 + * + * @param orderId + * 微信分帐单号 + * @param outOrderNo + * 商户分帐单号 + * @param outReturnNo + * 商户回退单号 + * @param returnAccountType + * 回退方类型 + * @param returnAccount + * 回退方帐号 + * @param description + * 回退描述 + */ + public ProfitSharingReturnRequest(String orderId, String outOrderNo, String outReturnNo, + ReturnAccountType returnAccountType, String returnAccount, + int returnAmount, String description) { + this.orderId = orderId; + this.outOrderNo = outOrderNo; + this.outReturnNo = outReturnNo; + this.returnAccountType = returnAccountType; + this.returnAccount = returnAccount; + this.returnAmount = returnAmount; + this.description = description; + } + + @Override + public String getSignType() { + return signType; + } + + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public String getOutOrderNo() { + return outOrderNo; + } + + public void setOutOrderNo(String outOrderNo) { + this.outOrderNo = outOrderNo; + } + + public String getOutReturnNo() { + return outReturnNo; + } + + public void setOutReturnNo(String outReturnNo) { + this.outReturnNo = outReturnNo; + } + + public ReturnAccountType getReturnAccountType() { + return returnAccountType; + } + + public void setReturnAccountType(ReturnAccountType returnAccountType) { + this.returnAccountType = returnAccountType; + } + + public String getReturnAccount() { + return returnAccount; + } + + public void setReturnAccount(String returnAccount) { + this.returnAccount = returnAccount; + } + + public int getReturnAmount() { + return returnAmount; + } + + public void setReturnAmount(int returnAmount) { + this.returnAmount = returnAmount; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingReturnResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingReturnResult.java new file mode 100644 index 00000000..22c7da6a --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ProfitSharingReturnResult.java @@ -0,0 +1,167 @@ +package com.foxinmy.weixin4j.pay.profitsharing; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; +import com.foxinmy.weixin4j.pay.type.profitsharing.ReturnAccountType; + +import javax.xml.bind.annotation.XmlElement; + +/** + * 分帐回退/回退查询返回内容 + * + * @author kit(kit.li@qq.com) + * @date 2020年05年25日 + * @since weixin4j-pay 1.1.0 + */ +public class ProfitSharingReturnResult extends MerchantResult { + /** + * 微信分账单号 + */ + @XmlElement(name = "order_id") + @JSONField(name = "order_id") + private String orderId; + /** + * 商户分账单号 + */ + @XmlElement(name = "out_order_no") + @JSONField(name = "out_order_no") + private String outOrderNo; + /** + * 商户回退单号 + */ + @XmlElement(name = "out_return_no") + @JSONField(name = "out_return_no") + private String outReturnNo; + /** + * 微信回退单号 + */ + @XmlElement(name = "return_no") + @JSONField(name = "return_no") + private String returnNo; + /** + * 回退方类型 + */ + @XmlElement(name = "return_account_type") + @JSONField(name = "return_account_type") + private ReturnAccountType returnAccountType; + /** + * 回退方账号 + */ + @XmlElement(name = "return_account") + @JSONField(name = "return_account") + private String returnAccount; + /** + * 回退金额 + */ + @XmlElement(name = "return_amount") + @JSONField(name = "return_amount") + private Integer returnAmount; + /** + * 回退描述 + */ + private String description; + /** + * 回退结果 + */ + private String result; + /** + * 失败原因 + */ + @XmlElement(name = "fail_reason") + @JSONField(name = "fail_reason") + private String failReason; + /** + * 完成时间 + */ + @XmlElement(name = "finish_time") + @JSONField(name = "finish_time") + private String finishTime; + + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public String getOutOrderNo() { + return outOrderNo; + } + + public void setOutOrderNo(String outOrderNo) { + this.outOrderNo = outOrderNo; + } + + public String getOutReturnNo() { + return outReturnNo; + } + + public void setOutReturnNo(String outReturnNo) { + this.outReturnNo = outReturnNo; + } + + public String getReturnNo() { + return returnNo; + } + + public void setReturnNo(String returnNo) { + this.returnNo = returnNo; + } + + public ReturnAccountType getReturnAccountType() { + return returnAccountType; + } + + public void setReturnAccountType(ReturnAccountType returnAccountType) { + this.returnAccountType = returnAccountType; + } + + public String getReturnAccount() { + return returnAccount; + } + + public void setReturnAccount(String returnAccount) { + this.returnAccount = returnAccount; + } + + public Integer getReturnAmount() { + return returnAmount; + } + + public void setReturnAmount(Integer returnAmount) { + this.returnAmount = returnAmount; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public String getFailReason() { + return failReason; + } + + public void setFailReason(String failReason) { + this.failReason = failReason; + } + + public String getFinishTime() { + return finishTime; + } + + public void setFinishTime(String finishTime) { + this.finishTime = finishTime; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/Receiver.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/Receiver.java new file mode 100644 index 00000000..64086769 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/Receiver.java @@ -0,0 +1,105 @@ +package com.foxinmy.weixin4j.pay.profitsharing; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.type.profitsharing.ReceiverType; +import com.foxinmy.weixin4j.pay.type.profitsharing.RelationType; + +/** + * 分账接收方基础信息 + * 用于添加或删除分帐接收方时使用 + * + * @author kit(kit_21cn@21cn.com) + * @date 2020年05月20日 + * @since weixin4j-pay 1.1.0 + */ +public class Receiver { + + public Receiver(){} + + public Receiver(ReceiverType type, String account, RelationType relationType) { + this.type = type; + this.account = account; + this.relationType = relationType; + } + + public Receiver(ReceiverType type, String account, String name, RelationType relationType, String customRelation) { + this.type = type; + this.account = account; + this.name = name; + this.relationType = relationType; + this.customRelation = customRelation; + } + + /** + * 分账接收方类型 + */ + private ReceiverType type; + /** + * 分账接收方帐号 + * 类型是MERCHANT_ID时,是商户ID + * 类型是PERSONAL_WECHATID时,是个人微信号 + * 类型是PERSONAL_OPENID时,是个人openid + * 类型是PERSONAL_SUB_OPENID时,是个人sub_openid + */ + private String account; + /** + * 分账接收方全称 + * 分账接收方类型是MERCHANT_ID时,是商户全称(必传) + * 分账接收方类型是PERSONAL_WECHATID 时,是个人姓名(必传) + * 分账接收方类型是PERSONAL_OPENID时,是个人姓名(选传,传则校验) + * 分账接收方类型是PERSONAL_SUB_OPENID时,是个人姓名(选传,传则校验) + */ + private String name; + /** + * 与分账方的关系类型 + */ + @JSONField(name = "relation_type") + private RelationType relationType; + /** + * 自定义的分账关系 + * 子商户与接收方具体的关系,本字段最多10个字。 + * 当字段relation_type的值为CUSTOM时,本字段必填 + */ + @JSONField(name = "custom_relation") + private String customRelation; + + public ReceiverType getType() { + return type; + } + + public void setType(ReceiverType type) { + this.type = type; + } + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public RelationType getRelationType() { + return relationType; + } + + public void setRelationType(RelationType relationType) { + this.relationType = relationType; + } + + public String getCustomRelation() { + return customRelation; + } + + public void setCustomRelation(String customRelation) { + this.customRelation = customRelation; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverProfit.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverProfit.java new file mode 100644 index 00000000..1304c979 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverProfit.java @@ -0,0 +1,44 @@ +package com.foxinmy.weixin4j.pay.profitsharing; + +import com.foxinmy.weixin4j.pay.type.profitsharing.ReceiverType; + +/** + * 请求分帐时使用的分帐方信息 + * + * @author kit(kit.li@qq.com) + * @date 2020年05月25日 + * @since weixin4j-pay 1.1.0 + */ +public class ReceiverProfit extends Receiver { + private int amount; + private String description; + + /** + * json deserialize need + */ + public ReceiverProfit(){ + super(); + } + + public ReceiverProfit(ReceiverType type, String account, int amount, String description){ + super(type, account, null); + this.amount = amount; + this.description = description; + } + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverProfitResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverProfitResult.java new file mode 100644 index 00000000..944f2d2d --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverProfitResult.java @@ -0,0 +1,63 @@ +package com.foxinmy.weixin4j.pay.profitsharing; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.type.profitsharing.ReceiverType; + +import javax.xml.bind.annotation.XmlElement; + +/** + * 分帐方添加删除API调用结果 + * + * @author kit (kit.li@qq.com) + * @date 2020年05月25日 + * @since weixin4j-pay 1.1.0 + */ +public class ReceiverProfitResult extends ReceiverProfit { + /** + * 分帐结果: + * PENDING:待分账 + * SUCCESS:分账成功 + * ADJUST:分账失败待调账 + * RETURNED:已转回分账方 + * CLOSED: 已关闭 + */ + private String result; + /** + * 分账完成时间 + */ + @XmlElement(name = "finish_time") + @JSONField(name = "finish_time") + private String finishTime; + @XmlElement(name = "fail_reason") + @JSONField(name = "fail_reason") + private String failReason; + + public ReceiverProfitResult(ReceiverType type, String account, int amount, String description, String result){ + super(type, account, amount, description); + this.result = result; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public String getFinishTime() { + return finishTime; + } + + public void setFinishTime(String finishTime) { + this.finishTime = finishTime; + } + + public String getFailReason() { + return failReason; + } + + public void setFailReason(String failReason) { + this.failReason = failReason; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverRequest.java new file mode 100644 index 00000000..f052f038 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverRequest.java @@ -0,0 +1,41 @@ +package com.foxinmy.weixin4j.pay.profitsharing; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; + +import javax.xml.bind.annotation.XmlElement; + +/** + * 分帐方添加及删除的API请求 + * + * @author kit (kit.li@qq.com) + * @date 2020年05月20日 + * @since weixin4j-pay 1.1.0 + */ +public class ReceiverRequest extends MerchantResult { + + @XmlElement(name = "sign_type") + @JSONField(name = "sign_type") + private final String signType = "HMAC-SHA256"; + + public ReceiverRequest(Receiver receiver){ + super(); + this.receiver = JSON.toJSONString(receiver); + } + + private String receiver; + + public String getReceiver() { + return this.receiver; + } + + public void setReceiver(String receiver) { + this.receiver = receiver; + } + + @Override + public String getSignType() { + return signType; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverResult.java new file mode 100644 index 00000000..764a4871 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/profitsharing/ReceiverResult.java @@ -0,0 +1,41 @@ +package com.foxinmy.weixin4j.pay.profitsharing; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; + +/** + * 微信支付-服务商分帐接口-分帐接收方API返回结果 + * + * @author kit(kit_21cn@21cn.com) + * @className ProfitSharingReceiverResult + * @date 2020年05月20日 + * @since weixin4j-pay 1.1.0 + */ +public class ReceiverResult extends MerchantResult { + /** + * 分账接收方对象,json格式字符串 + */ + @JSONField(serialize = false) + private String receiver; + + public String getReceiver() { + return receiver; + } + + public void setReceiver(String receiver) { + this.receiver = receiver; + } + + /** + * 返回接收方java对象 + */ + @JSONField(name = "receiver") + public Receiver getReceiverObject(){ + try { + return JSON.parseObject(receiver, Receiver.class); + } catch (Exception e) { + return null; + } + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/ProfitIdType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/ProfitIdType.java new file mode 100644 index 00000000..55ad96ee --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/ProfitIdType.java @@ -0,0 +1,19 @@ +package com.foxinmy.weixin4j.pay.type; + +/** + * 分帐单号类型 + * + * @author kit (kit.li@qq.com) + * @date 2020年05月25日 + * @since weixin4j-pay 1.1.0 + */ +public enum ProfitIdType { + /** + * 微信分帐单号 + */ + ORDER_ID, + /** + * 商户分帐单号 + */ + OUT_ORDER_NO +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/DepositType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/DepositType.java deleted file mode 100644 index 08524415..00000000 --- a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/DepositType.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.foxinmy.weixin4j.pay.type.mch; - -/** - * 是否押金支付 - * - * @className DepositType - * @author kit(kit_21cn@21cn.com) - * @date 2019年9月21日 - * @since JDK 1.6 - */ -public enum DepositType { - /** - * 是 - */ - Y, - /** - * 否 - */ - N; -} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/profitsharing/ReceiverType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/profitsharing/ReceiverType.java new file mode 100644 index 00000000..29dd6d3f --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/profitsharing/ReceiverType.java @@ -0,0 +1,27 @@ +package com.foxinmy.weixin4j.pay.type.profitsharing; + +/** + * 分帐接收方类型 + * + * @author kit (kit.li@qq.com) + * @date 2020年05月20日 + * @since weixin4j-pay 1.1.0 + */ +public enum ReceiverType { + /** + * 商户ID + */ + MERCHANT_ID, + /** + * 个人微信号 + */ + PERSONAL_WECHATID, + /** + * 个人微信openid + */ + PERSONAL_OPENID, + /** + * 个人微信sub_openid (对应服务商API的子商户sub_appid转换得到) + */ + PERSONAL_SUB_OPENID; +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/profitsharing/RelationType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/profitsharing/RelationType.java new file mode 100644 index 00000000..90d197be --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/profitsharing/RelationType.java @@ -0,0 +1,55 @@ +package com.foxinmy.weixin4j.pay.type.profitsharing; + +/** + * 子商户与接收方的关系 + * + * @author kit (kit.li@qq.com) + * @date 2020年05月20日 + * @since weixin4j-pay 1.1.0 + */ +public enum RelationType { + /** + * 服务商 + */ + SERVICE_PROVIDER, + /** + * 门店 + */ + STORE, + /** + * 员工 + */ + STAFF, + /** + * 店主 + */ + STORE_OWNER, + /** + * 合作伙伴 + */ + PARTNER, + /** + * 总部 + */ + HEADQUARTER, + /** + * 品牌方 + */ + BRAND, + /** + * 分销商 + */ + DISTRIBUTOR, + /** + * 用户 + */ + USER, + /** + * 供应商 + */ + SUPPLIER, + /** + * 自定义 + */ + CUSTOM; +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/profitsharing/ReturnAccountType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/profitsharing/ReturnAccountType.java new file mode 100644 index 00000000..37b0492e --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/profitsharing/ReturnAccountType.java @@ -0,0 +1,16 @@ +package com.foxinmy.weixin4j.pay.type.profitsharing; + +/** + * 分帐回退的回退方类型 + * + * @author kit + * @date 2020年05月25日 + * @since weixin4j-pay 1.1.0 + */ +public enum ReturnAccountType { + /** + * 商户ID + * 目前仅支付商户接收方的回退 + */ + MERCHANT_ID +} diff --git a/weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties b/weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/pay/weixin.properties similarity index 75% rename from weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties rename to weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/pay/weixin.properties index 635bb53b..d92e56e4 100644 --- a/weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/payment/weixin.properties +++ b/weixin4j-pay/src/main/resources/com/foxinmy/weixin4j/pay/weixin.properties @@ -61,4 +61,20 @@ facepay_url={mch_base_url}/pay/facepay # \u652F\u4ED8\u62BC\u91D1\uFF08\u4EBA\u8138\uFF09 deposit_facepay_uri={mch_base_url}/deposit/facepay # \u652F\u4ED8\u62BC\u91D1\uFF08\u4ED8\u6B3E\u7801\uFF09 -deposit_micropay_uri={mch_base_url}/deposit/micropay \ No newline at end of file +deposit_micropay_uri={mch_base_url}/deposit/micropay +# \u670D\u52A1\u5546\u5206\u5E10\u63A5\u53E3--\u6DFB\u52A0\u5206\u8D26\u63A5\u6536\u65B9 +profit_sharing_add_receiver_uri={mch_base_url}/pay/profitsharingaddreceiver +# \u670D\u52A1\u5546\u5206\u5E10\u63A5\u53E3--\u5220\u9664\u5206\u8D26\u63A5\u6536\u65B9 +profit_sharing_remove_receiver_uri={mch_base_url}/pay/profitsharingremovereceiver +# \u8BF7\u6C42\u5355\u6B21\u5206\u5E10 +profit_sharing_uri={mch_base_url}/secapi/pay/profitsharing +# \u8BF7\u6C42\u591A\u6B21\u5206\u5E10 +multi_profit_sharing_uri={mch_base_url}/secapi/pay/multiprofitsharing +# \u67E5\u8BE2\u5206\u8D26\u7ED3\u679C +profit_sharing_query_uri={mch_base_url}/pay/profitsharingquery +# \u5206\u5E10\u5B8C\u7ED3 +profit_sharing_finish_uri={mch_base_url}/secapi/pay/profitsharingfinish +# \u5206\u5E10\u56DE\u9000 +profit_sharing_return_uri={mch_base_url}/secapi/pay/profitsharingreturn +# \u5206\u5E10\u56DE\u9000\u67E5\u8BE2 +profit_sharing_return_query_uri={mch_base_url}/pay/profitsharingreturnquery diff --git a/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/PayApiExample.java b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/PayApiExample.java new file mode 100644 index 00000000..0d51164b --- /dev/null +++ b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/PayApiExample.java @@ -0,0 +1,37 @@ +package com.foxinmy.weixin4j.pay.test; + +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.pay.PayPackageBuilder; +import com.foxinmy.weixin4j.pay.WeixinPayProxy; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.mch.MICROPayRequest; +import com.foxinmy.weixin4j.pay.payment.mch.MchPayPackage; +import com.foxinmy.weixin4j.pay.payment.mch.MchPayRequest; +import org.junit.Assert; +import org.junit.Test; + +/** + * 一个支付例子 + * + * @author kit (kit.li@qq.com) + */ +public class PayApiExample { + + /** + * 这是一个付款码支付的例子 + * + * @throws WeixinException + */ + @Test + public void testPay() throws WeixinException { + WeixinPayAccount payAccount = new WeixinPayAccount("你的appid", "支付密钥", "商户号"); + MchPayPackage payPackage = PayPackageBuilder.microPay("body内容", "商户订单号", 1.00D, "127.0.0.1", + "你的付款码") + .attach("这是一个测试") + .limitPay() + .build(); + WeixinPayProxy proxy = new WeixinPayProxy(payAccount); + MICROPayRequest r = (MICROPayRequest) proxy.createPayRequest(payPackage); + Assert.assertEquals(r.getResultCode(), "SUCCESS"); + } +} diff --git a/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestFacePay.java b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestFacePay.java deleted file mode 100644 index 8b3145c1..00000000 --- a/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestFacePay.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.foxinmy.weixin4j.pay.test; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.foxinmy.weixin4j.exception.WeixinException; -import com.foxinmy.weixin4j.pay.WeixinPayProxy; -import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; -import com.foxinmy.weixin4j.pay.payment.mch.MchPayRequest; -import com.foxinmy.weixin4j.pay.type.mch.DepositType; -import org.junit.Test; - -public class TestFacePay { - @Test - public void test() throws WeixinException { - String appid = ""; - String mchid = ""; - String paySignKey = ""; - WeixinPayAccount payAccount = new WeixinPayAccount(appid, paySignKey, mchid); - WeixinPayProxy proxy = new WeixinPayProxy(payAccount); - - String orderNo = "TESTORDER2019092001"; - String openId = "oguJRswolIOGg7Vd1VaqGJuDBFAE"; - String faceCode = "0f879a6c-5fff-421c-a233-5fac0f4aad12"; - - MchPayRequest rsp = proxy.createFacePayRequest(faceCode, "测试的人脸支付", - orderNo, 1, - "127.0.0.1", openId, null); - - JSONObject obj = (JSONObject) JSON.toJSON(rsp); - } -} \ No newline at end of file diff --git a/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestProfitSharingApi.java b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestProfitSharingApi.java new file mode 100644 index 00000000..4136cd97 --- /dev/null +++ b/weixin4j-pay/src/test/java/com/foxinmy/weixin4j/pay/test/TestProfitSharingApi.java @@ -0,0 +1,69 @@ +package com.foxinmy.weixin4j.pay.test; + +import com.alibaba.fastjson.JSON; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.pay.WeixinPayProxy; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.profitsharing.*; +import com.foxinmy.weixin4j.pay.type.profitsharing.ReceiverType; +import com.foxinmy.weixin4j.pay.type.profitsharing.RelationType; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +public class TestProfitSharingApi { + // 微信公众号appid + private static String APPID = ""; + // 微信支付商户密钥 + private static String PAY_SIGN_KEY = ""; + // 商户号 + private static String MCHID = ""; + // + private static String OPENID = ""; + + /** + * 测试添加分帐方 + */ + @Test + public void testAddReceiver() throws WeixinException { + Receiver receiver = new Receiver(ReceiverType.PERSONAL_OPENID, OPENID, RelationType.STAFF); + WeixinPayAccount account = new WeixinPayAccount(APPID, PAY_SIGN_KEY, MCHID); + WeixinPayProxy proxy = new WeixinPayProxy(account); + ReceiverResult result = proxy.addProfitSharingReceiver(receiver); + System.out.println(JSON.toJSONString(result)); + Assert.assertEquals(result.getReturnCode(), "SUCCESS"); + } + + /** + * 测试删除分帐方 + */ + @Test + public void testRemoveReceiver() throws WeixinException { + Receiver receiver = new Receiver(ReceiverType.PERSONAL_OPENID, OPENID, null); + WeixinPayAccount account = new WeixinPayAccount(APPID, PAY_SIGN_KEY, MCHID); + WeixinPayProxy proxy = new WeixinPayProxy(account); + ReceiverResult result = proxy.removeProfitSharingReceiver(receiver); + System.out.println(JSON.toJSONString(result)); + Assert.assertEquals(result.getReturnCode(), "SUCCESS"); + } + + /** + * 单次分帐 + * + * @throws WeixinException + */ + @Test + public void testProfitSharing() throws WeixinException { + ReceiverProfit receiverProfit = new ReceiverProfit(ReceiverType.MERCHANT_ID, "", 1, "test"); + List list = new ArrayList(); + list.add(receiverProfit); + WeixinPayAccount account = new WeixinPayAccount(APPID, PAY_SIGN_KEY, MCHID); + WeixinPayProxy proxy = new WeixinPayProxy(account); + ProfitSharingResult result = proxy.profitSharing("transactioId", "outOrderNo", list, false); + System.out.println(JSON.toJSONString(result)); + Assert.assertEquals(result.getReturnCode(), "SUCCESS"); + } + +} diff --git a/weixin4j-server/pom.xml b/weixin4j-server/pom.xml index b67857f1..19878129 100644 --- a/weixin4j-server/pom.xml +++ b/weixin4j-server/pom.xml @@ -29,6 +29,13 @@ fastjson ${fastjson.version} + + + javax.xml.bind + jaxb-api + 2.2.11 + provided + junit junit diff --git a/weixin4j-serverX/pom.xml b/weixin4j-serverX/pom.xml index 7b924bb5..58dab73b 100644 --- a/weixin4j-serverX/pom.xml +++ b/weixin4j-serverX/pom.xml @@ -26,6 +26,18 @@ spring-webmvc ${spring.version} + + + javax.xml.bind + jaxb-api + 2.2.11 + provided + + + javax.annotation + javax.annotation-api + 1.3.2 + javax.servlet servlet-api