diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsCancelResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsCancelResult.java new file mode 100644 index 0000000000000000000000000000000000000000..9e59fecf73bf85b79dfae7249843611634d38f7c --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsCancelResult.java @@ -0,0 +1,48 @@ +package com.github.binarywang.wxpay.bean.transfer; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + *
+ * 商家转账到零钱撤销转账接口
+ * 文档地址:https://pay.weixin.qq.com/doc/v3/merchant/4012716458
+ * 
+ * + * @author Nor + * @date 2025/1/17 + */ +@Data +@NoArgsConstructor +public class TransferBillsCancelResult implements Serializable { + private static final long serialVersionUID = -4935840810530008418L; + + /** + * 【商户单号】 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一 + */ + @SerializedName("out_bill_no") + private String outBillNo; + + /** + * 【微信转账单号】 微信转账单号,微信商家转账系统返回的唯一标识 + */ + @SerializedName("transfer_bill_no") + private String transferBillNo; + + /** + * 【单据状态】 商家转账订单状态 + * 可选取值 + * CANCELING: 商户撤销请求受理成功,该笔转账正在撤销中 + * CANCELLED: 转账撤销完成 + */ + private String state; + + /** + * 【最后一次单据状态变更时间】 按照使用rfc3339所定义的格式,格式为yyyy-MM-DDThh:mm:ss+TIMEZONE + */ + @SerializedName("update_time") + private String updateTime; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsGetResult.java new file mode 100644 index 0000000000000000000000000000000000000000..2e24a4a3c647a21a962573e2134b743c8ee82f80 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsGetResult.java @@ -0,0 +1,103 @@ +package com.github.binarywang.wxpay.bean.transfer; + +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + *
+ * 商家转账到零钱查询转账单接口
+ * 文档地址:https://pay.weixin.qq.com/doc/v3/merchant/4012716457 https://pay.weixin.qq.com/doc/v3/merchant/4012716437
+ * 
+ * + * @author Nor + * @date 2025/1/17 + */ +@Data +@NoArgsConstructor +public class TransferBillsGetResult implements Serializable { + private static final long serialVersionUID = -6376955113492371763L; + + /** + * 【商户号】 微信支付分配的商户号 + */ + @SerializedName("mch_id") + private String mchId; + + /** + * 【商户单号】 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一 + */ + @SerializedName("out_bill_no") + private String outBillNo; + + /** + * 【商家转账订单号】 商家转账订单的主键,唯一定义此资源的标识 + */ + @SerializedName("transfer_bill_no") + private String transferBillNo; + + /** + * 【商户AppID】 申请商户号的AppID或商户号绑定的AppID(企业号corpid即为此AppID) + */ + private String appid; + + /** + * 【单据状态】 + * 可选取值 + * ACCEPTED: 转账已受理 + * PROCESSING: 转账处理中,转账结果尚未明确,如一直处于此状态,建议检查账户余额是否足够 + * WAIT_USER_CONFIRM: 待收款用户确认,可拉起微信收款确认页面进行收款确认 + * TRANSFERING: 转账结果尚未明确,可拉起微信收款确认页面再次重试确认收款 + * SUCCESS: 转账成功 + * FAIL: 转账失败 + * CANCELING: 商户撤销请求受理成功,该笔转账正在撤销中 + * CANCELLED: 转账撤销完成 + * + * @see WxPayConstants.TransformBillState + */ + private String state; + + /** + * 【转账金额】 转账金额单位为“分”。 + */ + @SerializedName("transfer_amount") + private String transferAmount; + + /** + * 【转账备注】 单条转账备注(微信用户会收到该备注),UTF8编码,最多允许32个字符 + */ + @SerializedName("transfer_remark") + private String transferRemark; + + /** + * 【失败原因】 订单已失败或者已退资金时,返回失败原因 + */ + @SerializedName("fail_reason") + private String failReason; + + /** + * 【收款用户OpenID】 商户AppID下,某用户的OpenID + */ + private String openid; + + /** + * 【收款用户姓名】 收款方真实姓名。支持标准RSA算法和国密算法,公钥由微信侧提供转账金额 >= 2,000元时,该笔明细必须填写若商户传入收款用户姓名,微信支付会校验用户OpenID与姓名是否一致,并提供电子回单 + */ + @SerializedName("user_name") + private String userName; + + /** + * 【单据创建时间】 单据受理成功时返回,按照使用rfc3339所定义的格式,格式为yyyy-MM-DDThh:mm:ss+TIMEZONE + */ + @SerializedName("create_time") + private String createTime; + + /** + * 【最后一次状态变更时间】 单据最后更新时间,按照使用rfc3339所定义的格式,格式为yyyy-MM-DDThh:mm:ss+TIMEZONE + */ + @SerializedName("update_time") + private String updateTime; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsResult.java index 9f7aac7fbb40343d3ecbc636c226e6d8ba10786f..78e0aec6abb2d2ba49df61623ee197e27018de83 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsResult.java @@ -1,5 +1,6 @@ package com.github.binarywang.wxpay.bean.transfer; +import com.github.binarywang.wxpay.constant.WxPayConstants; import com.google.gson.annotations.SerializedName; import lombok.Data; import lombok.NoArgsConstructor; @@ -37,9 +38,11 @@ public class TransferBillsResult implements Serializable { /** * 单据状态 + * + * @see WxPayConstants.TransformBillState */ - @SerializedName("status") - private String status; + @SerializedName("state") + private String state; /** * 失败原因 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java index 819cdfe731d1e0d5d2145fa6d0b8bce932c33e2b..e8a6b6acb35116628628bbfbfac3b46218a2b9b2 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java @@ -6,6 +6,7 @@ import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult; import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; import com.google.common.collect.Lists; +import lombok.experimental.UtilityClass; import org.apache.commons.lang3.time.FastDateFormat; import java.text.Format; @@ -353,4 +354,86 @@ public class WxPayConstants { public static final String PERSONAL_SUB_OPENID = "PERSONAL_SUB_OPENID"; } + /** + * 微信商户转账订单状态 + */ + @UtilityClass + public static class TransformBillState { + /** + * 转账已受理 + */ + public static final String ACCEPTED = "ACCEPTED"; + + /** + * 转账处理中,转账结果尚未明确,如一直处于此状态,建议检查账户余额是否足够 + */ + public static final String PROCESSING = "PROCESSING"; + + /** + * 待收款用户确认,可拉起微信收款确认页面进行收款确认 + */ + public static final String WAIT_USER_CONFIRM = "WAIT_USER_CONFIRM"; + + /** + * 转账结果尚未明确,可拉起微信收款确认页面再次重试确认收款 + */ + public static final String TRANSFERING = "TRANSFERING"; + + /** + * 转账成功 + */ + public static final String SUCCESS = "SUCCESS"; + + /** + * 转账失败 + */ + public static final String FAIL = "FAIL"; + + /** + * 商户撤销请求受理成功,该笔转账正在撤销中 + */ + public static final String CANCELING = "CANCELING"; + + /** + * 转账撤销完成 + */ + public static final String CANCELLED = "CANCELLED"; + + } + + /** + * 【转账场景ID】 该笔转账使用的转账场景,可前往“商户平台-产品中心-商家转账”中申请。 + */ + @UtilityClass + public static class TransformSceneId { + /** + * 现金营销 + */ + public static final String CASH_MARKETING = "1001"; + } + + /** + * 用户收款感知 + * + * @see 官方文档 + */ + @UtilityClass + public static class UserRecvPerception { + /** + * 转账场景 现金营销 + * 场景介绍 向参与营销活动的用户发放现金奖励 + */ + public static class CASH_MARKETING { + /** + * 默认展示 + */ + public static final String ACTIVITY = "活动奖励"; + + /** + * 需在发起转账时,“用户收款感知”字段主动传入“现金奖励”才可展示 + */ + public static final String CASH = "现金奖励"; + } + + } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/TransferService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/TransferService.java index c02430a960ea8a5ac147f93990a254955857e5a7..01113c95065a624dc6855d5490f072449cb4c149 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/TransferService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/TransferService.java @@ -128,6 +128,57 @@ public interface TransferService { */ TransferBillsResult transferBills(TransferBillsRequest request) throws WxPayException; + /** + *
+   *
+   * 2025.1.15 开始新接口 撤销转账API
+   *
+   * 请求方式:POST(HTTPS)
+   * 请求地址:请求地址
+   *
+   * 文档地址:商户撤销转账API
+   * 
+ * + * @param outBillNo 【商户单号】 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一 + * @return TransformBillsGetResult 转账单 + * @throws WxPayException . + */ + TransferBillsCancelResult transformBillsCancel(String outBillNo) throws WxPayException; + + /** + *
+   *
+   * 2025.1.15 开始新接口 发起商家转账API
+   *
+   * 请求方式:GET(HTTPS)
+   * 请求地址:请求地址
+   *
+   * 文档地址:商户单号查询转账单API
+   * 
+ * + * @param outBillNo 【商户单号】 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一 + * @return TransformBillsGetResult 转账单 + * @throws WxPayException . + */ + TransferBillsGetResult getBillsByOutBillNo(String outBillNo) throws WxPayException; + + /** + *
+   *
+   * 2025.1.15 开始新接口 微信单号查询转账单API
+   *
+   * 请求方式:GET(HTTPS)
+   * 请求地址:请求地址
+   *
+   * 文档地址:商户单号查询转账单API
+   * 
+ * + * @param transferBillNo 【微信转账单号】 微信转账单号,微信商家转账系统返回的唯一标识 + * @return TransformBillsGetResult 转账单 + * @throws WxPayException . + */ + TransferBillsGetResult getBillsByTransferBillNo(String transferBillNo) throws WxPayException; + /** * 2025.1.15 开始新接口 解析商家转账结果 * 详见 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index 19b4ed0a07a38d1d1a5ce2e20ed522b21086b5d3..8ceac2b6ba69b8f38cd93060ab819cf3917070db 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -39,16 +39,18 @@ public interface WxPayService { * Map里 加入新的 {@link WxPayConfig},适用于动态添加新的微信商户配置. * * @param mchId 商户id + * @param appId 微信应用id * @param wxPayConfig 新的微信配置 */ - void addConfig(String mchId, WxPayConfig wxPayConfig); + void addConfig(String mchId, String appId, WxPayConfig wxPayConfig); /** - * 从 Map中 移除 {@link String mchId} 所对应的 {@link WxPayConfig},适用于动态移除微信商户配置. + * 从 Map中 移除 {@link String mchId} 和 {@link String appId} 所对应的 {@link WxPayConfig},适用于动态移除微信商户配置. * * @param mchId 对应商户的标识 + * @param appId 微信应用id */ - void removeConfig(String mchId); + void removeConfig(String mchId, String appId); /** * 注入多个 {@link WxPayConfig} 的实现. 并为每个 {@link WxPayConfig} 赋予不同的 {@link String mchId} 值 @@ -70,17 +72,19 @@ public interface WxPayService { * 进行相应的商户切换. * * @param mchId 商户标识 + * @param appId 微信应用id * @return 切换是否成功 boolean */ - boolean switchover(String mchId); + boolean switchover(String mchId, String appId); /** * 进行相应的商户切换. * * @param mchId 商户标识 + * @param appId 微信应用id * @return 切换成功 ,则返回当前对象,方便链式调用,否则抛出异常 */ - WxPayService switchoverTo(String mchId); + WxPayService switchoverTo(String mchId, String appId); /** * 发送post请求,得到响应字节数组. @@ -617,10 +621,10 @@ public interface WxPayService { /** * 调用统一下单接口,并组装生成支付所需参数对象. * - * @param 请使用{@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段 + * @param 请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段 * @param tradeType the trade type * @param request 统一下单请求参数 - * @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段 + * @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段 * @throws WxPayException the wx pay exception */ T createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException; @@ -628,10 +632,10 @@ public interface WxPayService { /** * 服务商模式调用统一下单接口,并组装生成支付所需参数对象. * - * @param 请使用{@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段 + * @param 请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段 * @param tradeType the trade type * @param request 统一下单请求参数 - * @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段 + * @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段 * @throws WxPayException the wx pay exception */ T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException; @@ -1615,7 +1619,8 @@ public interface WxPayService { /** * 获取服务商直股份签约计划服务类 - * @return the partner pay score sign plan service + * + * @return the partner pay score sign plan service */ PartnerPayScoreSignPlanService getPartnerPayScoreSignPlanService(); } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java index 7c2055cec30070b0f3fbc031288818af4ad7e6fd..1fa2f8dc80e5d53f91c38e377d00c3b0ec9437f1 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java @@ -14,7 +14,6 @@ import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.config.WxPayConfigHolder; -import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.constant.WxPayConstants.SignType; import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType; import com.github.binarywang.wxpay.exception.WxPayException; @@ -46,6 +45,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.zip.ZipException; import static com.github.binarywang.wxpay.constant.WxPayConstants.QUERY_COMMENT_DATE_FORMAT; @@ -122,7 +122,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { private final PartnerPayScoreService partnerPayScoreService = new PartnerPayScoreServiceImpl(this); @Getter - private final PartnerPayScoreSignPlanService partnerPayScoreSignPlanService=new PartnerPayScoreSignPlanServiceImpl(this); + private final PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = new PartnerPayScoreSignPlanServiceImpl(this); @Getter private final MerchantTransferService merchantTransferService = new MerchantTransferServiceImpl(this); @@ -130,7 +130,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { @Getter private final BrandMerchantTransferService brandMerchantTransferService = new BrandMerchantTransferServiceImpl(this); - protected Map configMap = new HashMap<>(); + protected Map configMap = new ConcurrentHashMap<>(); @Override public WxPayConfig getConfig() { @@ -143,38 +143,37 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { @Override public void setConfig(WxPayConfig config) { - final String defaultMchId = config.getMchId(); - this.setMultiConfig(ImmutableMap.of(defaultMchId, config), defaultMchId); + final String defaultKey = this.getConfigKey(config.getMchId(), config.getAppId()); + this.setMultiConfig(ImmutableMap.of(defaultKey, config), defaultKey); } @Override - public void addConfig(String mchId, WxPayConfig wxPayConfig) { + public void addConfig(String mchId, String appId, WxPayConfig wxPayConfig) { synchronized (this) { if (this.configMap == null) { this.setConfig(wxPayConfig); } else { - WxPayConfigHolder.set(mchId); - this.configMap.put(mchId, wxPayConfig); + String configKey = this.getConfigKey(mchId, appId); + WxPayConfigHolder.set(configKey); + this.configMap.put(configKey, wxPayConfig); } } } @Override - public void removeConfig(String mchId) { + public void removeConfig(String mchId, String appId) { synchronized (this) { - if (this.configMap.size() == 1) { - this.configMap.remove(mchId); - log.warn("已删除最后一个商户号配置:{},须立即使用setConfig或setMultiConfig添加配置", mchId); + String configKey = this.getConfigKey(mchId, appId); + this.configMap.remove(configKey); + if (this.configMap.isEmpty()) { + log.warn("已删除最后一个商户号配置:mchId[{}],appid[{}],须立即使用setConfig或setMultiConfig添加配置", mchId, appId); return; } - if (WxPayConfigHolder.get().equals(mchId)) { - this.configMap.remove(mchId); - final String defaultMpId = this.configMap.keySet().iterator().next(); - WxPayConfigHolder.set(defaultMpId); - log.warn("已删除默认商户号配置,商户号【{}】被设为默认配置", defaultMpId); - return; + if (WxPayConfigHolder.get().equals(configKey)) { + final String nextConfigKey = this.configMap.keySet().iterator().next(); + WxPayConfigHolder.set(nextConfigKey); + log.warn("已删除默认商户号配置,商户号【{}】被设为默认配置", nextConfigKey); } - this.configMap.remove(mchId); } } @@ -184,28 +183,34 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { } @Override - public void setMultiConfig(Map wxPayConfigs, String defaultMchId) { + public void setMultiConfig(Map wxPayConfigs, String defaultConfigKey) { this.configMap = Maps.newHashMap(wxPayConfigs); - WxPayConfigHolder.set(defaultMchId); + WxPayConfigHolder.set(defaultConfigKey); } @Override - public boolean switchover(String mchId) { - if (this.configMap.containsKey(mchId)) { - WxPayConfigHolder.set(mchId); + public boolean switchover(String mchId, String appId) { + String configKey = this.getConfigKey(mchId, appId); + if (this.configMap.containsKey(configKey)) { + WxPayConfigHolder.set(configKey); return true; } - log.error("无法找到对应【{}】的商户号配置信息,请核实!", mchId); + log.error("无法找到对应mchId=【{}】,appId=【{}】的商户号配置信息,请核实!", mchId, appId); return false; } @Override - public WxPayService switchoverTo(String mchId) { - if (this.configMap.containsKey(mchId)) { - WxPayConfigHolder.set(mchId); + public WxPayService switchoverTo(String mchId, String appId) { + String configKey = this.getConfigKey(mchId, appId); + if (this.configMap.containsKey(configKey)) { + WxPayConfigHolder.set(configKey); return this; } - throw new WxRuntimeException(String.format("无法找到对应【%s】的商户号配置信息,请核实!", mchId)); + throw new WxRuntimeException(String.format("无法找到对应mchId=【%s】,appId=【%s】的商户号配置信息,请核实!", mchId, appId)); + } + + private String getConfigKey(String mchId, String appId) { + return mchId + "_" + appId; } @Override @@ -302,7 +307,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { @Override public WxPayRefundQueryV3Result refundPartnerQueryV3(WxPayRefundQueryV3Request request) throws WxPayException { - String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(),request.getSubMchid()); + String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(), request.getSubMchid()); String response = this.getV3(url); return GSON.fromJson(response, WxPayRefundQueryV3Result.class); } @@ -324,7 +329,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { } else if (configMap.get(result.getMchId()).getSignType() != null) { // 如果配置中signType有值,则使用它进行验签 signType = configMap.get(result.getMchId()).getSignType(); - this.switchover(result.getMchId()); + this.switchover(result.getMchId(), result.getAppid()); } } @@ -347,7 +352,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { */ private boolean verifyNotifySign(SignatureHeader header, String data) throws WxSignTestException { String wxPaySign = header.getSignature(); - if(wxPaySign.startsWith("WECHATPAY/SIGNTEST/")){ + if (wxPaySign.startsWith("WECHATPAY/SIGNTEST/")) { throw new WxSignTestException("微信支付签名探测流量"); } String beforeSign = String.format("%s\n%s\n%s\n", @@ -421,7 +426,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { WxPayRefundNotifyResult result; if (XmlConfig.fastMode) { result = BaseWxPayResult.fromXML(xmlData, WxPayRefundNotifyResult.class); - this.switchover(result.getMchId()); + this.switchover(result.getMchId(), result.getAppid()); result.decryptReqInfo(this.getConfig().getMchKey()); } else { result = WxPayRefundNotifyResult.fromXML(xmlData, this.getConfig().getMchKey()); @@ -458,7 +463,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { try { log.debug("扫码支付回调通知请求参数:{}", xmlData); WxScanPayNotifyResult result = BaseWxPayResult.fromXML(xmlData, WxScanPayNotifyResult.class); - this.switchover(result.getMchId()); + this.switchover(result.getMchId(), result.getAppid()); log.debug("扫码支付回调通知解析后的对象:{}", result); result.checkResult(this, this.getConfig().getSignType(), false); return result; @@ -1306,7 +1311,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { @Override public WxPayFaceAuthInfoResult getWxPayFaceAuthInfo(WxPayFaceAuthInfoRequest request) throws WxPayException { if (StringUtils.isEmpty(request.getSignType())) { - request.setSignType(WxPayConstants.SignType.MD5); + request.setSignType(SignType.MD5); } request.checkAndSign(this.getConfig()); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/TransferServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/TransferServiceImpl.java index 23bf7b13eef703246c081f1baf461fcab22fe50c..f43c887c16746a5b03638ce7a68b1d16c5eda461 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/TransferServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/TransferServiceImpl.java @@ -48,8 +48,7 @@ public class TransferServiceImpl implements TransferService { if (request.getNeedQueryDetail()) { url = String.format("%s/v3/transfer/batches/batch-id/%s?need_query_detail=true&offset=%s&limit=%s&detail_status=%s", this.payService.getPayBaseUrl(), request.getBatchId(), request.getOffset(), request.getLimit(), request.getDetailStatus()); - } - else { + } else { url = String.format("%s/v3/transfer/batches/batch-id/%s?need_query_detail=false", this.payService.getPayBaseUrl(), request.getBatchId()); } @@ -70,8 +69,7 @@ public class TransferServiceImpl implements TransferService { if (request.getNeedQueryDetail()) { url = String.format("%s/v3/transfer/batches/out-batch-no/%s?need_query_detail=true&offset=%s&limit=%s&detail_status=%s", this.payService.getPayBaseUrl(), request.getOutBatchNo(), request.getOffset(), request.getLimit(), request.getDetailStatus()); - } - else { + } else { url = String.format("%s/v3/transfer/batches/out-batch-no/%s?need_query_detail=false", this.payService.getPayBaseUrl(), request.getOutBatchNo()); } @@ -97,6 +95,31 @@ public class TransferServiceImpl implements TransferService { return GSON.fromJson(result, TransferBillsResult.class); } + @Override + public TransferBillsCancelResult transformBillsCancel(String outBillNo) throws WxPayException { + String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/%s/cancel", + this.payService.getPayBaseUrl(), outBillNo); + String result = this.payService.postV3(url, ""); + + return GSON.fromJson(result, TransferBillsCancelResult.class); + } + + @Override + public TransferBillsGetResult getBillsByOutBillNo(String outBillNo) throws WxPayException { + String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/%s", + this.payService.getPayBaseUrl(), outBillNo); + String result = this.payService.getV3(url); + return GSON.fromJson(result, TransferBillsGetResult.class); + } + + @Override + public TransferBillsGetResult getBillsByTransferBillNo(String transferBillNo) throws WxPayException { + String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/transfer-bill-no/%s", + this.payService.getPayBaseUrl(), transferBillNo); + String result = this.payService.getV3(url); + return GSON.fromJson(result, TransferBillsGetResult.class); + } + @Override public TransferBillsNotifyResult parseTransferBillsNotifyResult(String notifyData, SignatureHeader header) throws WxPayException { return this.payService.baseParseOrderNotifyV3Result(notifyData, header, TransferBillsNotifyResult.class, TransferBillsNotifyResult.DecryptNotifyResult.class); diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferServiceImplTest.java index cd607dff03caec89658aacddf804354b08cb5014..10c2a5da66c6cd8c07bb7ef24670ce6aec4811ee 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferServiceImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferServiceImplTest.java @@ -87,4 +87,19 @@ public class TransferServiceImplTest { .userName("测试用户").build(); log.info("发起商家转账:{}", this.payService.getTransferService().transferBills(transferBillsRequest)); } + + @Test + public void testTransformBillsCancel() throws WxPayException { + log.info("撤销商家转账:{}", this.payService.getTransferService().transformBillsCancel("123456")); + } + + @Test + public void testGetBillsByOutBillNo() throws WxPayException { + log.info("商户单号查询转账单:{}", this.payService.getTransferService().getBillsByOutBillNo("123456")); + } + + @Test + public void testGetBillsByTransferBillNo() throws WxPayException { + log.info("微信单号查询转账单:{}", this.payService.getTransferService().getBillsByTransferBillNo("123456")); + } }