| @@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.api; | |||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback; | import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback; | ||||
| import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderCloseResult; | |||||
| import me.chanjar.weixin.mp.bean.pay.request.WxEntPayRequest; | import me.chanjar.weixin.mp.bean.pay.request.WxEntPayRequest; | ||||
| import me.chanjar.weixin.mp.bean.pay.request.WxPayRefundRequest; | import me.chanjar.weixin.mp.bean.pay.request.WxPayRefundRequest; | ||||
| import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest; | import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest; | ||||
| @@ -35,6 +36,22 @@ public interface WxMpPayService { | |||||
| */ | */ | ||||
| WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException; | WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException; | ||||
| /** | |||||
| * <pre> | |||||
| * 关闭订单 | |||||
| * 应用场景 | |||||
| * 以下情况需要调用关单接口: | |||||
| * 1. 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付; | |||||
| * 2. 系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。 | |||||
| * 注意:订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟。 | |||||
| * 接口地址:https://api.mch.weixin.qq.com/pay/closeorder | |||||
| * 是否需要证书: 不需要。 | |||||
| * </pre> | |||||
| * @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。 | |||||
| * @throws WxErrorException | |||||
| */ | |||||
| WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorException; | |||||
| /** | /** | ||||
| * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) | * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) | ||||
| * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" | * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" | ||||
| @@ -8,6 +8,7 @@ import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||||
| import me.chanjar.weixin.mp.api.WxMpPayService; | import me.chanjar.weixin.mp.api.WxMpPayService; | ||||
| import me.chanjar.weixin.mp.api.WxMpService; | import me.chanjar.weixin.mp.api.WxMpService; | ||||
| import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback; | import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback; | ||||
| import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderCloseResult; | |||||
| import me.chanjar.weixin.mp.bean.pay.request.*; | import me.chanjar.weixin.mp.bean.pay.request.*; | ||||
| import me.chanjar.weixin.mp.bean.pay.result.*; | import me.chanjar.weixin.mp.bean.pay.result.*; | ||||
| import org.apache.commons.codec.digest.DigestUtils; | import org.apache.commons.codec.digest.DigestUtils; | ||||
| @@ -210,6 +211,39 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| return result; | return result; | ||||
| } | } | ||||
| @Override | |||||
| public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorException { | |||||
| if (StringUtils.isBlank(outTradeNo)) { | |||||
| throw new IllegalArgumentException("out_trade_no 不能为空"); | |||||
| } | |||||
| XStream xstream = XStreamInitializer.getInstance(); | |||||
| xstream.processAnnotations(WxPayOrderCloseRequest.class); | |||||
| xstream.processAnnotations(WxPayOrderCloseResult.class); | |||||
| WxPayOrderCloseRequest request = new WxPayOrderCloseRequest(); | |||||
| request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); | |||||
| request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId()); | |||||
| request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId()); | |||||
| request.setNonceStr(System.currentTimeMillis() + ""); | |||||
| String sign = this.createSign(BeanUtils.xmlBean2Map(request), | |||||
| this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | |||||
| request.setSign(sign); | |||||
| String url = PAY_BASE_URL + "/pay/closeorder"; | |||||
| String responseContent = this.wxMpService.post(url, xstream.toXML(request)); | |||||
| WxPayOrderCloseResult result = (WxPayOrderCloseResult) xstream.fromXML(responseContent); | |||||
| if ("FAIL".equals(result.getResultCode())) { | |||||
| throw new WxErrorException(WxError.newBuilder() | |||||
| .setErrorMsg(result.getErrCode() + ":" + result.getErrCodeDes()) | |||||
| .build()); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| @Override | @Override | ||||
| public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) | public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) | ||||
| throws WxErrorException { | throws WxErrorException { | ||||
| @@ -0,0 +1,36 @@ | |||||
| package me.chanjar.weixin.mp.bean.pay.request; | |||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||||
| /** | |||||
| * <pre> | |||||
| * 关闭订单请求对象类 | |||||
| * Created by Binary Wang on 2016-10-27. | |||||
| * @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("xml") | |||||
| public class WxPayOrderCloseRequest extends WxPayBaseRequest{ | |||||
| /** | |||||
| * <pre> | |||||
| * 商户订单号 | |||||
| * out_trade_no | |||||
| * 二选一 | |||||
| * String(32) | |||||
| * 20150806125346 | |||||
| * 商户系统内部的订单号,当没提供transaction_id时需要传这个。 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("out_trade_no") | |||||
| private String outTradeNo; | |||||
| public String getOutTradeNo() { | |||||
| return this.outTradeNo; | |||||
| } | |||||
| public void setOutTradeNo(String outTradeNo) { | |||||
| this.outTradeNo = outTradeNo; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,28 @@ | |||||
| package me.chanjar.weixin.mp.bean.pay.result; | |||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||||
| /** | |||||
| * <pre> | |||||
| * 关闭订单结果对象类 | |||||
| * Created by Binary Wang on 2016-10-27. | |||||
| * @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("xml") | |||||
| public class WxPayOrderCloseResult extends WxPayBaseResult { | |||||
| /** | |||||
| * 业务结果描述 | |||||
| */ | |||||
| @XStreamAlias("result_msg") | |||||
| private String resultMsg; | |||||
| public String getResultMsg() { | |||||
| return this.resultMsg; | |||||
| } | |||||
| public void setResultMsg(String resultMsg) { | |||||
| this.resultMsg = resultMsg; | |||||
| } | |||||
| } | |||||
| @@ -87,6 +87,15 @@ public class WxMpPayServiceImplTest { | |||||
| System.err.println(this.wxService.getPayService().queryOrder(null, "11111")); | System.err.println(this.wxService.getPayService().queryOrder(null, "11111")); | ||||
| } | } | ||||
| /** | |||||
| * Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#closeOrder(String)} . | |||||
| * @throws WxErrorException | |||||
| */ | |||||
| @Test | |||||
| public final void testCloseOrder() throws WxErrorException { | |||||
| System.err.println(this.wxService.getPayService().closeOrder("11212121")); | |||||
| } | |||||
| /** | /** | ||||
| * Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#entPay(WxEntPayRequest, File)}. | * Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#entPay(WxEntPayRequest, File)}. | ||||
| * @throws WxErrorException | * @throws WxErrorException | ||||