| @@ -0,0 +1,61 @@ | |||||
| package com.github.binarywang.wxpay.bean.result; | |||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||||
| import lombok.AllArgsConstructor; | |||||
| import lombok.Data; | |||||
| import lombok.NoArgsConstructor; | |||||
| /** | |||||
| * <pre> | |||||
| * 退款代金券信息. | |||||
| * Created by BinaryWang on 2018/4/21. | |||||
| * </pre> | |||||
| * | |||||
| * @author Binary Wang | |||||
| */ | |||||
| @Data | |||||
| @NoArgsConstructor | |||||
| @AllArgsConstructor | |||||
| public class WxPayRefundCouponInfo { | |||||
| /** | |||||
| * <pre> | |||||
| * 字段名:退款代金券ID. | |||||
| * 变量名:coupon_refund_id_$n_$m | |||||
| * 是否必填:否 | |||||
| * 类型:String(20) | |||||
| * 示例值:10000 | |||||
| * 描述:退款代金券ID, $n为下标,$m为下标,从0开始编号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("coupon_refund_id") | |||||
| private String couponRefundId; | |||||
| /** | |||||
| * <pre> | |||||
| * 字段名:单个退款代金券支付金额. | |||||
| * 变量名:coupon_refund_fee_$n_$m | |||||
| * 是否必填:否 | |||||
| * 类型:Int | |||||
| * 示例值:100 | |||||
| * 描述:单个退款代金券支付金额, $n为下标,$m为下标,从0开始编号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("coupon_refund_fee") | |||||
| private Integer couponRefundFee; | |||||
| /** | |||||
| * <pre> | |||||
| * 字段名:代金券类型. | |||||
| * 变量名:coupon_type_$n_$m | |||||
| * 是否必填:否 | |||||
| * 类型:String(8) | |||||
| * 示例值:CASH | |||||
| * 描述:CASH--充值代金券 , NO_CASH---非充值代金券。 | |||||
| * 开通免充值券功能,并且订单使用了优惠券后有返回(取值:CASH、NO_CASH)。 | |||||
| * $n为下标,$m为下标,从0开始编号,举例:coupon_type_$0_$1 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("coupon_type") | |||||
| private String couponType; | |||||
| } | |||||
| @@ -151,10 +151,10 @@ public class WxPayRefundQueryResult extends BaseWxPayResult { | |||||
| continue; | continue; | ||||
| } | } | ||||
| List<RefundRecord.RefundCoupon> coupons = Lists.newArrayList(); | |||||
| List<WxPayRefundCouponInfo> coupons = Lists.newArrayList(); | |||||
| for (int j = 0; j < refundRecord.getCouponRefundCount(); j++) { | for (int j = 0; j < refundRecord.getCouponRefundCount(); j++) { | ||||
| coupons.add( | coupons.add( | ||||
| new RefundRecord.RefundCoupon( | |||||
| new WxPayRefundCouponInfo( | |||||
| this.getXmlValue("xml/coupon_refund_id_" + i + "_" + j), | this.getXmlValue("xml/coupon_refund_id_" + i + "_" + j), | ||||
| this.getXmlValueAsInt("xml/coupon_refund_fee_" + i + "_" + j), | this.getXmlValueAsInt("xml/coupon_refund_fee_" + i + "_" + j), | ||||
| this.getXmlValue("xml/coupon_type_" + i + "_" + j) | this.getXmlValue("xml/coupon_type_" + i + "_" + j) | ||||
| @@ -277,7 +277,7 @@ public class WxPayRefundQueryResult extends BaseWxPayResult { | |||||
| @XStreamAlias("coupon_refund_count") | @XStreamAlias("coupon_refund_count") | ||||
| private Integer couponRefundCount; | private Integer couponRefundCount; | ||||
| private List<RefundCoupon> refundCoupons; | |||||
| private List<WxPayRefundCouponInfo> refundCoupons; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -323,54 +323,6 @@ public class WxPayRefundQueryResult extends BaseWxPayResult { | |||||
| @XStreamAlias("refund_success_time") | @XStreamAlias("refund_success_time") | ||||
| private String refundSuccessTime; | private String refundSuccessTime; | ||||
| @Data | |||||
| @NoArgsConstructor | |||||
| @AllArgsConstructor | |||||
| public static class RefundCoupon { | |||||
| /** | |||||
| * <pre> | |||||
| * 字段名:退款代金券ID. | |||||
| * 变量名:coupon_refund_id_$n_$m | |||||
| * 是否必填:否 | |||||
| * 类型:String(20) | |||||
| * 示例值:10000 | |||||
| * 描述:退款代金券ID, $n为下标,$m为下标,从0开始编号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("coupon_refund_id") | |||||
| private String couponRefundId; | |||||
| /** | |||||
| * <pre> | |||||
| * 字段名:单个退款代金券支付金额. | |||||
| * 变量名:coupon_refund_fee_$n_$m | |||||
| * 是否必填:否 | |||||
| * 类型:Int | |||||
| * 示例值:100 | |||||
| * 描述:单个退款代金券支付金额, $n为下标,$m为下标,从0开始编号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("coupon_refund_fee") | |||||
| private Integer couponRefundFee; | |||||
| /** | |||||
| * <pre> | |||||
| * 字段名:代金券类型. | |||||
| * 变量名:coupon_type_$n_$m | |||||
| * 是否必填:否 | |||||
| * 类型:String(8) | |||||
| * 示例值:CASH | |||||
| * 描述:CASH--充值代金券 , NO_CASH---非充值代金券。 | |||||
| * 开通免充值券功能,并且订单使用了优惠券后有返回(取值:CASH、NO_CASH)。 | |||||
| * $n为下标,$m为下标,从0开始编号,举例:coupon_type_$0_$1 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("coupon_type") | |||||
| private String couponType; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,67 +1,122 @@ | |||||
| package com.github.binarywang.wxpay.bean.result; | package com.github.binarywang.wxpay.bean.result; | ||||
| import com.google.common.collect.Lists; | |||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | import com.thoughtworks.xstream.annotations.XStreamAlias; | ||||
| import lombok.Data; | import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | import lombok.EqualsAndHashCode; | ||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||
| import java.io.Serializable; | import java.io.Serializable; | ||||
| import java.util.List; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 微信支付-申请退款返回结果 | |||||
| * 微信支付-申请退款返回结果. | |||||
| * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4 | * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4 | ||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @author liukaitj | |||||
| * @author liukaitj & Binary Wang | |||||
| */ | */ | ||||
| @Data | @Data | ||||
| @EqualsAndHashCode(callSuper = true) | @EqualsAndHashCode(callSuper = true) | ||||
| @NoArgsConstructor | @NoArgsConstructor | ||||
| @XStreamAlias("xml") | @XStreamAlias("xml") | ||||
| public class WxPayRefundResult extends BaseWxPayResult implements Serializable { | public class WxPayRefundResult extends BaseWxPayResult implements Serializable { | ||||
| private static final long serialVersionUID = 1L; | |||||
| @XStreamAlias("device_info") | |||||
| private String deviceInfo; | |||||
| private static final long serialVersionUID = -3392333879907788033L; | |||||
| /** | |||||
| * 微信订单号. | |||||
| */ | |||||
| @XStreamAlias("transaction_id") | @XStreamAlias("transaction_id") | ||||
| private String transactionId; | private String transactionId; | ||||
| /** | |||||
| * 商户订单号. | |||||
| */ | |||||
| @XStreamAlias("out_trade_no") | @XStreamAlias("out_trade_no") | ||||
| private String outTradeNo; | private String outTradeNo; | ||||
| /** | |||||
| * 商户退款单号. | |||||
| */ | |||||
| @XStreamAlias("out_refund_no") | @XStreamAlias("out_refund_no") | ||||
| private String outRefundNo; | private String outRefundNo; | ||||
| /** | |||||
| * 微信退款单号. | |||||
| */ | |||||
| @XStreamAlias("refund_id") | @XStreamAlias("refund_id") | ||||
| private String refundId; | private String refundId; | ||||
| @XStreamAlias("refund_channel") | |||||
| private String refundChannel; | |||||
| /** | |||||
| * 退款金额. | |||||
| */ | |||||
| @XStreamAlias("refund_fee") | @XStreamAlias("refund_fee") | ||||
| private String refundFee; | |||||
| private Integer refundFee; | |||||
| /** | |||||
| * 应结退款金额. | |||||
| */ | |||||
| @XStreamAlias("settlement_refund_fee") | |||||
| private Integer settlementRefundFee; | |||||
| /** | |||||
| * 标价金额. | |||||
| */ | |||||
| @XStreamAlias("total_fee") | @XStreamAlias("total_fee") | ||||
| private String totalFee; | |||||
| private Integer totalFee; | |||||
| /** | |||||
| * 应结订单金额. | |||||
| */ | |||||
| @XStreamAlias("settlement_total_fee") | |||||
| private Integer settlementTotalFee; | |||||
| /** | |||||
| * 标价币种. | |||||
| */ | |||||
| @XStreamAlias("fee_type") | @XStreamAlias("fee_type") | ||||
| private String feeType; | private String feeType; | ||||
| /** | |||||
| * 现金支付金额. | |||||
| */ | |||||
| @XStreamAlias("cash_fee") | @XStreamAlias("cash_fee") | ||||
| private String cashFee; | |||||
| private Integer cashFee; | |||||
| /** | |||||
| * 现金支付币种. | |||||
| */ | |||||
| @XStreamAlias("cash_fee_type") | |||||
| private String cashFeeType; | |||||
| /** | |||||
| * 现金退款金额. | |||||
| */ | |||||
| @XStreamAlias("cash_refund_fee") | @XStreamAlias("cash_refund_fee") | ||||
| private String cashRefundFee; | private String cashRefundFee; | ||||
| @XStreamAlias("coupon_refund_fee") | |||||
| private String couponRefundFee; | |||||
| /** | |||||
| * 退款代金券使用数量. | |||||
| */ | |||||
| @XStreamAlias("coupon_refund_count") | @XStreamAlias("coupon_refund_count") | ||||
| private String couponRefundCount; | |||||
| @XStreamAlias("coupon_refund_id") | |||||
| private String couponRefundId; | |||||
| private Integer couponRefundCount; | |||||
| private List<WxPayRefundCouponInfo> refundCoupons; | |||||
| /** | |||||
| * 组装生成退款代金券信息. | |||||
| */ | |||||
| public void composeRefundCoupons() { | |||||
| List<WxPayRefundCouponInfo> coupons = Lists.newArrayList(); | |||||
| for (int i = 0; i < this.getCouponRefundCount(); i++) { | |||||
| coupons.add( | |||||
| new WxPayRefundCouponInfo( | |||||
| this.getXmlValue("xml/coupon_refund_id_" + i), | |||||
| this.getXmlValueAsInt("xml/coupon_refund_fee_" + i), | |||||
| this.getXmlValue("xml/coupon_type_" + i) | |||||
| ) | |||||
| ); | |||||
| } | |||||
| this.setRefundCoupons(coupons); | |||||
| } | |||||
| } | } | ||||
| @@ -131,6 +131,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { | |||||
| String url = this.getPayBaseUrl() + "/secapi/pay/refund"; | String url = this.getPayBaseUrl() + "/secapi/pay/refund"; | ||||
| String responseContent = this.post(url, request.toXML(), true); | String responseContent = this.post(url, request.toXML(), true); | ||||
| WxPayRefundResult result = BaseWxPayResult.fromXML(responseContent, WxPayRefundResult.class); | WxPayRefundResult result = BaseWxPayResult.fromXML(responseContent, WxPayRefundResult.class); | ||||
| result.composeRefundCoupons(); | |||||
| result.checkResult(this, request.getSignType(), true); | result.checkResult(this, request.getSignType(), true); | ||||
| return result; | return result; | ||||
| } | } | ||||
| @@ -0,0 +1,51 @@ | |||||
| package com.github.binarywang.wxpay.bean.result; | |||||
| import org.testng.annotations.Test; | |||||
| import static org.assertj.core.api.Assertions.assertThat; | |||||
| /** | |||||
| * <pre> | |||||
| * Created by BinaryWang on 2018/4/22. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| public class WxPayRefundResultTest { | |||||
| @Test | |||||
| public void testComposeRefundCoupons() { | |||||
| /* | |||||
| 该xml字符串来自于官方文档示例,稍加改造,加上代金卷 | |||||
| refund_channel 是个什么鬼,官方文档只字不提 | |||||
| */ | |||||
| String xmlString = "<xml>\n" + | |||||
| " <return_code><![CDATA[SUCCESS]]></return_code>\n" + | |||||
| " <return_msg><![CDATA[OK]]></return_msg>\n" + | |||||
| " <appid><![CDATA[wx2421b1c4370ec43b]]></appid>\n" + | |||||
| " <mch_id><![CDATA[10000100]]></mch_id>\n" + | |||||
| " <nonce_str><![CDATA[NfsMFbUFpdbEhPXP]]></nonce_str>\n" + | |||||
| " <sign><![CDATA[B7274EB9F8925EB93100DD2085FA56C0]]></sign>\n" + | |||||
| " <result_code><![CDATA[SUCCESS]]></result_code>\n" + | |||||
| " <transaction_id><![CDATA[1008450740201411110005820873]]></transaction_id>\n" + | |||||
| " <out_trade_no><![CDATA[1415757673]]></out_trade_no>\n" + | |||||
| " <out_refund_no><![CDATA[1415701182]]></out_refund_no>\n" + | |||||
| " <refund_id><![CDATA[2008450740201411110000174436]]></refund_id>\n" + | |||||
| " <refund_channel><![CDATA[]]></refund_channel>\n" + | |||||
| " <coupon_refund_fee>1</coupon_refund_fee>\n" + | |||||
| " <coupon_refund_count>1</coupon_refund_count>\n" + | |||||
| " <coupon_refund_id_0>123</coupon_refund_id_0>\n" + | |||||
| " <coupon_refund_fee_0>1</coupon_refund_fee_0>\n" + | |||||
| " <coupon_type_0><![CDATA[CASH]]></coupon_type_0>\n" + | |||||
| " <refund_fee>2</refund_fee> \n" + | |||||
| "</xml>"; | |||||
| WxPayRefundResult result = WxPayRefundResult.fromXML(xmlString, WxPayRefundResult.class); | |||||
| result.composeRefundCoupons(); | |||||
| assertThat(result.getRefundCoupons()).isNotEmpty(); | |||||
| assertThat(result.getRefundCoupons().get(0).getCouponRefundId()).isEqualTo("123"); | |||||
| assertThat(result.getRefundCoupons().get(0).getCouponType()).isEqualTo("CASH"); | |||||
| assertThat(result.getRefundCoupons().get(0).getCouponRefundFee()).isEqualTo(1); | |||||
| } | |||||
| } | |||||