diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxCombinePayService.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxCombinePayService.java new file mode 100644 index 0000000..4c99699 --- /dev/null +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxCombinePayService.java @@ -0,0 +1,159 @@ +package com.egzosn.pay.wx.v3.api; + +import java.util.LinkedHashMap; +import java.util.Map; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.egzosn.pay.common.bean.CloseOrder; +import com.egzosn.pay.common.bean.Order; +import com.egzosn.pay.common.bean.OrderParaStructure; +import com.egzosn.pay.common.bean.PayMessage; +import com.egzosn.pay.common.bean.PayOrder; +import com.egzosn.pay.common.bean.result.PayException; +import com.egzosn.pay.common.exception.PayErrorException; +import com.egzosn.pay.common.http.HttpConfigStorage; +import com.egzosn.pay.common.util.DateUtils; +import com.egzosn.pay.common.util.MapGen; +import com.egzosn.pay.common.util.str.StringUtils; +import com.egzosn.pay.wx.v3.bean.WxTransactionType; +import com.egzosn.pay.wx.v3.bean.combine.CombinePayMessage; +import com.egzosn.pay.wx.v3.utils.WxConst; + +/** + * 微信合单支付服务 + * + * @author egan + *
+ * email egzosn@gmail.com
+ * date 2016-5-18 14:09:01
+ * 
+ */ +public class WxCombinePayService extends WxPayService { + + /** + * 创建支付服务 + * + * @param payConfigStorage 微信对应的支付配置 + */ + public WxCombinePayService(WxPayConfigStorage payConfigStorage) { + super(payConfigStorage); + } + + /** + * 创建支付服务 + * + * @param payConfigStorage 微信对应的支付配置 + * @param configStorage 微信对应的网络配置,包含代理配置、ssl证书配置 + */ + public WxCombinePayService(WxPayConfigStorage payConfigStorage, HttpConfigStorage configStorage) { + super(payConfigStorage, configStorage); + } + + + /** + * 获取公共参数 + * + * @return 公共参数 + */ + public Map getPublicParameters() { + Map parameters = new LinkedHashMap<>(); + parameters.put(WxConst.COMBINE_APPID, payConfigStorage.getAppId()); + parameters.put(WxConst.COMBINE_MCH_ID, payConfigStorage.getMchId()); + return parameters; + } + + /** + * 初始化通知URL必须为直接可访问的URL,不允许携带查询串,要求必须为https地址。 + * + * @param parameters 订单参数 + * @param order 订单信息 + * @return 订单参数 + */ + public void initNotifyUrl(Map parameters, Order order) { + OrderParaStructure.loadParameters(parameters, WxConst.NOTIFY_URL, payConfigStorage.getNotifyUrl()); + OrderParaStructure.loadParameters(parameters, WxConst.NOTIFY_URL, order); + } + + /** + * 微信统一下单接口 + * + * @param order 支付订单集 + * @return 下单结果 + */ + public JSONObject unifiedOrder(PayOrder order) { + + //统一下单 + Map parameters = getPublicParameters(); + + // 订单号 + parameters.put(WxConst.COMBINE_OUT_TRADE_NO, order.getOutTradeNo()); + + OrderParaStructure.loadDateParameters(parameters, WxConst.TIME_START, order, DateUtils.YYYY_MM_DD_T_HH_MM_SS); + OrderParaStructure.loadDateParameters(parameters, WxConst.TIME_EXPIRE, order, DateUtils.YYYY_MM_DD_T_HH_MM_SS); + initNotifyUrl(parameters, order); + //支付场景描述 + OrderParaStructure.loadParameters(parameters, WxConst.SCENE_INFO, order); + //子单信息 最多支持子单条数:50 + OrderParaStructure.loadParameters(parameters, WxConst.SUB_ORDERS, order); + //支付者信息 + if (StringUtils.isNotEmpty(order.getOpenid())) { + parameters.put("combine_payer_info", new MapGen<>("openid", order.getOpenid()).getAttr()); + } + + return getAssistService().doExecute(parameters, order); + } + + + /** + * 交易查询接口 + * + * @param transactionId 微信支付平台订单号 + * @param outTradeNo 商户单号 + * @return 返回查询回来的结果集,支付方原值返回 + */ + @Override + public Map query(String transactionId, String outTradeNo) { + return getAssistService().doExecute("", WxTransactionType.COMBINE_TRANSACTION, outTradeNo); + } + + + /** + * 交易关闭接口 + * + * @param transactionId 支付平台订单号 + * @param outTradeNo 商户单号 + * @return 返回支付方交易关闭后的结果 + */ + @Override + public Map close(String transactionId, String outTradeNo) { + throw new PayErrorException(new PayException("failure", "合单关闭必须要有子单")); + } + + /** + * 交易关闭接口 + * + * @param closeOrder 关闭订单 + * @return 返回支付方交易关闭后的结果 + */ + @Override + public Map close(CloseOrder closeOrder) { + Map parameters = new MapGen(WxConst.COMBINE_APPID, payConfigStorage.getAppId()) + .keyValue(WxConst.SUB_ORDERS, closeOrder.getAttr(WxConst.SUB_ORDERS)) + .getAttr(); + String requestBody = JSON.toJSONString(parameters, SerializerFeature.WriteMapNullValue); + return getAssistService().doExecute(requestBody, WxTransactionType.COMBINE_CLOSE, closeOrder.getOutTradeNo()); + } + + /** + * 创建消息 + * + * @param message 支付平台返回的消息 + * @return 支付消息对象 + */ + @Override + public PayMessage createMessage(Map message) { + return CombinePayMessage.create(message); + } +} diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayService.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayService.java index 49da334..80c6679 100644 --- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayService.java +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayService.java @@ -22,6 +22,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.egzosn.pay.common.api.BasePayService; import com.egzosn.pay.common.bean.BillType; +import com.egzosn.pay.common.bean.CloseOrder; import com.egzosn.pay.common.bean.CurType; import com.egzosn.pay.common.bean.MethodType; import com.egzosn.pay.common.bean.NoticeParams; @@ -81,27 +82,13 @@ public class WxPayService extends BasePayService { /** * 辅助api */ - private volatile WxPayAssistService wxPayAssistService; + private volatile WxPayAssistService assistService; /** * 微信参数构造器 */ private volatile WxParameterStructure wxParameterStructure; - - public WxPayAssistService getAssistService() { - if (null == wxPayAssistService) { - wxPayAssistService = new DefaultWxPayAssistService(this); - //在这预先进行初始化 - wxPayAssistService.refreshCertificate(); - } - return wxPayAssistService; - } - - public void setAssistService(WxPayAssistService wxPayAssistService) { - this.wxPayAssistService = wxPayAssistService; - } - /** * 创建支付服务 * @@ -123,26 +110,24 @@ public class WxPayService extends BasePayService { /** - * 初始化之后执行 + * 辅助api + * @return 辅助api */ - @Override - protected void initAfter() { - new Thread(() -> { - payConfigStorage.loadCertEnvironment(); - wxParameterStructure = new WxParameterStructure(payConfigStorage); + public WxPayAssistService getAssistService() { + if (null == assistService) { + assistService = new DefaultWxPayAssistService(this); //在这预先进行初始化 - try { - Thread.sleep(10); - } - catch (InterruptedException e) { - - } - getAssistService(); - }).start(); - - + assistService.refreshCertificate(); + } + return assistService; } + public void setAssistService(WxPayAssistService assistService) { + this.assistService = assistService; + } + + + /** * 设置api服务器地址 * @@ -154,6 +139,14 @@ public class WxPayService extends BasePayService { return this; } + public String getApiServerUrl() { + return apiServerUrl; + } + + public WxParameterStructure getWxParameterStructure() { + return wxParameterStructure; + } + /** * 根据交易类型获取url * @@ -323,6 +316,7 @@ public class WxPayService extends BasePayService { * @param is 请求流 * @return 获得回调的请求参数 */ + @Deprecated @Override public Map getParameter2Map(Map parameterMap, InputStream is) { throw new PayErrorException(new WxPayError(FAILURE, "微信V3不支持方式")); @@ -350,7 +344,7 @@ public class WxPayService extends BasePayService { noticeParams.setBody(JSON.parseObject(data)); } catch (IOException e) { - LOG.error("获取回调参数异常", e); + throw new PayErrorException(new WxPayError(FAILURE, "获取回调参数异常"), e); } Map> headers = new HashMap<>(); Enumeration headerNames = request.getHeaderNames(); @@ -457,8 +451,20 @@ public class WxPayService extends BasePayService { */ @Override public Map close(String transactionId, String outTradeNo) { + return close(new CloseOrder(outTradeNo)); + } + + + /** + * 交易关闭接口 + * + * @param closeOrder 关闭订单 + * @return 返回支付方交易关闭后的结果 + */ + @Override + public Map close(CloseOrder closeOrder) { String parameters = wxParameterStructure.getSpParameters(); - return getAssistService().doExecute(parameters, WxTransactionType.CLOSE, outTradeNo); + return getAssistService().doExecute(parameters, WxTransactionType.CLOSE, closeOrder.getOutTradeNo()); } /** diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/WxTransactionType.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/WxTransactionType.java index 70a6ee8..948d3f0 100644 --- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/WxTransactionType.java +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/WxTransactionType.java @@ -25,11 +25,14 @@ public enum WxTransactionType implements TransactionType { /** * 获取证书. */ - CERT("certificates", MethodType.GET), + CERT("/v3/certificates", MethodType.GET), + + //----------------------------------------------------------------- + //以下为直连与服务商支付方式 /** - * 公众号支付 + * 微信公众号支付或者小程序支付 */ - JSAPI("pay{partner}/transactions/jsapi", MethodType.POST) { + JSAPI("/v3/pay{partner}/transactions/jsapi", MethodType.POST) { @Override public void setAttribute(Map parameters, PayOrder order) { String key = parameters.containsKey("sub_mchid") ? "sub_openid" : "openid"; @@ -40,15 +43,15 @@ public enum WxTransactionType implements TransactionType { /** * 二维码支付 */ - NATIVE("pay{partner}/transactions/native", MethodType.POST, true), + NATIVE("/v3/pay{partner}/transactions/native", MethodType.POST, true), /** * 移动支付 */ - APP("pay{partner}/transactions/app", MethodType.POST), + APP("/v3/pay{partner}/transactions/app", MethodType.POST), /** * H5支付 */ - H5("pay{partner}/transactions/h5", MethodType.POST, true) { + H5("/v3/pay{partner}/transactions/h5", MethodType.POST, true) { @Override public void setAttribute(Map parameters, PayOrder order) { Object sceneInfoObj = parameters.get(WxConst.SCENE_INFO); @@ -79,7 +82,7 @@ public enum WxTransactionType implements TransactionType { * 兼容 后期会抛弃 */ @Deprecated - MWEB("pay{partner}/transactions/h5", MethodType.POST, true) { + MWEB("/v3/pay{partner}/transactions/h5", MethodType.POST, true) { @Override public void setAttribute(Map parameters, PayOrder order) { H5.setAttribute(parameters, order); @@ -91,35 +94,64 @@ public enum WxTransactionType implements TransactionType { * 查询订单 * 兼容V2的方式,通过入参来决定 */ - QUERY("pay{partner}/transactions/", MethodType.GET), + QUERY("/v3/pay{partner}/transactions/", MethodType.GET), /** * 微信支付订单号查询 */ - QUERY_TRANSACTION_ID("pay{partner}/transactions/id/{transaction_id}", MethodType.GET), + QUERY_TRANSACTION_ID("/v3/pay{partner}/transactions/id/{transaction_id}", MethodType.GET), /** * 商户订单号查询 */ - QUERY_OUT_TRADE_NO("pay{partner}/transactions/out-trade-no/{out_trade_no}", MethodType.GET), + QUERY_OUT_TRADE_NO("/v3/pay{partner}/transactions/out-trade-no/{out_trade_no}", MethodType.GET), /** * 关闭订单 */ - CLOSE("pay{partner}/transactions/out-trade-no/{out_trade_no}/close", MethodType.POST), + CLOSE("/v3/pay{partner}/transactions/out-trade-no/{out_trade_no}/close", MethodType.POST), /** * 申请退款 */ - REFUND("refund/domestic/refunds", MethodType.POST), + REFUND("/v3/refund/domestic/refunds", MethodType.POST), /** * 查询退款 */ - REFUND_QUERY("refund/domestic/refunds/{out_refund_no}", MethodType.GET), + REFUND_QUERY("/v3/refund/domestic/refunds/{out_refund_no}", MethodType.GET), /** * 申请交易账单 */ - TRADE_BILL("bill/tradebill", MethodType.GET), + TRADE_BILL("/v3/bill/tradebill", MethodType.GET), /** * 申请资金账单 */ - FUND_FLOW_BILL("bill/fundflowbill", MethodType.GET) + FUND_FLOW_BILL("/v3/bill/fundflowbill", MethodType.GET), + + //----------------------------------------------------------------- + //以下为合并支付 + /** + * 合单下单-APP支付API. + */ + COMBINE_APP("/v3/combine-transactions/app", MethodType.POST), + + /** + * 合单下单-微信公众号支付或者小程序支付. + */ + COMBINE_JSAPI("/v3/combine-transactions/jsapi", MethodType.POST), + /** + * 合单下单-H5支付API. + */ + COMBINE_H5("/v3/combine-transactions/h5", MethodType.POST, true), + /** + * 合单下单-Native支付API. + */ + COMBINE_NATIVE("/v3/combine-transactions/native", MethodType.POST, true), + /** + * 合单查询订单API. + */ + COMBINE_TRANSACTION("/v3/combine-transactions/out-trade-no/{combine_out_trade_no}", MethodType.GET), + + /** + * 合单关闭订单API. + */ + COMBINE_CLOSE("/v3/combine-transactions/out-trade-no/{combine_out_trade_no}/close", MethodType.POST), ; WxTransactionType(String type, MethodType method) { diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombineAmount.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombineAmount.java new file mode 100644 index 0000000..f3d812b --- /dev/null +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombineAmount.java @@ -0,0 +1,34 @@ +package com.egzosn.pay.wx.v3.bean.combine; + +import com.alibaba.fastjson.annotation.JSONField; +import com.egzosn.pay.wx.v3.bean.response.order.Amount; + +/** + * 合单支付订单金额信息. + * + * @author Egan + *
+ * email egan@egzosn.com
+ * date 2021/10/5
+ * 
+ */ +public class CombineAmount extends Amount { + + /** + * 子单金额,单位为分,必填 + * 境外场景下,标价金额要超过商户结算币种的最小单位金额,例如结算币种为美元,则标价金额必须大于1美分 + */ + @JSONField(name = "total_amount") + private Integer totalAmount; + + + public Integer getTotalAmount() { + return totalAmount; + } + + public void setTotalAmount(Integer totalAmount) { + this.totalAmount = totalAmount; + } + + +} \ No newline at end of file diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombineCloseOrder.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombineCloseOrder.java new file mode 100644 index 0000000..cef6267 --- /dev/null +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombineCloseOrder.java @@ -0,0 +1,30 @@ +package com.egzosn.pay.wx.v3.bean.combine; + +import java.util.List; + +import com.egzosn.pay.common.bean.CloseOrder; +import com.egzosn.pay.wx.v3.utils.WxConst; + +/** + * 微信合单关闭订单 + * @author Egan + * @email egan@egzosn.com + * @date 2021/10/6 + */ +public class CombineCloseOrder extends CloseOrder { + + /** + * 子单信息,必填,最多50单 + */ + private List subOrders; + + + public List getSubOrders() { + return subOrders; + } + + public void setSubOrders(List subOrders) { + this.subOrders = subOrders; + addAttr(WxConst.SUB_ORDERS, subOrders); + } +} diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombinePayMessage.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombinePayMessage.java new file mode 100644 index 0000000..cda2d61 --- /dev/null +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombinePayMessage.java @@ -0,0 +1,115 @@ +package com.egzosn.pay.wx.v3.bean.combine; + +import java.util.List; +import java.util.Map; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.egzosn.pay.common.bean.PayMessage; +import com.egzosn.pay.wx.v3.bean.order.SceneInfo; +import com.egzosn.pay.wx.v3.bean.response.order.Payer; +import com.egzosn.pay.wx.v3.utils.WxConst; + +/** + * 合单支付回调消息,兼容退款回调 + * @author Egan + *
+ * email egan@egzosn.com
+ * date 2021/10/4
+ * 
+ */ +public class CombinePayMessage extends PayMessage { + + + /** + * 合单商户appid,即合单发起方的appid + */ + @JSONField(name = WxConst.COMBINE_APPID) + private String combineAppid; + + /** + * 合单商户号. + */ + @JSONField(name = WxConst.COMBINE_MCH_ID) + private String combineMchid; + + /** + * 合单商户订单号. + */ + @JSONField(name = WxConst.COMBINE_OUT_TRADE_NO) + private String combineOutTradeNo; + + + /** + * 支付者信息 + */ + @JSONField(name = "combine_payer_info") + private Payer combinePayerInfo; + + /** + * 场景信息,合单支付回调只返回device_id + */ + @JSONField(name = WxConst.SCENE_INFO) + private SceneInfo sceneInfo; + + /** + * 合单支付回调子订单. + */ + @JSONField(name = WxConst.SUB_ORDERS) + private List subOrders; + + public String getCombineAppid() { + return combineAppid; + } + + public void setCombineAppid(String combineAppid) { + this.combineAppid = combineAppid; + } + + public String getCombineMchid() { + return combineMchid; + } + + public void setCombineMchid(String combineMchid) { + this.combineMchid = combineMchid; + } + + public String getCombineOutTradeNo() { + return combineOutTradeNo; + } + + public void setCombineOutTradeNo(String combineOutTradeNo) { + this.combineOutTradeNo = combineOutTradeNo; + } + + public Payer getCombinePayerInfo() { + return combinePayerInfo; + } + + public void setCombinePayerInfo(Payer combinePayerInfo) { + this.combinePayerInfo = combinePayerInfo; + } + + public SceneInfo getSceneInfo() { + return sceneInfo; + } + + public void setSceneInfo(SceneInfo sceneInfo) { + this.sceneInfo = sceneInfo; + } + + public List getSubOrders() { + return subOrders; + } + + public void setSubOrders(List subOrders) { + this.subOrders = subOrders; + } + + public static final CombinePayMessage create(Map message) { + CombinePayMessage payMessage = new JSONObject(message).toJavaObject(CombinePayMessage.class); +// payMessage.setPayType(""); + payMessage.setPayMessage(message); + return payMessage; + } +} diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombinePayOrder.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombinePayOrder.java new file mode 100644 index 0000000..280aef3 --- /dev/null +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombinePayOrder.java @@ -0,0 +1,92 @@ +package com.egzosn.pay.wx.v3.bean.combine; + +import java.util.Date; +import java.util.List; + +import com.egzosn.pay.common.bean.PayOrder; +import com.egzosn.pay.wx.v3.bean.order.SceneInfo; +import com.egzosn.pay.wx.v3.bean.order.SubOrder; +import com.egzosn.pay.wx.v3.utils.WxConst; + +/** + * 合并支付订单 + * + * @author Egan + *
+ * email egan@egzosn.com
+ * date 2021/10/5
+ * 
+ */ +public class CombinePayOrder extends PayOrder { + + /** + * 子单信息,必填,最多50单 + */ + private List subOrders; + /** + * 交易起始时间,选填 + */ + private Date timeStart; + + /** + * 交易结束时间,选填 + */ + private Date timeExpire; + + /** + * 支付场景信息描述 + */ + private SceneInfo sceneInfo; + + public List getSubOrders() { + return subOrders; + } + + public void setSubOrders(List subOrders) { + this.subOrders = subOrders; + addAttr(WxConst.SUB_ORDERS, subOrders); + } + + public Date getTimeStart() { + return timeStart; + } + + public void setTimeStart(Date timeStart) { + this.timeStart = timeStart; + addAttr(WxConst.TIME_START, timeStart); + } + + public Date getTimeExpire() { + return timeExpire; + } + + public void setTimeExpire(Date timeExpire) { + this.timeExpire = timeExpire; + addAttr(WxConst.TIME_EXPIRE, timeExpire); + } + + /** + * 合单支付总订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一 。 + * @return 合单支付总订单号 + */ + public String getCombineOutTradeNo() { + return getOutTradeNo(); + } + + /** + * 合单支付总订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一 。 + * @param combineOutTradeNo 合单支付总订单号 + */ + public void setCombineOutTradeNo(String combineOutTradeNo) { + setOutTradeNo(combineOutTradeNo); + } + + public SceneInfo getSceneInfo() { + return sceneInfo; + } + + public void setSceneInfo(SceneInfo sceneInfo) { + this.sceneInfo = sceneInfo; + addAttr(WxConst.SCENE_INFO, sceneInfo); + } +} diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombineSubOrder.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombineSubOrder.java new file mode 100644 index 0000000..ee66a24 --- /dev/null +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/combine/CombineSubOrder.java @@ -0,0 +1,42 @@ +package com.egzosn.pay.wx.v3.bean.combine; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 子单信息,最多50单. + * @author Egan + *
+ * email egan@egzosn.com
+ * date 2021/10/5
+ * 
+ */ +public class CombineSubOrder { + + /** + * 子单发起方商户号,必填,必须与发起方appid有绑定关系。 + */ + private String mchid; + + /** + * 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。 + * 示例值:20150806125346 + */ + @JSONField(name = "out_trade_no") + private String outTradeNo; + + public String getMchid() { + return mchid; + } + + public void setMchid(String mchid) { + this.mchid = mchid; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public void setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + } +} diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/order/SettleInfo.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/order/SettleInfo.java new file mode 100644 index 0000000..4ce0a7c --- /dev/null +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/order/SettleInfo.java @@ -0,0 +1,45 @@ +package com.egzosn.pay.wx.v3.bean.order; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 结算信息 + * @author Egan + *
+ * email egan@egzosn.com
+ * date 2021/10/5
+ * 
+ */ +public class SettleInfo { + /** + * 是否指定分账,枚举值 + * true:是 + * false:否 + * 示例值:true + */ + @JSONField(name = "profit_sharing") + private Boolean profitSharing; + /** + * 补差金额 + * SettleInfo.profit_sharing为true时,该金额才生效。 + * 注意:单笔订单最高补差金额为5000元 + */ + @JSONField(name = "subsidy_amount") + private Integer subsidyAmount; + + public Boolean getProfitSharing() { + return profitSharing; + } + + public void setProfitSharing(Boolean profitSharing) { + this.profitSharing = profitSharing; + } + + public Integer getSubsidyAmount() { + return subsidyAmount; + } + + public void setSubsidyAmount(Integer subsidyAmount) { + this.subsidyAmount = subsidyAmount; + } +} diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/order/SubOrder.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/order/SubOrder.java new file mode 100644 index 0000000..0b0010d --- /dev/null +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/order/SubOrder.java @@ -0,0 +1,187 @@ +package com.egzosn.pay.wx.v3.bean.order; + +import java.util.Date; +import java.util.List; + +import com.alibaba.fastjson.annotation.JSONField; +import com.egzosn.pay.wx.v3.bean.WxTransactionType; +import com.egzosn.pay.wx.v3.bean.combine.CombineAmount; +import com.egzosn.pay.wx.v3.bean.combine.CombineSubOrder; +import com.egzosn.pay.wx.v3.bean.response.order.PromotionDetail; +import com.egzosn.pay.wx.v3.bean.response.order.TradeState; + +/** + * 子单信息,最多50单. + * + * @author Egan + *
+ * email egan@egzosn.com
+ * date 2021/10/5
+ * 
+ */ +public class SubOrder extends CombineSubOrder { + /** + * 合单支付订单金额信息,必填。 + */ + private CombineAmount amount; + + + /** + * 商品描述,必填,需传入应用市场上的APP名字-实际商品名称,例如:天天爱消除-游戏充值。 + */ + private String description; + + + /** + * 二级商户商户号,由微信支付生成并下发。 + *

+ * 服务商子商户的商户号,被合单方。 + *

+ * 直连商户不用传二级商户号。 + */ + @JSONField(name = "sub_mchid") + private String subMchid; + + /** + * 结算信息,选填 + */ + @JSONField(name = "settle_info") + private SettleInfo settleInfo; + + + /** + * 银行类型,采用字符串类型的银行标识。 + * 银行标识请参考 《银行类型对照表》 + * 示例值:CMC + */ + @JSONField(name = "bank_type") + private String bankType; + + /** + * 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用 + */ + private String attach; + + /** + * 支付完成时间|| 退款完成时间,遵循rfc3339标准格式, + * 格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒, + * TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。 + * 例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。 + * 示例值:2018-06-08T10:34:56+08:00 + */ + @JSONField(name = "success_time", format = "yyyy-MM-dd'T'HH:mm:ssXXX") + private Date successTime; + + /** + * 交易状态 + */ + @JSONField(name = "trade_state") + private TradeState tradeState; + + /** + * 交易类型 + */ + @JSONField(name = "trade_type") + private WxTransactionType tradeType; + + /** + * 微信支付侧订单号 + */ + @JSONField(name = "transaction_id") + private String transactionId; + + /** + * 优惠功能,子单有核销优惠券时有返回 + */ + @JSONField(name = "promotion_detail") + private List promotionDetail; + + public CombineAmount getAmount() { + return amount; + } + + public void setAmount(CombineAmount amount) { + this.amount = amount; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + + public String getSubMchid() { + return subMchid; + } + + public void setSubMchid(String subMchid) { + this.subMchid = subMchid; + } + + public SettleInfo getSettleInfo() { + return settleInfo; + } + + public void setSettleInfo(SettleInfo settleInfo) { + this.settleInfo = settleInfo; + } + + public String getBankType() { + return bankType; + } + + public void setBankType(String bankType) { + this.bankType = bankType; + } + + public String getAttach() { + return attach; + } + + public void setAttach(String attach) { + this.attach = attach; + } + + public Date getSuccessTime() { + return successTime; + } + + public void setSuccessTime(Date successTime) { + this.successTime = successTime; + } + + public TradeState getTradeState() { + return tradeState; + } + + public void setTradeState(TradeState tradeState) { + this.tradeState = tradeState; + } + + public WxTransactionType getTradeType() { + return tradeType; + } + + public void setTradeType(WxTransactionType tradeType) { + this.tradeType = tradeType; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public List getPromotionDetail() { + return promotionDetail; + } + + public void setPromotionDetail(List promotionDetail) { + this.promotionDetail = promotionDetail; + } +} diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/WxPayMessage.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/WxPayMessage.java index 8aa4008..f02ffc4 100644 --- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/WxPayMessage.java +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/WxPayMessage.java @@ -16,7 +16,7 @@ import com.egzosn.pay.wx.v3.bean.response.order.PromotionDetail; import com.egzosn.pay.wx.v3.bean.response.order.TradeState; /** - * 支付回调消息 + * 支付回调消息,兼容退款回调 * @author Egan *

  * email egan@egzosn.com
@@ -99,8 +99,36 @@ public class WxPayMessage extends PayMessage {
      */
     @JSONField(name = "trade_state")
     private TradeState tradeState;
-
-
+    /**
+     * 商户退款单号
+     */
+    @JSONField(name = "out_refund_no")
+    private String outRefundNo;
+    /**
+     * 微信退款单号
+     */
+    @JSONField(name = "refund_id")
+    private String refundId;
+    /**
+     * 退款状态,枚举值:
+     * SUCCESS:退款成功
+     * CLOSE:退款关闭
+     * ABNORMAL:退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款
+     * 示例值:SUCCESS
+     */
+    @JSONField(name = "refund_status")
+    private TradeState refundStatus;
+    /**
+     * 退款入账账户
+     * 取当前退款单的退款入账方。
+     * 1、退回银行卡:{银行名称}{卡类型}{卡尾号}
+     * 2、退回支付用户零钱: 支付用户零钱
+     * 3、退还商户: 商户基本账户、商户结算银行账户
+     * 4、退回支付用户零钱通:支付用户零钱通
+     * 示例值:招商银行信用卡0403
+     */
+    @JSONField(name = "user_received_account")
+    private String userReceivedAccount;
     /**
      * 交易状态描述
      * 示例值:支付成功
@@ -121,7 +149,7 @@ public class WxPayMessage extends PayMessage {
     private String attach;
 
     /**
-     * 支付完成时间,遵循rfc3339标准格式,
+     * 支付完成时间|| 退款完成时间,遵循rfc3339标准格式,
      * 格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,
      * TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
      * 例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。
@@ -301,6 +329,37 @@ public class WxPayMessage extends PayMessage {
         return BigDecimal.valueOf(getAmount().getTotal());
     }
 
+    public String getOutRefundNo() {
+        return outRefundNo;
+    }
+
+    public void setOutRefundNo(String outRefundNo) {
+        this.outRefundNo = outRefundNo;
+    }
+
+    public String getRefundId() {
+        return refundId;
+    }
+
+    public void setRefundId(String refundId) {
+        this.refundId = refundId;
+    }
+
+    public TradeState getRefundStatus() {
+        return refundStatus;
+    }
+
+    public void setRefundStatus(TradeState refundStatus) {
+        this.refundStatus = refundStatus;
+    }
+
+    public String getUserReceivedAccount() {
+        return userReceivedAccount;
+    }
+
+    public void setUserReceivedAccount(String userReceivedAccount) {
+        this.userReceivedAccount = userReceivedAccount;
+    }
 
     public static final WxPayMessage create(Map message) {
         WxPayMessage payMessage = new JSONObject(message).toJavaObject(WxPayMessage.class);
diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/Amount.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/Amount.java
index c6cf950..b134a8c 100644
--- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/Amount.java
+++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/Amount.java
@@ -2,25 +2,41 @@ package com.egzosn.pay.wx.v3.bean.response.order;
 
 import java.math.BigDecimal;
 
+import com.alibaba.fastjson.annotation.JSONField;
+
 /**
  * 回调中的订单金额信息
+ *
  * @author Egan
  * 
  * email egan@egzosn.com
  * date 2021/10/4
  * 
*/ -public class Amount extends com.egzosn.pay.wx.v3.bean.order.Amount{ +public class Amount extends com.egzosn.pay.wx.v3.bean.order.Amount { /** * 用户支付金额,单位为分。 */ + @JSONField(name = "payer_total") private BigDecimal payerTotal; /** * 用户支付币种 */ + @JSONField(name = "payer_currency") private String payerCurrency; + /** + * 退款金额,单位为分 + */ + private Integer refund; + + /** + * 退款给用户的金额,单位为分,不包含所有优惠券金额 + */ + @JSONField(name = "payer_refund") + private Integer payerRefund; + public BigDecimal getPayerTotal() { return payerTotal; } @@ -36,4 +52,20 @@ public class Amount extends com.egzosn.pay.wx.v3.bean.order.Amount{ public void setPayerCurrency(String payerCurrency) { this.payerCurrency = payerCurrency; } + + public Integer getRefund() { + return refund; + } + + public void setRefund(Integer refund) { + this.refund = refund; + } + + public Integer getPayerRefund() { + return payerRefund; + } + + public void setPayerRefund(Integer payerRefund) { + this.payerRefund = payerRefund; + } } diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/Payer.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/Payer.java index 623b97d..7f359f1 100644 --- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/Payer.java +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/Payer.java @@ -11,6 +11,7 @@ package com.egzosn.pay.wx.v3.bean.response.order; public class Payer { /** * 用户在直连商户appid下的唯一标识。 + * 使用合单appid获取的对应用户openid。是用户在商户appid下的唯一标识。 */ private String openid; diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/TradeState.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/TradeState.java index 6b6afe6..9d49a4c 100644 --- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/TradeState.java +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/response/order/TradeState.java @@ -1,7 +1,8 @@ package com.egzosn.pay.wx.v3.bean.response.order; /** - * 微信侧返回交易状态 + * 微信侧返回交易状态,兼容退款状态 + * * @author Egan *
  * email egan@egzosn.com
@@ -11,31 +12,28 @@ package com.egzosn.pay.wx.v3.bean.response.order;
 public enum TradeState {
     /**
      * 支付成功
-     *
-     * 
+     * 退款成功
      */
     SUCCESS,
     /**
      * 转入退款
-     *
-     * 
      */
     REFUND,
     /**
      * 未支付
-     *
-     * 
      */
     NOTPAY,
     /**
      * 已关闭
-     *
-     * 
+     * 退款关闭
      */
     CLOSED,
+    /**
+     * 退款异常.
+     */
+    ABNORMAL,
     /**
      * 已撤销(付款码支付)
-     *
      */
     REVOKED,
     /**
@@ -48,7 +46,6 @@ public enum TradeState {
     PAYERROR,
     /**
      * 已接收,等待扣款
-     *
      */
     ACCEPT,
 }
\ No newline at end of file
diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/utils/WxConst.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/utils/WxConst.java
index 2055d49..941ff10 100644
--- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/utils/WxConst.java
+++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/utils/WxConst.java
@@ -17,7 +17,7 @@ public final class WxConst {
     /**
      * 微信默认请求地址
      */
-    public static final String URI = "https://api.mch.weixin.qq.com/v3/";
+    public static final String URI = "https://api.mch.weixin.qq.com";
     /**
      * 证书别名
      */
@@ -31,12 +31,20 @@ public final class WxConst {
      * 沙箱
      */
     public static final String SANDBOXNEW = "sandboxnew/";
+    public static final String COMBINE = "combine_";
     public static final String APPID = "appid";
+
+    public static final String COMBINE_APPID = COMBINE + APPID;
     public static final String MCH_ID = "mchid";
+    public static final String COMBINE_MCH_ID = COMBINE + MCH_ID;
     public static final String SUB_MCH_ID = "sub_mchid";
     public static final String SP_MCH_ID = "sp_mchid";
     public static final String OUT_TRADE_NO = "out_trade_no";
+    public static final String COMBINE_OUT_TRADE_NO = COMBINE + OUT_TRADE_NO;
     public static final String NOTIFY_URL = "notify_url";
+    public static final String TIME_START = "time_start";
+    public static final String TIME_EXPIRE = "time_expire";
+    public static final String SUB_ORDERS = "sub_orders";
 
     public static final String TOKEN_PATTERN = "mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\"";