diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PartnerUserSignPlanDetail.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PartnerUserSignPlanDetail.java new file mode 100644 index 000000000..d006f15a0 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PartnerUserSignPlanDetail.java @@ -0,0 +1,94 @@ +package com.github.binarywang.wxpay.bean.payscore; + +import com.github.binarywang.wxpay.bean.payscore.enums.SignPlanServiceOrderPlanDetailStateEnum; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author UltramanNoa + * @className PartnerUserSignPlanDetail + * @description 签约计划明细列表 + * @createTime 2023/11/3 17:19 + **/ +@Data +@NoArgsConstructor +public class PartnerUserSignPlanDetail implements Serializable { + + private static final long serialVersionUID = 2089297485318293622L; + /** + * 计划明细序号 + */ + @SerializedName("plan_detail_no") + private Integer planDetailNo; + + /** + * 计划明细原支付金额(单位分) + */ + @SerializedName("original_price") + private Integer originalPrice; + + /** + * 计划明细优惠说明 + */ + @SerializedName("plan_discount_description") + private String planDiscountDescription; + + /** + * 计划明细实际支付金额(单位分) + */ + @SerializedName("actual_price") + private Integer actualPrice; + + /** + * 计划明细状态 + * + * @see SignPlanServiceOrderPlanDetailStateEnum + */ + @SerializedName("plan_detail_state") + private String planDetailState; + + /** + * 计划明细对应的支付分服务单号 + */ + @SerializedName("order_id") + private String orderId; + + /** + * 商户侧计划明细使用订单号 + */ + @SerializedName("merchant_plan_detail_no") + private String merchantPlanDetailNo; + + /** + * 计划详情名称 + */ + @SerializedName("plan_detail_name") + private Integer planDetailName; + + /** + * 计划明细对应订单实际支付金额(单位分) + */ + @SerializedName("actual_pay_price") + private Integer actualPayPrice; + + /** + * 详情使用时间 + */ + @SerializedName("use_time") + private String useTime; + + /** + * 详情完成时间 + */ + @SerializedName("complete_time") + private String completeTime; + + /** + * 详情取消时间 + */ + @SerializedName("cancel_time") + private String cancelTime; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PartnerUserSignPlanEntity.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PartnerUserSignPlanEntity.java new file mode 100644 index 000000000..60b789886 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PartnerUserSignPlanEntity.java @@ -0,0 +1,165 @@ +package com.github.binarywang.wxpay.bean.payscore; + +import com.github.binarywang.wxpay.bean.payscore.enums.SignPlanServiceOrderStateEnum; +import com.github.binarywang.wxpay.bean.payscore.enums.UserSignPlanCancelSignTypeEnum; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * @author UltramanNoa + * @className PartnerUserSignPlanEntity + * @description 用户的签约计划 + * @createTime 2023/11/3 16:05 + **/ +@Data +@NoArgsConstructor +public class PartnerUserSignPlanEntity implements Serializable { + + private static final long serialVersionUID = -662901613603698430L; + + public static PartnerUserSignPlanEntity fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, PartnerUserSignPlanEntity.class); + } + + + /** + * 待创建服务订单对应的用户的签约计划 + */ + @SerializedName("sign_plan_id") + private String signPlanId; + + @SerializedName("openid") + private String openid; + + /** + *
+ * 字段名:二级商户用户标识 + * 变量名:sub_openid + * 是否必填:否 + * 类型:string(128) + * 描述: + * 用户在二级商户appid下的唯一标识。 + * 示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o + *+ */ + @SerializedName(value = "sub_openid") + private String subOpenid; + + + @SerializedName("service_id") + private String serviceId; + + @SerializedName("mchid") + private String mchid; + + /** + * 子商户商户号 + */ + @SerializedName("sub_mchid") + private String subMchid; + + @SerializedName("appid") + private String appid; + + /** + * 子商户AppID + */ + @SerializedName("sub_appid") + private String subAppid; + + /** + * 商户签约计划单号 + */ + @SerializedName("merchant_sign_plan_no") + private String merchantSignPlanNo; + + /** + * 商户回调地址 + */ + @SerializedName("merchant_callback_url") + private String merchantCallbackUrl; + + /** + * 支付分计划ID + */ + @SerializedName("plan_id") + private String planId; + + /** + * 目前用户进行到的计划详情序号 + */ + @SerializedName("going_detail_no") + private Integer goingDetailNo; + + /** + * 计划签约状态 + * + * @see SignPlanServiceOrderStateEnum + */ + @SerializedName("sign_state") + private String signState; + + /** + * 签约计划取消时间 + */ + @SerializedName("cancel_sign_time") + private String cancelSignTime; + + /** + * 签约计划取消类型 + * + * @see UserSignPlanCancelSignTypeEnum + */ + @SerializedName("cancel_sign_type") + private String cancelSignType; + + /** + * 签约计划取消原因 + */ + @SerializedName("cancel_reason") + private String cancelReason; + + /** + * 签约计划的名称 + */ + @SerializedName("plan_name") + private String planName; + + /** + * 签约计划的过期时间 + */ + @SerializedName("plan_over_time") + private String planOverTime; + + /** + * 签约计划原总金额(单位分) + */ + @SerializedName("total_origin_price") + private Integer totalOriginPrice; + + /** + * 签约计划扣费次数 + */ + @SerializedName("deduction_quantity") + private Integer deductionQuantity; + + /** + * 签约计划实际总金额(单位分) + */ + @SerializedName("total_actual_price") + private Integer totalActualPrice; + + @SerializedName("signed_detail_list") + private List
2、解除授权成功通知的类型为PAYSCORE.USER_CLOSE_SERVICE
*3、用户确认成功通知的类型为PAYSCORE.USER_CONFIRM
*4、支付成功通知的类型为PAYSCORE.USER_PAID
+ *5、取消签约成功通知类型为PAYSCORE.USER_CANCEL_SIGN_PLAN
+ *6、签约计划成功通知类型为PAYSCORE
*/ @SerializedName("event_type") private String eventType; @@ -85,5 +87,11 @@ public class PayScoreNotifyData implements Serializable { */ @SerializedName("associated_data") private String associatedData; + + /** + * 原始回调类型,支付分的原始回调类型为payscore + */ + @SerializedName("original_type") + private String originalType; } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PayScorePlanDetail.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PayScorePlanDetail.java new file mode 100644 index 000000000..a0ed7ed12 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PayScorePlanDetail.java @@ -0,0 +1,49 @@ +package com.github.binarywang.wxpay.bean.payscore; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author UltramanNoa + * @className PayScorePlanDetail + * @description 支付分计划明细列表 + * @createTime 2023/11/3 11:22 + **/ +@Data +@NoArgsConstructor +public class PayScorePlanDetail implements Serializable { + + private static final long serialVersionUID = 999251141141181820L; + /** + * 计划明细原支付金额(单位分) + */ + @SerializedName("original_price") + private Integer originalPrice; + + /** + * 计划明细优惠说明 + */ + @SerializedName("plan_discount_description") + private String planDiscountDescription; + + /** + * 计划明细实际支付金额(单位分) + */ + @SerializedName("actual_price") + private String actualPrice; + + /** + * 计划明细名称 + */ + @SerializedName("plan_detail_name") + private String planDetailName; + + /** + * 计划明细序号(返回参数) + */ + @SerializedName("plan_detail_no") + private Integer planDetailNo; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/UserSignPlanDetailMerchatNo.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/UserSignPlanDetailMerchatNo.java new file mode 100644 index 000000000..bd081cec8 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/UserSignPlanDetailMerchatNo.java @@ -0,0 +1,32 @@ +package com.github.binarywang.wxpay.bean.payscore; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author UltramanNoa + * @className UserSignPlanDetailMerchatNo + * @description 签约计划对应的计划详情列表的商户侧单号信息 + * @createTime 2023/11/3 15:51 + **/ +@Data +@NoArgsConstructor +public class UserSignPlanDetailMerchatNo implements Serializable { + + private static final long serialVersionUID = 2668791598158720023L; + + /** + * 计划明细序号 + */ + @SerializedName("plan_detail_no") + private Integer planDetailNo; + + /** + * 商户侧计划明细使用订单号 + */ + @SerializedName("merchant_plan_detail_no") + private String merchantPlanDetailNo; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerPayScoreSignPlanRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerPayScoreSignPlanRequest.java new file mode 100644 index 000000000..02733e299 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerPayScoreSignPlanRequest.java @@ -0,0 +1,130 @@ +package com.github.binarywang.wxpay.bean.payscore; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.util.List; + +/** + * @author UltramanNoa + * @className WxPartnerPayScoreSignPlanRequest + * @description 支付分计划请求参数 + * @createTime 2023/11/3 09:54 + **/ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class WxPartnerPayScoreSignPlanRequest extends WxPayScoreRequest { + private static final long serialVersionUID = 6269843192878112955L; + + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + /** + * 子商户appid + */ + @SerializedName("sub_appid") + private String subAppid; + + /** + * 子商户mchid + */ + @SerializedName("sub_mchid") + private String subMchid; + + /** + * 子商户公众号下的用户标识 + */ + @SerializedName("sub_openid") + private String subOpenid; + /** + * 支付分计划名称 + */ + @SerializedName("plan_name") + private String planName; + + /** + * 支付分计划有效期(单位天) + */ + @SerializedName("plan_duration") + private Integer planDuration; + + /** + * 支付分计划扣费次数 + */ + @SerializedName("deduction_quantity") + private Integer deductionQuantity; + + + /** + * 支付分计划原总金额(单位分) + */ + @SerializedName("total_original_price") + private Integer totalOriginalPrice; + + /** + * 支付分计划实际扣费总金额(单位分) + */ + @SerializedName("total_actual_price") + private Integer totalActualPrice; + + /** + * 支付分计划明细列表 + */ + @SerializedName("plan_detail_list") + private List+ * @apiNote 微信支付分签约计划 + *+ **/ +public interface PartnerPayScoreSignPlanService { + + /** + *
+ * 文档更新时间:2023.10.13 + *
+ * 微信支付分签约计划是不同模式的支付分接口(随着国家大力推广教培行业先享后付政策,微信支付也紧跟政策于2023.07.25上线第一版签约计划接口以适用教培行业先享后付。于2023.10.13文档推至官网文档中心) + *
+ * 免确认/需确认 用服务商创单接口 {@link PartnerPayScoreService} 需要用户授权 + *
+ * 签约计划,用单独创单接口 {@link PartnerPayScoreSignPlanService} 不需要用户授权 + *
description:创建支付分计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 11:58
+ *version: v.1.0
+ * + * @param request {@link WxPartnerPayScoreSignPlanRequest} + * + * @return {@link WxPartnerPayScoreSignPlanResult} + * @apiNote 创建支付分计划 + **/ + WxPartnerPayScoreSignPlanResult createPlans(WxPartnerPayScoreSignPlanRequest request) throws WxPayException; + + /** + *description: 查询支付分计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 14:03
+ *version: v.1.0
+ * + * @param merchantPlanNo 路径参数:支付分计划商户侧单号 + * @param subMchid 子商户号 + * + * @return {@link WxPartnerPayScoreSignPlanResult} + * @apiNote 查询支付分计划 + **/ + WxPartnerPayScoreSignPlanResult queryPlans(@NonNull String merchantPlanNo, @NonNull String subMchid) throws WxPayException; + + /** + *description: 停止支付分计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 14:24
+ *version: v.1.0
+ * + * @param merchantPlanNo 路径参数:支付分计划商户侧单号 + * @param subMchid 子商户号 + * + * @return {@link WxPartnerPayScoreSignPlanResult} + * @apiNote 停止支付分计划 + **/ + WxPartnerPayScoreSignPlanResult stopPlans(@NonNull String merchantPlanNo, @NonNull String subMchid) throws WxPayException; + + /** + *description: 创建用户的签约计划详情对应的服务订单
+ *author:UltramanNoa
+ *create Time: 2023/11/3 14:53
+ *version: v.1.0
+ * + * @param request {@link WxPartnerPayScoreSignPlanRequest} + * + * @return {@link WxPartnerPayScoreSignPlanResult} + * @apiNote 创建用户的签约计划详情对应的服务订单 + **/ + WxPartnerPayScoreSignPlanResult signPlanServiceOrder(WxPartnerPayScoreSignPlanRequest request) throws WxPayException; + + /** + *description: 创建用户的签约计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 17:48
+ *version: v.1.0
+ * + * @param request {@link WxPartnerPayScoreSignPlanRequest} + * + * @return {@link WxPartnerPayScoreUserSignPlanResult} + * @apiNote 创建用户的签约计划 + **/ + WxPartnerPayScoreUserSignPlanResult createUserSignPlans(WxPartnerPayScoreSignPlanRequest request) throws WxPayException; + + /** + *description: 查询用户的签约计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 18:01
+ *version: v.1.0
+ * + * @param merchantSignPlanNo 路径参数 商户签约计划号 + * @param subMchid 子商户号 + * + * @return {@link PartnerUserSignPlanEntity} + * @apiNote 查询用户的签约计划 + **/ + PartnerUserSignPlanEntity queryUserSignPlans(@NonNull String merchantSignPlanNo, @NonNull String subMchid) throws WxPayException; + + /** + *description: 取消用户的签约计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 18:01
+ *version: v.1.0
+ * + * @param merchantSignPlanNo 路径参数 商户签约计划号 subMchid – 子商户号 + * @param subMchid 子商户号 + * @param stopReason 停止签约计划原因 + * + * @return {@link PartnerUserSignPlanEntity} + * @apiNote 取消用户的签约计划 + **/ + PartnerUserSignPlanEntity stopUserSignPlans(@NonNull String merchantSignPlanNo, @NonNull String subMchid, @NonNull String stopReason) throws WxPayException; + + /** + *description: 回调通知校验解密
+ *author:UltramanNoa
+ *create Time: 2023/11/6 10:27
+ *version: v.1.0
+ * @param + * @param notifyData + * @param header + * @return {@link PartnerUserSignPlanEntity} + **/ + PartnerUserSignPlanEntity parseSignPlanNotifyResult(String notifyData, SignatureHeader header) throws WxPayException; +} 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 f40d895f6..9aba25d04 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 @@ -11,6 +11,7 @@ import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.exception.WxPayException; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; + import java.io.File; import java.io.InputStream; import java.util.Date; @@ -1529,4 +1530,9 @@ public interface WxPayService { */ PartnerPayScoreService getPartnerPayScoreService(); + /** + * 获取服务商直股份签约计划服务类 + * @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 f08f014d3..121fd5ae0 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 @@ -119,6 +119,9 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { @Getter private final PartnerPayScoreService partnerPayScoreService = new PartnerPayScoreServiceImpl(this); + @Getter + private final PartnerPayScoreSignPlanService partnerPayScoreSignPlanService=new PartnerPayScoreSignPlanServiceImpl(this); + @Getter private final MerchantTransferService merchantTransferService = new MerchantTransferServiceImpl(this); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerPayScoreSignPlanServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerPayScoreSignPlanServiceImpl.java new file mode 100644 index 000000000..e81454bb7 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerPayScoreSignPlanServiceImpl.java @@ -0,0 +1,308 @@ +package com.github.binarywang.wxpay.service.impl; + +import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; +import com.github.binarywang.wxpay.bean.payscore.*; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.PartnerPayScoreService; +import com.github.binarywang.wxpay.service.PartnerPayScoreSignPlanService; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.v3.util.AesUtils; +import com.google.common.collect.Maps; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.utils.URIBuilder; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.util.Map; +import java.util.Objects; + + +/** + * @author UltramanNoa + * @className PartnerPayScoreSignPlanServiceImpl + * @description 微信支付分签约计划接口实现 + * @createTime 2023/11/3 09:23 + * + *+ * @apiNote 微信支付分签约计划 + *+ **/ +@RequiredArgsConstructor +public class PartnerPayScoreSignPlanServiceImpl implements PartnerPayScoreSignPlanService { + private static final Gson GSON = new GsonBuilder().create(); + private final WxPayService payService ; + + /** + *
+ * 文档更新时间:2023.10.13 + *
+ * 微信支付分签约计划是不同模式的支付分接口(随着国家大力推广教培行业先享后付政策,微信支付也紧跟政策于2023.07.25上线第一版签约计划接口以适用教培行业先享后付。于2023.10.13文档推至官网文档中心) + *
+ * 免确认/需确认 用服务商创单接口 {@link PartnerPayScoreService} 需要用户授权 + *
+ * 签约计划,用单独创单接口 {@link PartnerPayScoreSignPlanService} 不需要用户授权 + *
description:创建支付分计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 11:58
+ *version: v.1.0
+ * + * @param request {@link WxPartnerPayScoreSignPlanRequest} + * + * @return {@link WxPartnerPayScoreSignPlanResult} + * @apiNote 创建支付分计划 + **/ + @Override + public WxPartnerPayScoreSignPlanResult createPlans(WxPartnerPayScoreSignPlanRequest request) throws WxPayException { + String url = String.format("%s/v3/payscore/plan/partner/payscore-plans", payService.getPayBaseUrl()); + + if (StringUtils.isBlank(request.getAppid())) { + request.setAppid(payService.getConfig().getAppId()); + } + if (StringUtils.isBlank((request.getServiceId()))) { + request.setServiceId(payService.getConfig().getServiceId()); + } + + String result = payService.postV3(url, request.toJson()); + return WxPartnerPayScoreSignPlanResult.fromJson(result); + } + + /** + *description: 查询支付分计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 14:03
+ *version: v.1.0
+ * + * @param merchantPlanNo 路径参数:支付分计划商户侧单号 + * @param subMchid 子商户号 + * + * @return {@link WxPartnerPayScoreSignPlanResult} + * @apiNote 查询支付分计划 + **/ + @Override + public WxPartnerPayScoreSignPlanResult queryPlans(@NonNull String merchantPlanNo, @NonNull String subMchid) throws WxPayException { + String url = String.format("%s/v3/payscore/plan/partner/payscore-plans/merchant-plan-no/%s", payService.getPayBaseUrl(), merchantPlanNo); + + try { + URI uri = new URIBuilder(url) + .setParameter("sub_mchid", subMchid) + .build(); + + String result = payService.getV3(uri.toString()); + + return WxPartnerPayScoreSignPlanResult.fromJson(result); + } catch (URISyntaxException e) { + throw new WxPayException("未知异常!", e); + } + } + + /** + *description: 停止支付分计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 14:24
+ *version: v.1.0
+ * + * @param merchantPlanNo 路径参数:支付分计划商户侧单号 + * @param subMchid 子商户号 + * + * @return {@link WxPartnerPayScoreSignPlanResult} + * @apiNote 停止支付分计划 + **/ + @Override + public WxPartnerPayScoreSignPlanResult stopPlans(@NonNull String merchantPlanNo, @NonNull String subMchid) throws WxPayException { + String url = String.format("%s/v3/payscore/plan/partner/payscore-plans/merchant-plan-no/%s/stop", payService.getPayBaseUrl(), merchantPlanNo); + + Mapdescription: 创建用户的签约计划详情对应的服务订单
+ *author:UltramanNoa
+ *create Time: 2023/11/3 14:53
+ *version: v.1.0
+ * + * @param request {@link WxPartnerPayScoreSignPlanRequest} + * + * @return {@link WxPartnerPayScoreSignPlanResult} + * @apiNote 创建用户的签约计划详情对应的服务订单 + **/ + @Override + public WxPartnerPayScoreSignPlanResult signPlanServiceOrder(WxPartnerPayScoreSignPlanRequest request) throws WxPayException { + String url = String.format("%s/v3/payscore/sign-plan/partner/serviceorder", payService.getPayBaseUrl()); + + if (StringUtils.isBlank(request.getAppid())) { + request.setAppid(payService.getConfig().getAppId()); + } + if (StringUtils.isBlank((request.getServiceId()))) { + request.setServiceId(payService.getConfig().getServiceId()); + } + + String result = payService.postV3(url, request.toJson()); + return WxPartnerPayScoreSignPlanResult.fromJson(result); + } + + /** + *description: 创建用户的签约计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 17:48
+ *version: v.1.0
+ * + * @param request {@link WxPartnerPayScoreSignPlanRequest} + * + * @return {@link WxPartnerPayScoreUserSignPlanResult} + * @apiNote 创建用户的签约计划 + **/ + @Override + public WxPartnerPayScoreUserSignPlanResult createUserSignPlans(WxPartnerPayScoreSignPlanRequest request) throws WxPayException { + String url = String.format("%s/v3/payscore/sign-plan/partner/user-sign-plans", payService.getPayBaseUrl()); + + if (StringUtils.isBlank(request.getAppid())) { + request.setAppid(payService.getConfig().getAppId()); + } + if (StringUtils.isBlank((request.getServiceId()))) { + request.setServiceId(payService.getConfig().getServiceId()); + } + + String result = payService.postV3(url, request.toJson()); + return WxPartnerPayScoreUserSignPlanResult.fromJson(result); + } + + /** + *description: 查询用户的签约计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 18:01
+ *version: v.1.0
+ * + * @param merchantSignPlanNo 路径参数 商户签约计划号 + * @param subMchid 子商户号 + * + * @return {@link PartnerUserSignPlanEntity} + * @apiNote 查询用户的签约计划 + **/ + @Override + public PartnerUserSignPlanEntity queryUserSignPlans(@NonNull String merchantSignPlanNo, @NonNull String subMchid) throws WxPayException { + String url = String.format("%s/v3/payscore/sign-plan/partner/user-sign-plans/merchant-sign-plan-no/%s", payService.getPayBaseUrl(), merchantSignPlanNo); + + try { + URI uri = new URIBuilder(url) + .setParameter("sub_mchid", subMchid) + .build(); + + String result = payService.getV3(uri.toString()); + + return PartnerUserSignPlanEntity.fromJson(result); + } catch (URISyntaxException e) { + throw new WxPayException("未知异常!", e); + } + } + + /** + *description: 取消用户的签约计划
+ *author:UltramanNoa
+ *create Time: 2023/11/3 18:01
+ *version: v.1.0
+ * + * @param merchantSignPlanNo 路径参数 商户签约计划号 subMchid – 子商户号 + * @param subMchid 子商户号 + * @param stopReason 停止签约计划原因 + * + * @return {@link PartnerUserSignPlanEntity} + * @apiNote 取消用户的签约计划 + **/ + @Override + public PartnerUserSignPlanEntity stopUserSignPlans(@NonNull String merchantSignPlanNo, @NonNull String subMchid, @NonNull String stopReason) throws WxPayException { + String url = String.format("%s/v3/payscore/sign-plan/partner/user-sign-plans/merchant-sign-plan-no/%s/stop", payService.getPayBaseUrl(), merchantSignPlanNo); + + Mapdescription:回调通知
+ *author:UltramanNoa
+ *create Time: 2023/11/3 18:28
+ *version: v.1.0
+ * + * @param notifyData 回调参数 + * @param header 签名 + * + * @return {@link PartnerUserSignPlanEntity} + **/ + @Override + public PartnerUserSignPlanEntity parseSignPlanNotifyResult(String notifyData, SignatureHeader header) throws WxPayException { + PayScoreNotifyData response = parseNotifyData(notifyData, header); + return decryptNotifyDataResource(response); + } + + /** + *description: 检验并解析通知参数
+ *author:UltramanNoa
+ *create Time: 2023/11/3 18:30
+ *version: v.1.0
+ * @param data + * @param header + * @return {@link PayScoreNotifyData} + **/ + public PayScoreNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException { + if (Objects.nonNull(header) && !verifyNotifySign(header, data)) { + throw new WxPayException("非法请求,头部信息验证失败"); + } + return GSON.fromJson(data, PayScoreNotifyData.class); + } + + /** + *description: 解析回调通知参数
+ *author:UltramanNoa
+ *create Time: 2023/11/3 18:27
+ *version: v.1.0
+ * + * @param data {@link PayScoreNotifyData} + * + * @return {@link PartnerUserSignPlanEntity} + **/ + public PartnerUserSignPlanEntity decryptNotifyDataResource(PayScoreNotifyData data) throws WxPayException { + PayScoreNotifyData.Resource resource = data.getResource(); + String cipherText = resource.getCipherText(); + String associatedData = resource.getAssociatedData(); + String nonce = resource.getNonce(); + String apiV3Key = payService.getConfig().getApiV3Key(); + try { + return PartnerUserSignPlanEntity.fromJson(AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key)); + } catch (GeneralSecurityException | IOException e) { + throw new WxPayException("解析报文异常!", e); + } + } + + /** + * 校验通知签名 + * + * @param header 通知头信息 + * @param data 通知数据 + * + * @return true:校验通过 false:校验不通过 + */ + private boolean verifyNotifySign(SignatureHeader header, String data) { + String beforeSign = String.format("%s\n%s\n%s\n", header.getTimeStamp(), header.getNonce(), data); + return this.payService.getConfig().getVerifier().verify( + header.getSerialNo(), + beforeSign.getBytes(StandardCharsets.UTF_8), + header.getSigned() + ); + } +} diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/PartnerPayScoreSignPlanServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/PartnerPayScoreSignPlanServiceImplTest.java new file mode 100644 index 000000000..c10884049 --- /dev/null +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/PartnerPayScoreSignPlanServiceImplTest.java @@ -0,0 +1,76 @@ +package com.github.binarywang.wxpay.service.impl; + +import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanRequest; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.PartnerPayScoreSignPlanService; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.testbase.ApiTestModule; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +/** + * @className PartnerPayScoreSignPlanServiceImplTest + * @description + * @author + * @createTime 2023/11/6 10:30 + **/ +@Slf4j +@Test +@Guice(modules = ApiTestModule.class) +public class PartnerPayScoreSignPlanServiceImplTest { + @Inject + private WxPayService wxPayService; + + private static final Gson GSON = new GsonBuilder().create(); + + @Test + public void testcreatePlans()throws WxPayException{ + PartnerPayScoreSignPlanService scoreSignPlan=new PartnerPayScoreSignPlanServiceImpl(wxPayService); + WxPartnerPayScoreSignPlanRequest request=new WxPartnerPayScoreSignPlanRequest(); + request.setSubMchid("子商户号"); + scoreSignPlan.createPlans(request); + } + + @Test + public void testqueryPlans()throws WxPayException{ + PartnerPayScoreSignPlanService scoreSignPlan=new PartnerPayScoreSignPlanServiceImpl(wxPayService); + scoreSignPlan.queryPlans("merchantPlanNo","子商户号"); + } + + @Test + public void teststopPlans()throws WxPayException{ + PartnerPayScoreSignPlanService scoreSignPlan=new PartnerPayScoreSignPlanServiceImpl(wxPayService); + scoreSignPlan.stopPlans("merchantPlanNo","子商户号"); + } + + @Test + public void testsignPlanServiceOrder()throws WxPayException{ + PartnerPayScoreSignPlanService scoreSignPlan=new PartnerPayScoreSignPlanServiceImpl(wxPayService); + WxPartnerPayScoreSignPlanRequest request=new WxPartnerPayScoreSignPlanRequest(); + + scoreSignPlan.signPlanServiceOrder(request); + } + + @Test + public void testcreateUserSignPlans()throws WxPayException{ + PartnerPayScoreSignPlanService scoreSignPlan=new PartnerPayScoreSignPlanServiceImpl(wxPayService); + WxPartnerPayScoreSignPlanRequest request=new WxPartnerPayScoreSignPlanRequest(); + scoreSignPlan.createUserSignPlans(request); + } + + @Test + public void testqueryUserSignPlans()throws WxPayException{ + PartnerPayScoreSignPlanService scoreSignPlan=new PartnerPayScoreSignPlanServiceImpl(wxPayService); + scoreSignPlan.queryUserSignPlans("merchantPlanNo","子商户号"); + } + + @Test + public void teststopUserSignPlans()throws WxPayException{ + PartnerPayScoreSignPlanService scoreSignPlan=new PartnerPayScoreSignPlanServiceImpl(wxPayService); + scoreSignPlan.stopUserSignPlans("merchantPlanNo","子商户号","测试取消"); + } +}