From 86fc0712d052a11dfa99f2732ca3113e4b960cfe Mon Sep 17 00:00:00 2001 From: Kit Date: Mon, 16 Sep 2019 16:59:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E6=94=AF=E4=BB=98API=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=86=85=E5=AE=B9=E8=BF=81=E7=A7=BB=E5=88=B0=E6=96=B0?= =?UTF-8?q?=E7=9A=84=E5=AD=90=E6=A8=A1=E5=9D=97weixin4j-pay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin4j-pay/pom.xml | 46 + .../com/foxinmy/weixin4j/pay/api/MchApi.java | 138 +++ .../com/foxinmy/weixin4j/pay/api/PayApi.java | 775 ++++++++++++++++ .../weixin4j/pay/model/WeixinPayAccount.java | 190 ++++ .../weixin4j/pay/payment/JsPayNotify.java | 60 ++ .../weixin4j/pay/payment/PayBaseInfo.java | 116 +++ .../weixin4j/pay/payment/PayPackage.java | 284 ++++++ .../weixin4j/pay/payment/PayRequest.java | 75 ++ .../foxinmy/weixin4j/pay/payment/README.md | 47 + .../weixin4j/pay/payment/WeixinPayProxy.java | 827 ++++++++++++++++++ .../pay/payment/mch/APPPayRequest.java | 74 ++ .../pay/payment/mch/AbstractPayRequest.java | 28 + .../weixin4j/pay/payment/mch/CorpPayment.java | 147 ++++ .../pay/payment/mch/CorpPaymentRecord.java | 202 +++++ .../pay/payment/mch/CorpPaymentResult.java | 74 ++ .../pay/payment/mch/CustomsOrder.java | 217 +++++ .../pay/payment/mch/CustomsOrderRecord.java | 72 ++ .../pay/payment/mch/CustomsOrderResult.java | 123 +++ .../pay/payment/mch/JSAPIPayRequest.java | 50 ++ .../pay/payment/mch/MICROPayRequest.java | 75 ++ .../pay/payment/mch/MchPayPackage.java | 224 +++++ .../pay/payment/mch/MchPayRequest.java | 55 ++ .../pay/payment/mch/MerchantResult.java | 176 ++++ .../pay/payment/mch/MerchantTradeResult.java | 126 +++ .../pay/payment/mch/NATIVEPayRequest.java | 46 + .../pay/payment/mch/NativePayNotify.java | 54 ++ .../pay/payment/mch/NativePayResponse.java | 79 ++ .../pay/payment/mch/OpenIdResult.java | 52 ++ .../weixin4j/pay/payment/mch/Order.java | 247 ++++++ .../weixin4j/pay/payment/mch/PrePay.java | 79 ++ .../weixin4j/pay/payment/mch/Redpacket.java | 269 ++++++ .../pay/payment/mch/RedpacketRecord.java | 315 +++++++ .../pay/payment/mch/RedpacketRisk.java | 85 ++ .../pay/payment/mch/RedpacketSendResult.java | 102 +++ .../pay/payment/mch/RefundDetail.java | 218 +++++ .../pay/payment/mch/RefundRecord.java | 81 ++ .../pay/payment/mch/RefundResult.java | 128 +++ .../pay/payment/mch/SceneInfoApp.java | 99 +++ .../pay/payment/mch/SceneInfoStore.java | 75 ++ .../pay/payment/mch/SettlementRecord.java | 272 ++++++ .../pay/payment/mch/WAPPayRequest.java | 61 ++ .../pay/sign/AbstractWeixinSignature.java | 45 + .../pay/sign/WeixinPaymentSignature.java | 36 + .../weixin4j/pay/sign/WeixinSignature.java | 43 + .../foxinmy/weixin4j/pay/type/BankType.java | 260 ++++++ .../weixin4j/pay/type/CredentialType.java | 23 + .../weixin4j/pay/type/CurrencyType.java | 25 + .../weixin4j/pay/type/CustomsCity.java | 26 + .../weixin4j/pay/type/CustomsSatus.java | 24 + .../foxinmy/weixin4j/pay/type/IdQuery.java | 45 + .../com/foxinmy/weixin4j/pay/type/IdType.java | 46 + .../foxinmy/weixin4j/pay/type/SignType.java | 14 + .../foxinmy/weixin4j/pay/type/TarType.java | 14 + .../foxinmy/weixin4j/pay/type/TradeType.java | 33 + .../weixin4j/pay/type/mch/BillType.java | 34 + .../type/mch/CorpPaymentCheckNameType.java | 25 + .../weixin4j/pay/type/mch/CouponStatus.java | 34 + .../pay/type/mch/CouponStockStatus.java | 42 + .../pay/type/mch/CouponStockType.java | 30 + .../weixin4j/pay/type/mch/CouponType.java | 43 + .../pay/type/mch/RedpacketSceneType.java | 44 + .../pay/type/mch/RedpacketSendType.java | 25 + .../pay/type/mch/RedpacketStatus.java | 32 + .../weixin4j/pay/type/mch/RedpacketType.java | 21 + .../pay/type/mch/RefundAccountType.java | 18 + .../weixin4j/pay/type/mch/RefundChannel.java | 37 + .../weixin4j/pay/type/mch/RefundStatus.java | 34 + .../weixin4j/pay/type/mch/RefundType.java | 35 + 68 files changed, 7551 insertions(+) create mode 100644 weixin4j-pay/pom.xml create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/model/WeixinPayAccount.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/JsPayNotify.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayBaseInfo.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayPackage.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayRequest.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/README.md create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/WeixinPayProxy.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/APPPayRequest.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/AbstractPayRequest.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPayment.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentRecord.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentResult.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrder.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderRecord.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderResult.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/JSAPIPayRequest.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MICROPayRequest.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayRequest.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantResult.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantTradeResult.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NATIVEPayRequest.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayNotify.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayResponse.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/OpenIdResult.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Order.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/PrePay.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Redpacket.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRecord.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRisk.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketSendResult.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundDetail.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundRecord.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundResult.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SettlementRecord.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/WAPPayRequest.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/AbstractWeixinSignature.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinPaymentSignature.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinSignature.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/BankType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CredentialType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CurrencyType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsCity.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsSatus.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdQuery.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/SignType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TarType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/BillType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CorpPaymentCheckNameType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStatus.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockStatus.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSceneType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSendType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketStatus.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundAccountType.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundChannel.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundStatus.java create mode 100644 weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundType.java diff --git a/weixin4j-pay/pom.xml b/weixin4j-pay/pom.xml new file mode 100644 index 00000000..1104d1bd --- /dev/null +++ b/weixin4j-pay/pom.xml @@ -0,0 +1,46 @@ + + + + weixin4j + com.foxinmy + 1.9.0-SNAPSHOT + + 4.0.0 + weixin4j-pay + weixin4j-pay + https://github.com/foxinmy/weixin4j/tree/master/weixin4j-pay + 微信支付商户平台API + + + kit-lee + Kit lee + ryuji.cn@gmail.com + https://github.com/kit-lee + + kit_21cn@21cn.com + https://github.com/kit-lee/weixin4j + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.foxinmy + weixin4j-base + ${project.version} + + + junit + junit + + + \ No newline at end of file diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java new file mode 100644 index 00000000..104efa19 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/MchApi.java @@ -0,0 +1,138 @@ +package com.foxinmy.weixin4j.pay.api; + +import com.foxinmy.weixin4j.api.BaseApi; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.WeixinRequestExecutor; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; +import com.foxinmy.weixin4j.pay.sign.WeixinPaymentSignature; +import com.foxinmy.weixin4j.pay.type.IdQuery; +import com.foxinmy.weixin4j.pay.sign.WeixinSignature; +import com.foxinmy.weixin4j.util.RandomUtil; +import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.ResourceBundle; + +/** + * 商户支付 + * + * @className MchApi + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月26日 + * @since JDK 1.6 + * @see 商户支付平台 + */ +public class MchApi extends BaseApi { + private final static ResourceBundle WEIXIN_BUNDLE; + + private final static String PEM_CERT_PREFIX = "-----BEGIN CERTIFICATE-----"; + + static { + WEIXIN_BUNDLE = ResourceBundle.getBundle("com/foxinmy/weixin4j/payment/weixin"); + } + + protected final WeixinPayAccount weixinAccount; + protected final WeixinSignature weixinSignature; + private volatile WeixinRequestExecutor weixinSSLExecutor; + + public MchApi(WeixinPayAccount weixinAccount) { + this.weixinAccount = weixinAccount; + this.weixinSignature = new WeixinPaymentSignature(weixinAccount.getPaySignKey()); + } + + @Override + protected ResourceBundle weixinBundle() { + return WEIXIN_BUNDLE; + } + + /** + * 支付接口请求基本数据 + * + * @param idQuery + * ID信息 可为空 + * @return 基础map + */ + protected Map createBaseRequestMap(IdQuery idQuery) { + Map map = new HashMap(); + map.put("appid", weixinAccount.getId()); + map.put("mch_id", weixinAccount.getMchId()); + map.put("nonce_str", RandomUtil.generateString(16)); + if (StringUtil.isNotBlank(weixinAccount.getDeviceInfo())) { + map.put("device_info", weixinAccount.getDeviceInfo()); + } + if (StringUtil.isNotBlank(weixinAccount.getSubId())) { + map.put("sub_appid", weixinAccount.getSubId()); + } + if (StringUtil.isNotBlank(weixinAccount.getSubMchId())) { + map.put("sub_mch_id", weixinAccount.getSubMchId()); + } + if (idQuery != null) { + map.put(idQuery.getType().getName(), idQuery.getId()); + } + return map; + } + + /** + * 微信签名类 + * + * @return + */ + public WeixinSignature getWeixinSignature() { + return this.weixinSignature; + } + + /** + * 微信SSL + * + * @return + */ + protected WeixinRequestExecutor getWeixinSSLExecutor() throws WeixinException { + if (weixinSSLExecutor == null) { + if(weixinAccount.getCertificateFile().startsWith(PEM_CERT_PREFIX)){ + // 证书是PEM格式,直接使用PEM内容生成请求执行类 + this.weixinSSLExecutor = weixinExecutor.createSSLRequestExecutor(weixinAccount.getMchId(), + weixinAccount.getCertificateFile(), weixinAccount.getCertificateKey()); + }else { + // 证书是p12格式,读取证书文件并生成请求执行类 + try { + InputStream is = null; + File certificate = new File( + Weixin4jConfigUtil.replaceClassPathValue(weixinAccount.getCertificateFile())); + if (!certificate.exists() || !certificate.isFile()) { + is = Weixin4jConfigUtil.CLASSLOADER.getResourceAsStream(certificate.getName()); + } else { + is = new FileInputStream(certificate); + } + if (is == null) { + throw new WeixinException("Invalid certificate file : " + certificate.toString()); + } + this.weixinSSLExecutor = weixinExecutor.createSSLRequestExecutor(weixinAccount.getCertificateKey(), is); + } catch (IOException e) { + throw new WeixinException("IO Error on createSSLRequestExecutor", e); + } + } + } + return this.weixinSSLExecutor; + } + + /** + * 设置商户信息 + * + * @param merchant + */ + protected void declareMerchant(T merchant) { + merchant.setAppId(weixinAccount.getId()); + merchant.setMchId(weixinAccount.getMchId()); + merchant.setDeviceInfo(weixinAccount.getDeviceInfo()); + merchant.setSubAppId(weixinAccount.getSubId()); + merchant.setSubMchId(weixinAccount.getSubMchId()); + merchant.setNonceStr(RandomUtil.generateString(16)); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java new file mode 100644 index 00000000..0e7e7c0b --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/api/PayApi.java @@ -0,0 +1,775 @@ +package com.foxinmy.weixin4j.pay.api; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; +import com.foxinmy.weixin4j.http.weixin.XmlResult; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.mch.*; +import com.foxinmy.weixin4j.pay.type.mch.BillType; +import com.foxinmy.weixin4j.pay.type.mch.RefundAccountType; +import com.foxinmy.weixin4j.pay.type.*; +import com.foxinmy.weixin4j.util.*; +import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer; +import com.foxinmy.weixin4j.xml.XmlStream; + +import java.io.*; +import java.net.URLEncoder; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 支付API + * + * @className PayApi + * @author jinyu(foxinmy@gmail.com) + * @date 2014年10月28日 + * @since JDK 1.6 + */ +public class PayApi extends MchApi { + + public PayApi(WeixinPayAccount weixinAccount) { + super(weixinAccount); + } + + /** + * 统一下单接口
+ * 除被扫支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPI + * 、APP等不同场景生成交易串调起支付。 + * + * @param payPackage + * 包含订单信息的对象 + * @see MchPayPackage + * @see PrePay + * @see 统一下单接口 + * + * @return 预支付对象 + */ + public PrePay createPrePay(MchPayPackage payPackage) throws WeixinException { + super.declareMerchant(payPackage); + payPackage.setSign(weixinSignature.sign(payPackage)); + String payJsRequestXml = XmlStream.toXML(payPackage); + WeixinResponse response = weixinExecutor.post( + getRequestUri("order_create_uri"), payJsRequestXml); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 创建支付请求对象 + * + * @param payPackage + * 支付详情 + * @return 支付请求对象 + * @see JSAPIPayRequest JS支付 + * @see NATIVEPayRequest 扫码支付 + * @see MICROPayRequest 刷卡支付 + * @see APPPayRequest APP支付 + * @see WAPPayRequest WAP支付 + * @throws WeixinException + */ + public MchPayRequest createPayRequest(MchPayPackage payPackage) + throws WeixinException { + if (StringUtil.isBlank(payPackage.getTradeType())) { + throw new WeixinException("tradeType not be empty"); + } + String tradeType = payPackage.getTradeType().toUpperCase(); + if (TradeType.MICROPAY.name().equals(tradeType)) { + MchPayPackage _payPackage = new MchPayPackage(payPackage.getBody(), + payPackage.getDetail(), payPackage.getOutTradeNo(), + DateUtil.formatFee2Yuan(payPackage.getTotalFee()), null, + null, payPackage.getCreateIp(), null, null, + payPackage.getAuthCode(), null, payPackage.getAttach(), + null, null, payPackage.getGoodsTag(), + payPackage.getLimitPay(), payPackage.getSubAppId()); + super.declareMerchant(_payPackage); + _payPackage.setSign(weixinSignature.sign(_payPackage)); + String para = XmlStream.toXML(_payPackage); + WeixinResponse response = weixinExecutor.post( + getRequestUri("micropay_uri"), para); + MICROPayRequest microPayRequest = response + .getAsObject(new TypeReference() { + }); + microPayRequest.setPaymentAccount(weixinAccount); + return microPayRequest; + } + PrePay prePay = createPrePay(payPackage); + if (TradeType.APP.name().equals(tradeType)) { + return new APPPayRequest(prePay.getPrepayId(), weixinAccount); + } else if (TradeType.JSAPI.name().equals(tradeType)) { + return new JSAPIPayRequest(prePay.getPrepayId(), weixinAccount); + } else if (TradeType.NATIVE.name().equals(tradeType)) { + return new NATIVEPayRequest(prePay.getPrepayId(), + prePay.getPayUrl(), weixinAccount); + } else if (TradeType.MWEB.name().equals(tradeType)) { + return new WAPPayRequest(prePay.getPrepayId(), prePay.getPayUrl(), + weixinAccount); + } else { + throw new WeixinException("unknown tradeType:" + tradeType); + } + } + + /** + * 创建JSAPI支付请求对象 + * + * @param openId + * 用户ID + * @param body + * 订单描述 + * @param outTradeNo + * 订单号 + * @param totalFee + * 订单总额(元) + * @param notifyUrl + * 支付通知地址 + * @param createIp + * ip地址 + * @param attach + * 附加数据 非必填 + * @see JSAPIPayRequest + * @return JSAPI支付对象 + * @throws WeixinException + */ + public MchPayRequest createJSPayRequest(String openId, String body, + String outTradeNo, double totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, notifyUrl, createIp, TradeType.JSAPI, openId, null, + null, attach); + return createPayRequest(payPackage); + } + + /** + *

+ * 生成编辑地址请求 + *

+ * + * err_msg edit_address:ok获取编辑收货地址成功
edit_address:fail获取编辑收货地址失败
+ * userName 收货人姓名
telNumber 收货人电话
addressPostalCode 邮编
+ * proviceFirstStageName 国标收货地址第一级地址
addressCitySecondStageName + * 国标收货地址第二级地址
addressCountiesThirdStageName 国标收货地址第三级地址
+ * addressDetailInfo 详细收货地址信息
nationalCode 收货地址国家码
+ * + * @param url + * 当前访问页的URL + * @param oauthToken + * oauth授权时产生的token + * @see + * 收货地址共享 + * @return 编辑地址请求JSON串 + */ + public String createAddressRequestJSON(String url, String oauthToken) { + Map map = new HashMap(); + map.put("appId", weixinAccount.getId()); + map.put("timeStamp", DateUtil.timestamp2string()); + map.put("nonceStr", RandomUtil.generateString(16)); + map.put("url", url); + map.put("accessToken", oauthToken); + String sign = DigestUtil.SHA1(MapUtil.toJoinString(map, false, true)); + map.remove("url"); + map.remove("accessToken"); + map.put("scope", "jsapi_address"); + map.put("signType", SignType.SHA1.name().toLowerCase()); + map.put("addrSign", sign); + return JSON.toJSONString(map); + } + + /** + * 创建Native支付(扫码支付)链接【模式一】 + * + * @param productId + * 与订单ID等价 + * @return 支付链接 + * @see 扫码支付 + * + * @see 模式一 + * + */ + public String createNativePayRequest(String productId) { + Map map = new HashMap(); + String timestamp = DateUtil.timestamp2string(); + String noncestr = RandomUtil.generateString(16); + map.put("appid", weixinAccount.getId()); + map.put("mch_id", weixinAccount.getMchId()); + map.put("time_stamp", timestamp); + map.put("nonce_str", noncestr); + map.put("product_id", productId); + String sign = weixinSignature.sign(map); + return String.format(getRequestUri("native_pay_uri"), sign, + weixinAccount.getId(), weixinAccount.getMchId(), productId, + timestamp, noncestr); + } + + /** + * 创建Native支付(扫码支付)回调对象【模式一】 + * + * @param productId + * 商品ID + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return Native回调对象 + * @see NativePayResponse + * @see 扫码支付 + * + * @see 模式一 + * + * @throws WeixinException + */ + public NativePayResponse createNativePayResponse(String productId, + String body, String outTradeNo, double totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, notifyUrl, createIp, TradeType.NATIVE, null, null, + productId, attach); + PrePay prePay = createPrePay(payPackage); + return new NativePayResponse(weixinAccount, prePay.getPrepayId()); + } + + /** + * 创建Native支付(扫码支付)链接【模式二】 + * + * @param productId + * 商品ID + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return Native支付对象 + * @see NATIVEPayRequest + * @see 扫码支付 + * + * @see 模式二 + * + * @throws WeixinException + */ + public MchPayRequest createNativePayRequest(String productId, String body, + String outTradeNo, double totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, notifyUrl, createIp, TradeType.NATIVE, null, null, + productId, attach); + return createPayRequest(payPackage); + } + + /** + * 创建APP支付请求对象 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @param store + * 门店信息 非必填 + * @return APP支付对象 + * @see SceneInfoStore + * @see APPPayRequest + * @see + * APP支付 + * @throws WeixinException + */ + public MchPayRequest createAppPayRequest(String body, String outTradeNo, + double totalFee, String notifyUrl, String createIp, String attach, + SceneInfoStore store) throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, notifyUrl, createIp, TradeType.APP, null, null, null, + attach); + if (store != null) { + payPackage.setSceneInfo(String.format( + "{\"store_id\": \"%s\", \"store_name\":\"%s\"}", + store.getId(), store.getName())); + } + return createPayRequest(payPackage); + } + + /** + * 创建WAP支付请求对象:正常流程用户支付完成后会返回至发起支付的页面,如需返回至指定页面, + * 则可以在MWEB_URL后拼接上redirect_url参数,来指定回调页面 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @param app + * 应用信息 + * @return WAP支付对象 + * @see SceneInfoApp + * @see WAPPayRequest + * @see WAP支付 + * + * @throws WeixinException + */ + public MchPayRequest createWapPayRequest(String body, String outTradeNo, + double totalFee, String notifyUrl, String createIp, String attach, + SceneInfoApp app) throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, notifyUrl, createIp, TradeType.MWEB, null, null, + null, attach); + if (app != null) { + payPackage.setSceneInfo(String.format("{\"h5_info\":\"%s\"}", + app.getSceneInfo())); + } + return createPayRequest(payPackage); + } + + /** + * 提交被扫支付 + * + * @param authCode + * 扫码支付授权码 ,设备读取用户微信中的条码或者二维码信息 + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @param store + * 门店信息 非必填 + * @return 支付的订单信息 + * @see MICROPayRequest + * @see Order + * @see SceneInfoStore + * @see + * 提交被扫支付API + * @throws WeixinException + */ + public MchPayRequest createMicroPayRequest(String authCode, String body, + String outTradeNo, double totalFee, String createIp, String attach, + SceneInfoStore store) throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, null, createIp, TradeType.MICROPAY, null, authCode, + null, attach); + if (store != null) { + payPackage.setSceneInfo(String.format("{\"store_info\":\"%s\"}", + JSON.toJSONString(store))); + } + return createPayRequest(payPackage); + } + + /** + * 订单查询 + *

+ * 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
调用支付接口后,返回系统错误或未知交易状态情况;
+ * 调用被扫支付API,返回USERPAYING的状态;
调用关单或撤销接口API之前,需确认支付状态; + *

+ * + * @param idQuery + * 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @return 订单信息 + * @see Order + * @see + * 订单查询API + * @since V3 + * @throws WeixinException + */ + public Order queryOrder(IdQuery idQuery) throws WeixinException { + Map map = createBaseRequestMap(idQuery); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = weixinExecutor.post( + getRequestUri("order_query_uri"), param); + return ListsuffixResultDeserializer.deserialize(response.getAsString(), + Order.class); + } + + /** + * 申请退款(请求需要双向证书) + * + *

+ * 当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,微信支付将在收到退款请求并且验证成功之后, + * 按照退款规则将支付款按原路退到买家帐号上。 + *

+ * + *
    + *
  1. 交易时间超过一年的订单无法提交退款;
  2. + *
  3. + * 微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。 + * 申请退款总金额不能超过订单金额。 + * 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号。 + *
  4. + *
  5. + * 请求频率限制:150qps,即每秒钟正常的申请退款请求次数不超过150次。 + * 错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次。 + *
  6. + *
  7. 每个支付订单的部分退款次数不能超过50次。
  8. + *
+ * + * @param idQuery + * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @param outRefundNo + * 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔 + * @param totalFee + * 订单总金额,单位为元 + * @param refundFee + * 退款总金额,单位为元,可以做部分退款 + * @param refundFeeType + * 货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY + * @param opUserId + * 操作员帐号, 默认为商户号 + * @param refundDesc + * 退款原因,若商户传入,会在下发给用户的退款消息中体现退款原因 + * @param refundAccountType + * 退款资金来源,默认使用未结算资金退款:REFUND_SOURCE_UNSETTLED_FUNDS + * @return 退款申请结果 + * @see RefundResult + * @see + * 申请退款API + * @since V3 + * @throws WeixinException + */ + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, + double totalFee, double refundFee, CurrencyType refundFeeType, + String opUserId, String refundDesc, + RefundAccountType refundAccountType) throws WeixinException { + Map map = createBaseRequestMap(idQuery); + map.put("out_refund_no", outRefundNo); + map.put("total_fee", + Integer.toString(DateUtil.formatYuan2Fen(totalFee))); + map.put("refund_fee", + Integer.toString(DateUtil.formatYuan2Fen(refundFee))); + if (StringUtil.isBlank(opUserId)) { + opUserId = weixinAccount.getMchId(); + } + map.put("op_user_id", opUserId); + if (refundFeeType == null) { + refundFeeType = CurrencyType.CNY; + } + if (refundAccountType == null) { + refundAccountType = RefundAccountType.REFUND_SOURCE_UNSETTLED_FUNDS; + } + if (StringUtil.isNotBlank(refundDesc)) { + map.put("refund_desc", refundDesc); + } + map.put("refund_fee_type", refundFeeType.name()); + map.put("refund_account", refundAccountType.name()); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = getWeixinSSLExecutor().post( + getRequestUri("refund_apply_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 退款申请(全额退款) + * + * @param idQuery + * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @param outRefundNo + * 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔 + * @param totalFee + * 订单总金额,单位为元 + * @see #applyRefund(IdQuery, String, double, double, CurrencyType, String, String, RefundAccountType) + */ + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, + double totalFee) throws WeixinException { + return applyRefund(idQuery, outRefundNo, totalFee, totalFee, null, + null, null, null); + } + + /** + * 冲正订单(需要证书)
当支付返回失败,或收银系统超时需要取消交易,可以调用该接口
接口逻辑:支 + * 付失败的关单,支付成功的撤销支付
7天以内的单可撤销,其他正常支付的单 + * 如需实现相同功能请调用退款接口
调用扣款接口后请勿立即调用撤销,需要等待5秒以上。先调用查单接口,如果没有确切的返回,再调用撤销
+ * + * @param idQuery + * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @return 撤销结果 + * @since V3 + * @throws WeixinException + */ + public MerchantResult reverseOrder(IdQuery idQuery) throws WeixinException { + Map map = createBaseRequestMap(idQuery); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = getWeixinSSLExecutor().post( + getRequestUri("order_reverse_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * native支付URL转短链接:用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),减小二维码数据量 + * ,提升扫描速度和精确度。 + * + * @param url + * 具有native标识的支付URL + * @return 转换后的短链接 + * @throws WeixinException + * @see + * 转换短链接API + */ + public String getShorturl(String url) throws WeixinException { + Map map = createBaseRequestMap(null); + try { + map.put("long_url", URLEncoder.encode(url, Consts.UTF_8.name())); + } catch (UnsupportedEncodingException e) { + ; + } + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = weixinExecutor.post( + getRequestUri("longurl_convert_uri"), param); + map = XmlStream.xml2map(response.getAsString()); + return map.get("short_url"); + } + + /** + * 关闭订单 + *

+ * 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续 + * ,请调用关单接口,如果关单失败,返回已完 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。 + *

+ * + * @param outTradeNo + * 商户系统内部的订单号 + * @return 处理结果 + * @since V3 + * @throws WeixinException + * @see + * 关闭订单API + */ + public MerchantResult closeOrder(String outTradeNo) throws WeixinException { + Map map = createBaseRequestMap(new IdQuery(outTradeNo, + IdType.TRADENO)); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = weixinExecutor.post( + getRequestUri("order_close_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 下载对账单
+ * 1.微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账 单中,跟原支付单订单号一致,bill_type 为 + * REVOKED;
+ * 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;
+ * 3.对账单中涉及金额的字段单位为“元”。
+ * + * @param billDate + * 下载对账单的日期 + * @param billType + * 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单 + * REFUND,返回当日退款订单 + * @param outputStream + * 输出流 + * @param tarType + * 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。 + * @since V3 + * @see + * 下载对账单API + * @throws WeixinException + */ + public void downloadBill(Date billDate, BillType billType, + OutputStream outputStream, TarType tarType) throws WeixinException { + if (billDate == null) { + Calendar now = Calendar.getInstance(); + now.add(Calendar.DAY_OF_MONTH, -1); + billDate = now.getTime(); + } + if (billType == null) { + billType = BillType.ALL; + } + String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate); + Map map = createBaseRequestMap(null); + map.put("bill_date", formatBillDate); + map.put("bill_type", billType.name()); + if (tarType != null) { + map.put("tar_type", tarType.name()); + } + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = weixinExecutor.post( + getRequestUri("downloadbill_uri"), param); + + if (TarType.GZIP == tarType) { + try { + IOUtil.copy(response.getBody(), outputStream); + } catch (IOException e) { + ; + } + } else { + BufferedReader reader = null; + BufferedWriter writer = null; + try { + writer = new BufferedWriter(new OutputStreamWriter( + outputStream, Consts.UTF_8)); + reader = new BufferedReader(new InputStreamReader( + response.getBody(), Consts.UTF_8)); + String line = null; + while ((line = reader.readLine()) != null) { + writer.write(line); + writer.newLine(); + } + } catch (IOException e) { + throw new WeixinException(e); + } finally { + try { + if (reader != null) { + reader.close(); + } + if (writer != null) { + writer.close(); + } + } catch (IOException ignore) { + ; + } + } + } + } + + /** + * 退款查询 + * + *

+ * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。 + *

+ * + * @param idQuery + * 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id + * 四个参数必填一个,优先级为: + * refund_id>out_refund_no>transaction_id>out_trade_no + * @return 退款记录 + * @see RefundRecord + * @see com.foxinmy.weixin4j.payment.mch.RefundDetail + * @see + * 退款查询API + * @since V3 + * @throws WeixinException + */ + public RefundRecord queryRefund(IdQuery idQuery) throws WeixinException { + Map map = createBaseRequestMap(idQuery); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = weixinExecutor.post( + getRequestUri("refund_query_uri"), param); + return ListsuffixResultDeserializer.deserialize(response.getAsString(), + RefundRecord.class); + } + + /** + * 接口上报 + * + * @param interfaceUrl + * 上报对应的接口的完整 URL, 类似: https://api.mch.weixin.q + * q.com/pay/unifiedorder + * @param executeTime + * 接口耗时情况,单位为毫秒 + * @param outTradeNo + * 商户系统内部的订单号,商 户可以在上报时提供相关商户订单号方便微信支付更好 的提高服务质量。 + * @param ip + * 发起接口调用时的机器 IP + * @param time + * 商户调用该接口时商户自己 系统的时间 + * @param returnXml + * 调用接口返回的基本数据 + * @return 处理结果 + * @throws WeixinException + * @see + * 交易保障 + */ + @SuppressWarnings("unchecked") + public XmlResult reportInterface(String interfaceUrl, int executeTime, + String outTradeNo, String ip, Date time, XmlResult returnXml) + throws WeixinException { + Map map = createBaseRequestMap(null); + map.put("interface_url", interfaceUrl); + map.put("execute_time_", Integer.toString(executeTime)); + map.put("out_trade_no", outTradeNo); + map.put("user_ip", ip); + map.put("time", DateUtil.fortmat2yyyyMMddHHmmss(time)); + map.putAll((Map) JSON.toJSON(returnXml)); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = weixinExecutor.post( + getRequestUri("interface_report_uri"), param); + return response.getAsXml(); + } + + /** + * 授权码查询OPENID接口 + * + * @param authCode + * 扫码支付授权码,设备读取用户微信中的条码或者二维码信息 + * @return 查询结果 + * @see OpenIdResult + * @see + * 授权码查询OPENID + * @throws WeixinException + */ + public OpenIdResult authCode2openId(String authCode) throws WeixinException { + Map map = createBaseRequestMap(null); + map.put("auth_code", authCode); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = weixinExecutor.post( + getRequestUri("authcode_openid_uri"), param); + return response.getAsObject(new TypeReference() { + }); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/model/WeixinPayAccount.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/model/WeixinPayAccount.java new file mode 100644 index 00000000..d6dc9fc2 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/model/WeixinPayAccount.java @@ -0,0 +1,190 @@ +package com.foxinmy.weixin4j.pay.model; + +import com.alibaba.fastjson.annotation.JSONCreator; +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.model.WeixinAccount; +import com.foxinmy.weixin4j.util.StringUtil; + +/** + * 微信支付账户 + * + * @className WeixinPayAccount + * @author jinyu(foxinmy@gmail.com) + * @date 2015年6月26日 + * @since JDK 1.6 + * @see + */ +public class WeixinPayAccount extends WeixinAccount { + + private static final long serialVersionUID = -2791256176906048632L; + /** + * 公众号支付请求中用于加密的密钥 + */ + private final String paySignKey; + /** + * 微信支付分配的商户号 + */ + private final String mchId; + /** + * 加载支付证书文件的密码(默认为商户号) + */ + private String certificateKey; + /** + * 商户证书文件(默认加载classpath:ca.p12) + */ + private String certificateFile; + /** + * 微信支付分配的设备号 + */ + private String deviceInfo; + /** + * 财付通商户身份的标识 + */ + private String partnerId; + + /** + * 微信分配的子商户公众账号ID + */ + private String subId; + /** + * 微信支付分配的子商户号 + */ + private String subMchId; + + /** + * 支付商户信息 + * + * @param id + * 公众号唯一的身份ID(必填) + * @param paySignKey + * 支付密钥字符串(必填) + * @param mchId + * 微信支付分配的商户号(必填) + */ + public WeixinPayAccount(String id, String paySignKey, String mchId) { + this(id, paySignKey, mchId, mchId, "classpath:ca.p12"); + } + + /** + * 支付商户信息 + * + * @param id + * 公众号唯一的身份ID(必填) + * @param paySignKey + * 支付密钥字符串(必填) + * @param mchId + * 微信支付分配的商户号(必填) + * @param certificateKey + * 加载支付证书文件的密码(默认为商户号) + * @param certificateFile + * 商户证书文件(默认加载classpath:ca.p12) + */ + public WeixinPayAccount(String id, String paySignKey, String mchId, String certificateKey, String certificateFile) { + this(id, null, paySignKey, mchId, certificateKey, certificateFile, null, null, null, null); + } + + /** + * 支付商户信息 + * + * @param id + * 公众号唯一的身份ID(必填) + * @param secret + * 公众号调用接口的凭证(最好填写) + * @param paySignKey + * 支付密钥字符串(必填) + * @param mchId + * 微信支付分配的商户号(必填) + * @param certificateKey + * 加载支付证书文件的密码(默认为商户号) + * @param certificateFile + * 商户证书文件(默认加载classpath:ca.p12) + * @param deviceInfo + * 微信支付分配的设备号(非必填) + * @param partnerId + * 财付通的商户号(非必填) + * @param subId + * 微信分配的子商户公众账号ID(非必填) + * @param subMchId + * 微信支付分配的子商户号(非必填) + */ + @JSONCreator + public WeixinPayAccount(@JSONField(name = "id") String id, @JSONField(name = "secret") String secret, + @JSONField(name = "paySignKey") String paySignKey, @JSONField(name = "mchId") String mchId, + @JSONField(name = "certificateKey") String certificateKey, + @JSONField(name = "certificateFile") String certificateFile, + @JSONField(name = "deviceInfo") String deviceInfo, @JSONField(name = "partnerId") String partnerId, + @JSONField(name = "subId") String subId, @JSONField(name = "subMchId") String subMchId) { + super(id, secret); + this.paySignKey = paySignKey; + this.mchId = mchId; + this.certificateKey = certificateKey; + this.certificateFile = certificateFile; + this.deviceInfo = deviceInfo; + this.partnerId = partnerId; + this.subId = subId; + this.subMchId = subMchId; + } + + public String getPaySignKey() { + return paySignKey; + } + + public String getMchId() { + return mchId; + } + + public String getDeviceInfo() { + return deviceInfo; + } + + public String getCertificateKey() { + return StringUtil.isBlank(certificateKey) ? mchId : certificateKey; + } + + public String getPartnerId() { + return partnerId; + } + + public String getSubId() { + return subId; + } + + public String getSubMchId() { + return subMchId; + } + + public void setCertificateKey(String certificateKey) { + this.certificateKey = certificateKey; + } + + public String getCertificateFile() { + return certificateFile; + } + + public void setCertificateFile(String certificateFile) { + this.certificateFile = certificateFile; + } + + public void setDeviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + } + + public void setPartnerId(String partnerId) { + this.partnerId = partnerId; + } + + public void setSubId(String subId) { + this.subId = subId; + } + + public void setSubMchId(String subMchId) { + this.subMchId = subMchId; + } + + @Override + public String toString() { + return "WeixinPayAccount [" + super.toString() + ", paySignKey=" + paySignKey + ", mchId=" + mchId + + ", certificateKey=" + certificateKey + ",certificateFile =" + certificateFile + ", deviceInfo=" + + deviceInfo + ", partnerId=" + partnerId + ", subId=" + subId + ", subMchId=" + subMchId + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/JsPayNotify.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/JsPayNotify.java new file mode 100644 index 00000000..14af1807 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/JsPayNotify.java @@ -0,0 +1,60 @@ +package com.foxinmy.weixin4j.pay.payment; + +import com.alibaba.fastjson.annotation.JSONField; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * JSAPI支付回调时的POST信息 + * + * @className JsPayNotify + * @author jinyu(foxinmy@gmail.com) + * @date 2014年8月19日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class JsPayNotify extends PayBaseInfo { + + private static final long serialVersionUID = -4659030958445259803L; + + /** + * 用户的openid + */ + @JSONField(name = "OpenId") + @XmlElement(name = "OpenId") + private String openId; + /** + * 是否关注公众号 + */ + @JSONField(name = "IsSubscribe") + @XmlElement(name = "IsSubscribe") + private int isSubscribe; + + public JsPayNotify() { + + } + + public String getOpenId() { + return openId; + } + + public int getIsSubscribe() { + return isSubscribe; + } + + @JSONField(serialize = false) + public boolean getFormatIsSubscribe() { + return isSubscribe == 1; + } + + @Override + public String toString() { + return "openId=" + openId + ", isSubscribe=" + getFormatIsSubscribe() + + ", " + super.toString(); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayBaseInfo.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayBaseInfo.java new file mode 100644 index 00000000..a38eaab2 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayBaseInfo.java @@ -0,0 +1,116 @@ +package com.foxinmy.weixin4j.pay.payment; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.type.SignType; + +import javax.xml.bind.annotation.*; +import java.io.Serializable; + +/** + * 基本信息 + * + * @className PayBaseInfo + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月5日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class PayBaseInfo implements Serializable { + + private static final long serialVersionUID = 1843024880782466990L; + + /** + * 公众号ID + */ + @JSONField(name = "appId") + @XmlElement(name = "AppId") + private String appId; + /** + * 时间戳 + */ + @JSONField(name = "timeStamp") + @XmlElement(name = "TimeStamp") + private String timeStamp; + /** + * 随机字符串 + */ + @JSONField(name = "nonceStr") + @XmlElement(name = "NonceStr") + private String nonceStr; + /** + * 签名结果 + */ + @JSONField(name = "paySign") + @XmlElement(name = "AppSignature") + private String paySign; + /** + * 签名方式 + */ + @JSONField(name = "signType") + @XmlElement(name = "SignMethod") + private String signType; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + public String getNonceStr() { + return nonceStr; + } + + public void setNonceStr(String nonceStr) { + this.nonceStr = nonceStr; + } + + public String getPaySign() { + return paySign; + } + + public void setPaySign(String paySign) { + this.paySign = paySign; + } + + public String getSignType() { + return signType; + } + + @XmlTransient + @JSONField(serialize = false) + public SignType getFormatSignType() { + return signType != null ? SignType.valueOf(signType.toUpperCase()) + : null; + } + + public void setSignType(SignType signType) { + this.signType = signType != null ? signType.name() : null; + } + + public PayBaseInfo() { + } + + public PayBaseInfo(String appId, String timestamp, String noncestr) { + this.appId = appId; + this.timeStamp = timestamp; + this.nonceStr = noncestr; + } + + @Override + public String toString() { + return "appId=" + appId + ", timeStamp=" + timeStamp + ", nonceStr=" + + nonceStr + ", paySign=" + paySign + ", signType=" + signType; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayPackage.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayPackage.java new file mode 100644 index 00000000..e652828f --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayPackage.java @@ -0,0 +1,284 @@ +package com.foxinmy.weixin4j.pay.payment; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.Date; + +/** + * 订单信息 + * + * @className PayPackage + * @author jinyu(foxinmy@gmail.com) + * @date 2014年12月18日 + * @since JDK 1.6 + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class PayPackage extends MerchantResult { + + private static final long serialVersionUID = 3450161267802545790L; + + /** + * 商品描述 必须 + */ + private String body; + /** + * 商品详情 非必须 + */ + private String detail; + /** + * 商户系统内部的订单号 ,32 个字符内 、可包含字母 ,确保 在商户系统唯一 必须 + */ + @XmlElement(name = "out_trade_no") + @JSONField(name = "out_trade_no") + private String outTradeNo; + /** + * 订单总金额,单位为分,不能带小数点 必须 + */ + @XmlElement(name = "total_fee") + @JSONField(name = "total_fee") + private int totalFee; + /** + * 通知地址接收微信支付成功通知 必须 + */ + @XmlElement(name = "notify_url") + @JSONField(name = "notify_url") + private String notifyUrl; + /** + * 订单生成的机器 IP 必须 + */ + @XmlElement(name = "spbill_create_ip") + @JSONField(name = "spbill_create_ip") + private String createIp; + /** + * 附加数据,原样返回 非必须 + */ + private String attach; + /** + * 订单生成时间,格式为 yyyyMMddHHmmss,如 2009 年 12月25日9点10分10秒表示为 20091225091010。时区 为 + * GMT+8 beijing。该时间取 自商户服务器 非必须 + */ + @XmlElement(name = "time_start") + @JSONField(name = "time_start") + private String timeStart; + /** + * 订单失效时间,格为 yyyyMMddHHmmss,如 2009 年 12月27日9点10分10秒表示为 20091227091010。时区 为 + * GMT+8 beijing。该时间取 自商户服务商品标记 非必须 + */ + @XmlElement(name = "time_expire") + @JSONField(name = "time_expire") + private String timeExpire; + /** + * 商品标记,该字段不能随便填,不使用请填空 非必须 + */ + @XmlElement(name = "goods_tag") + @JSONField(name = "goods_tag") + private String goodsTag; + + protected PayPackage() { + // jaxb required + } + + /** + * 订单对象 + * + * @param body + * 订单描述 必填 + * @param detail + * 订单详情 非必填 + * @param outTradeNo + * 商户内部ID 必填 + * @param totalFee + * 订单总额 必填 单位为元 + * @param notifyUrl + * 回调地址 必填 + * @param createIp + * 生成订单数据的机器IP 必填 + * @param attach + * 附加数据 非必填 + * @param timeStart + * 订单生成时间 非必填 + * @param timeExpire + * 订单失效时间 非必填 + * @param goodsTag + * 订单标记 非必填 + */ + public PayPackage(String body, String detail, String outTradeNo, + double totalFee, String notifyUrl, String createIp, String attach, + Date timeStart, Date timeExpire, String goodsTag) { + this.body = body; + this.detail = detail; + this.outTradeNo = outTradeNo; + this.totalFee = DateUtil.formatYuan2Fen(totalFee); + this.notifyUrl = notifyUrl; + this.createIp = createIp; + this.attach = attach; + this.timeStart = timeStart != null ? DateUtil + .fortmat2yyyyMMddHHmmss(timeStart) : null; + this.timeExpire = timeExpire != null ? DateUtil + .fortmat2yyyyMMddHHmmss(timeExpire) : null; + this.goodsTag = goodsTag; + } + + /** + * 订单对象 + * + * @param body + * 订单描述 必填 + * @param detail + * 订单详情 非必填 + * @param outTradeNo + * 商户内部ID 必填 + * @param totalFee + * 订单总额 必填 单位为分 + * @param notifyUrl + * 回调地址 必填 + * @param createIp + * 生成订单数据的机器IP 必填 + * @param attach + * 附加数据 非必填 + * @param timeStart + * 订单生成时间 非必填 + * @param timeExpire + * 订单失效时间 非必填 + * @param goodsTag + * 订单标记 非必填 + */ + public PayPackage(String body, String detail, String outTradeNo, + long totalFee, String notifyUrl, String createIp, String attach, + Date timeStart, Date timeExpire, String goodsTag) { + this.body = body; + this.detail = detail; + this.outTradeNo = outTradeNo; + this.totalFee = Long.valueOf(totalFee).intValue(); + this.notifyUrl = notifyUrl; + this.createIp = createIp; + this.attach = attach; + this.timeStart = timeStart != null ? DateUtil + .fortmat2yyyyMMddHHmmss(timeStart) : null; + this.timeExpire = timeExpire != null ? DateUtil + .fortmat2yyyyMMddHHmmss(timeExpire) : null; + this.goodsTag = goodsTag; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public void setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + } + + public int getTotalFee() { + return totalFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatTotalFee() { + return totalFee / 100d; + } + + /** + * 单位为元,自动格式化为分 + * + * @param totalFee + * 订单总额 单位为元 + */ + public void setTotalFee(double totalFee) { + this.totalFee = DateUtil.formatYuan2Fen(totalFee); + } + + public String getNotifyUrl() { + return notifyUrl; + } + + public void setNotifyUrl(String notifyUrl) { + this.notifyUrl = notifyUrl; + } + + public String getCreateIp() { + return createIp; + } + + public void setCreateIp(String createIp) { + this.createIp = createIp; + } + + public String getAttach() { + return attach; + } + + public void setAttach(String attach) { + this.attach = attach; + } + + public String getTimeStart() { + return timeStart; + } + + public void setTimeStart(String timeStart) { + this.timeStart = timeStart; + } + + public void setTimeExpire(String timeExpire) { + this.timeExpire = timeExpire; + } + + public void setTimeStart(Date timeStart) { + this.timeStart = timeStart != null ? DateUtil + .fortmat2yyyyMMddHHmmss(timeStart) : null; + } + + public String getTimeExpire() { + return timeExpire; + } + + public void setTimeExpire(Date timeExpire) { + this.timeExpire = timeExpire != null ? DateUtil + .fortmat2yyyyMMddHHmmss(timeExpire) : null; + } + + public String getGoodsTag() { + return goodsTag; + } + + public void setGoodsTag(String goodsTag) { + this.goodsTag = goodsTag; + } + + @Override + public String toString() { + return "body=" + body + ", detail=" + detail + ", outTradeNo=" + + outTradeNo + ", totalFee=" + totalFee + ", notifyUrl=" + + notifyUrl + ", createIp=" + createIp + ", attach=" + attach + + ", timeStart=" + timeStart + ", timeExpire=" + timeExpire + + ", goodsTag=" + goodsTag; + } +} \ No newline at end of file diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayRequest.java new file mode 100644 index 00000000..365bf49c --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/PayRequest.java @@ -0,0 +1,75 @@ +package com.foxinmy.weixin4j.pay.payment; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.util.DateUtil; +import com.foxinmy.weixin4j.util.RandomUtil; + +import javax.xml.bind.annotation.*; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class PayRequest extends PayBaseInfo { + + private static final long serialVersionUID = -453746488398523883L; + + /** + * 订单详情扩展 订单信息组成该字符串 + */ + @XmlElement(name = "Package") + @JSONField(name = "package") + private String packageInfo; + + /** + * 冗余字段 + */ + @XmlTransient + @JSONField(serialize = false) + private String prepayId; + /** + * 冗余字段 + */ + @XmlTransient + @JSONField(serialize = false) + private String partnerId; + + + protected PayRequest() { + // jaxb required + } + + public PayRequest(String appId, String packageInfo) { + super(appId, DateUtil.timestamp2string(), RandomUtil.generateString(16)); + this.packageInfo = packageInfo; + } + + public String getPackageInfo() { + return packageInfo; + } + + public void setPackageInfo(String packageInfo) { + this.packageInfo = packageInfo; + } + + public String getPrepayId() { + return prepayId; + } + + public void setPrepayId(String prepayId) { + this.prepayId = prepayId; + } + + public String getPartnerId() { + return partnerId; + } + + public void setPartnerId(String partnerId) { + this.partnerId = partnerId; + } + + + @Override + public String toString() { + return "package" + packageInfo + ", prepayId=" + prepayId + + super.toString(); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/README.md b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/README.md new file mode 100644 index 00000000..1792dfa0 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/README.md @@ -0,0 +1,47 @@ +支付模块【JSAPI】【NATIVE】【MICROPAY】 + +微信公众平台[V2版本支付](https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course2_tmpl&lang=zh_CN)文档 + +微信公众平台[V3版本支付](https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course3_tmpl&lang=zh_CN)文档 + +**在`2014年10月9号`之前申请并审核通过的支付接口应该属于`V2版本`支付,而之后申请的接口则为`V3版本(商户平台)`支付** + + +[WeixinPayProxy](WeixinPayProxy.java) +------------------------- + +* createPayJsRequestJson: 创建V3版本(商户平台)的JSAPI支付串 + +* createNativePayRequestURL: 创建V3版本(商户平台)的扫码支付链接 + +* createPrePay: 调用V3版本(商户平台)的统一订单接口生成预订单数据 + +* createMicroPay: 创建刷卡支付(商户平台)请求 + +* orderQuery: 订单查询接口 + +* refundOrder: 退款申请接口 + +* reverseOrder: 冲正订单接口 + +* closeOrder: 关闭订单接口 + +* downloadBill: 下载对账单接口 + +* refundQuery: 退款查询接口 + + +[Pay2Api](https://github.com/foxinmy/weixin4j/blob/master/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/Pay2Api.java) +------------------------- + +* createPayJsRequestJson: 创建V2版本的JSAPI支付串 + +* createNativePayRequestURL: 创建V2版本的扫码支付链接 + +* orderQuery: 订单查询接口 + +* refundOrder: 退款申请接口 + +* downloadBill: 下载对账单接口 + +* refundQuery: 退款查询接口 diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/WeixinPayProxy.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/WeixinPayProxy.java new file mode 100644 index 00000000..7aa1955a --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/WeixinPayProxy.java @@ -0,0 +1,827 @@ +package com.foxinmy.weixin4j.pay.payment; + +import com.alibaba.fastjson.JSON; +import com.foxinmy.weixin4j.api.CashApi; +import com.foxinmy.weixin4j.api.CouponApi; +import com.foxinmy.weixin4j.api.CustomsApi; +import com.foxinmy.weixin4j.api.PayApi; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.XmlResult; +import com.foxinmy.weixin4j.model.WeixinPayAccount; +import com.foxinmy.weixin4j.model.paging.Pageable; +import com.foxinmy.weixin4j.pay.payment.coupon.CouponDetail; +import com.foxinmy.weixin4j.pay.payment.coupon.CouponResult; +import com.foxinmy.weixin4j.pay.payment.coupon.CouponStock; +import com.foxinmy.weixin4j.pay.payment.mch.*; +import com.foxinmy.weixin4j.sign.WeixinSignature; +import com.foxinmy.weixin4j.type.CurrencyType; +import com.foxinmy.weixin4j.type.CustomsCity; +import com.foxinmy.weixin4j.type.IdQuery; +import com.foxinmy.weixin4j.type.TarType; +import com.foxinmy.weixin4j.type.mch.BillType; +import com.foxinmy.weixin4j.type.mch.RefundAccountType; +import com.foxinmy.weixin4j.util.Consts; +import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; + +import java.io.OutputStream; +import java.util.Date; +import java.util.List; +import java.util.concurrent.Future; + +/** + * 微信支付接口实现 + * + * @className WeixinPayProxy + * @author jinyu(foxinmy@gmail.com) + * @date 2015年1月3日 + * @since JDK 1.6 + * @see 商户平台支付API + */ +public class WeixinPayProxy { + + /** + * 微信支付API:js支付、扫码支付等接口 + */ + private final PayApi payApi; + /** + * 代金券API + */ + private final CouponApi couponApi; + /** + * 现金API + */ + private final CashApi cashApi; + /** + * 海关API + */ + private final CustomsApi customsApi; + /** + * 商户信息 + */ + private final WeixinPayAccount weixinPayAccount; + + /** + * 微信支付接口实现(使用weixin4j.properties配置的account商户信息) + */ + public WeixinPayProxy() { + this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), + WeixinPayAccount.class)); + } + + /** + * 微信支付接口实现 + * + * @param weixinPayAccount + * 微信商户信息 + */ + public WeixinPayProxy(WeixinPayAccount weixinPayAccount) { + if (weixinPayAccount == null) { + throw new IllegalArgumentException( + "weixinPayAccount must not be empty"); + } + this.weixinPayAccount = weixinPayAccount; + this.payApi = new PayApi(weixinPayAccount); + this.couponApi = new CouponApi(weixinPayAccount); + this.cashApi = new CashApi(weixinPayAccount); + this.customsApi = new CustomsApi(weixinPayAccount); + } + + /** + * 获取微信商户账号信息 + * + * @return + */ + public WeixinPayAccount getWeixinPayAccount() { + return weixinPayAccount; + } + + /** + * 获取微信签名类 + * + * @return + */ + public WeixinSignature getWeixinSignature() { + return payApi.getWeixinSignature(); + } + + /** + * 统一下单接口
+ * 除被扫支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPI + * 、APP等不同场景生成交易串调起支付。 + * + * @param payPackage + * 包含订单信息的对象 + * @see PayApi + * @see MchPayPackage + * @see PrePay + * @see 统一下单接口 + * + * @return 预支付对象 + */ + public PrePay createPrePay(MchPayPackage payPackage) throws WeixinException { + return payApi.createPrePay(payPackage); + } + + /** + * 创建支付请求对象 + * + * @param payPackage + * 支付详情 + * @return 支付请求对象 + * @see PayApi + * @see JSAPIPayRequest JS支付 + * @see NATIVEPayRequest 扫码支付 + * @see MICROPayRequest 刷卡支付 + * @see APPPayRequest APP支付 + * @see WAPPayRequest WAP支付 + * @see MchPayRequest#toRequestString() + * @throws WeixinException + */ + public MchPayRequest createPayRequest(MchPayPackage payPackage) + throws WeixinException { + return payApi.createPayRequest(payPackage); + } + + /** + * 创建JSAPI支付请求对象 + * + * @param openId + * 用户ID + * @param body + * 订单描述 + * @param outTradeNo + * 订单号 + * @param totalFee + * 订单总额(元) + * @param notifyUrl + * 支付通知地址 + * @param createIp + * ip地址 + * @param attach + * 附加数据 非必填 + * @see PayApi + * @see JSAPIPayRequest + * @see MchPayRequest#toRequestString() + * @return JSAPI支付对象 + * @throws WeixinException + */ + public MchPayRequest createJSPayRequest(String openId, String body, + String outTradeNo, double totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + return payApi.createJSPayRequest(openId, body, outTradeNo, totalFee, + notifyUrl, createIp, attach); + } + + /** + *

+ * 生成编辑地址请求 + *

+ * + * err_msg edit_address:ok获取编辑收货地址成功
edit_address:fail获取编辑收货地址失败
+ * userName 收货人姓名
telNumber 收货人电话
addressPostalCode 邮编
+ * proviceFirstStageName 国标收货地址第一级地址
addressCitySecondStageName + * 国标收货地址第二级地址
addressCountiesThirdStageName 国标收货地址第三级地址
+ * addressDetailInfo 详细收货地址信息
nationalCode 收货地址国家码
+ * + * @param url + * 当前访问页的URL + * @param oauthToken + * oauth授权时产生的token + * @see PayApi + * @see + * 收货地址共享 + * @return 编辑地址请求JSON串 + */ + public String createAddressRequestJSON(String url, String oauthToken) { + return payApi.createAddressRequestJSON(url, oauthToken); + } + + /** + * 创建Native支付(扫码支付)链接【模式一】 + * + * @param productId + * 与订单ID等价 + * @return 支付链接 + * @see PayApi + * @see 扫码支付 + * + * @see 模式一 + * + */ + public String createNativePayRequest(String productId) { + return payApi.createNativePayRequest(productId); + } + + /** + * 创建Native支付(扫码支付)回调对象【模式一】 + * + * @param productId + * 商品ID + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return Native回调对象 + * @see PayApi + * @see NativePayResponse + * @see 扫码支付 + * + * @see 模式一 + * + * @throws WeixinException + */ + public NativePayResponse createNativePayResponse(String productId, + String body, String outTradeNo, double totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + return payApi.createNativePayResponse(productId, body, outTradeNo, + totalFee, notifyUrl, createIp, attach); + } + + /** + * 创建Native支付(扫码支付)链接【模式二】 + * + * @param productId + * 商品ID + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return Native支付对象 + * @see PayApi + * @see NATIVEPayRequest + * @see MchPayRequest#toRequestString() + * @see 扫码支付 + * + * @see 模式二 + * + * @throws WeixinException + */ + public MchPayRequest createNativePayRequest(String productId, String body, + String outTradeNo, double totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + return payApi.createNativePayRequest(productId, body, outTradeNo, + totalFee, notifyUrl, createIp, attach); + } + + /** + * 创建APP支付请求对象 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @param store + * 门店信息 非必填 + * @return APP支付对象 + * @see PayApi + * @see SceneInfoStore + * @see APPPayRequest + * @see MchPayRequest#toRequestString() + * @see + * APP支付 + * @throws WeixinException + */ + public MchPayRequest createAppPayRequest(String body, String outTradeNo, + double totalFee, String notifyUrl, String createIp, String attach, + SceneInfoStore store) throws WeixinException { + return payApi.createAppPayRequest(body, outTradeNo, totalFee, + notifyUrl, createIp, attach, store); + } + + /** + * 创建WAP支付请求对象 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @param app + * 应用信息 + * @return WAP支付对象 + * @see PayApi + * @see SceneInfoApp + * @see WAPPayRequest + * @see MchPayRequest#toRequestString() + * @see WAP支付 + * + * @throws WeixinException + */ + public MchPayRequest createWapPayRequest(String body, String outTradeNo, + double totalFee, String notifyUrl, String createIp, String attach, + SceneInfoApp app) throws WeixinException { + return payApi.createWapPayRequest(body, outTradeNo, totalFee, + notifyUrl, createIp, attach, app); + } + + /** + * 提交被扫支付 + * + * @param authCode + * 扫码支付授权码 ,设备读取用户微信中的条码或者二维码信息 + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @param store + * 门店信息 非必填 + * @return 支付的订单信息 + * @see PayApi + * @see Order + * @see SceneInfoStore + * @see MICROPayRequest + * @see MchPayRequest#toRequestString() + * @see + * 提交被扫支付API + * @throws WeixinException + */ + public MchPayRequest createMicroPayRequest(String authCode, String body, + String outTradeNo, double totalFee, String createIp, String attach, + SceneInfoStore store) throws WeixinException { + return payApi.createMicroPayRequest(authCode, body, outTradeNo, + totalFee, createIp, attach, store); + } + + /** + * 订单查询 + *

+ * 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
调用支付接口后,返回系统错误或未知交易状态情况;
+ * 调用被扫支付API,返回USERPAYING的状态;
调用关单或撤销接口API之前,需确认支付状态; + *

+ * + * @param idQuery + * 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @since V3 + * @see Order + * @see PayApi + * @see + * 订单查询API + * @return 订单详情 + * @throws WeixinException + */ + public Order queryOrder(IdQuery idQuery) throws WeixinException { + return payApi.queryOrder(idQuery); + } + + /** + * 申请退款 + * + * @see PayApi#applyRefund(IdQuery, String, double, double, CurrencyType, String, String, RefundAccountType) + */ + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, + double totalFee, double refundFee, CurrencyType refundFeeType, + String opUserId, String refundDesc, + RefundAccountType refundAccountType) throws WeixinException { + return payApi.applyRefund(idQuery, outRefundNo, totalFee, refundFee, + refundFeeType, opUserId, refundDesc, refundAccountType); + } + + /** + * 申请退款 + * + * @see PayApi#applyRefund(IdQuery, String, double) + */ + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, + double totalFee) throws WeixinException { + return payApi.applyRefund(idQuery, outRefundNo, totalFee); + } + + /** + * 退款查询 + *

+ * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。 + *

+ * + * @param idQuery + * 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id + * 四个参数必填一个,优先级为: + * refund_id>out_refund_no>transaction_id>out_trade_no + * @return 退款记录 + * @see PayApi + * @see RefundRecord + * @see + * 退款查询API + * @since V3 + * @throws WeixinException + */ + public RefundRecord queryRefund(IdQuery idQuery) throws WeixinException { + return payApi.queryRefund(idQuery); + } + + /** + * 下载对账单
+ * 1.微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账 单中,跟原支付单订单号一致,bill_type 为 + * REVOKED;
+ * 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;
+ * 3.对账单中涉及金额的字段单位为“元”。
+ * + * @param billDate + * 下载对账单的日期 + * @param billType + * 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单 + * REFUND,返回当日退款订单 + * @para outputStream 输出流 + * @param tarType + * 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。 + * @since V2 & V3 + * @see PayApi + * @see + * 下载对账单API + * @throws WeixinException + */ + public void downloadBill(Date billDate, BillType billType, + OutputStream outputStream, TarType tarType) throws WeixinException { + payApi.downloadBill(billDate, billType, outputStream, tarType); + } + + /** + * 冲正订单(需要证书)
当支付返回失败,或收银系统超时需要取消交易,可以调用该接口
接口逻辑:支 + * 付失败的关单,支付成功的撤销支付
7天以内的单可撤销,其他正常支付的单 + * 如需实现相同功能请调用退款接口
调用扣款接口后请勿立即调用撤销,需要等待5秒以上。先调用查单接口,如果没有确切的返回,再调用撤销
+ * + * @param idQuery + * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @return 撤销结果 + * @see PayApi + * @since V3 + * @throws WeixinException + */ + public MerchantResult reverseOrder(IdQuery idQuery) throws WeixinException { + return payApi.reverseOrder(idQuery); + } + + /** + * 关闭订单 + *

+ * 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续 + * ,请调用关单接口,如果关单失败,返回已完 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。 + *

+ * + * @param outTradeNo + * 商户系统内部的订单号 + * @return 执行结果 + * @see PayApi + * @since V3 + * @throws WeixinException + * @see + * 关闭订单API + */ + public MerchantResult closeOrder(String outTradeNo) throws WeixinException { + return payApi.closeOrder(outTradeNo); + } + + /** + * native支付URL转短链接:用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),减小二维码数据量 + * ,提升扫描速度和精确度。 + * + * @param url + * 具有native标识的支付URL + * @return 转换后的短链接 + * @see PayApi + * @see + * 转换短链接API + * @since V3 + * @throws WeixinException + */ + public String getPayShorturl(String url) throws WeixinException { + return payApi.getShorturl(url); + } + + /** + * 接口上报 + * + * @param interfaceUrl + * 上报对应的接口的完整 URL, 类似: https://api.mch.weixin.q + * q.com/pay/unifiedorder + * @param executeTime + * 接口耗时情况,单位为毫秒 + * @param outTradeNo + * 商户系统内部的订单号,商 户可以在上报时提供相关商户订单号方便微信支付更好 的提高服务质量。 + * @param ip + * 发起接口调用时的机器 IP + * @param time + * 商户调用该接口时商户自己 系统的时间 + * @param returnXml + * 调用接口返回的基本数据 + * @return 处理结果 + * @see PayApi + * @see + * 接口测试上报API + * @throws WeixinException + */ + public XmlResult reportInterface(String interfaceUrl, int executeTime, + String outTradeNo, String ip, Date time, XmlResult returnXml) + throws WeixinException { + return payApi.reportInterface(interfaceUrl, executeTime, outTradeNo, + ip, time, returnXml); + } + + /** + * 发放代金券(需要证书) + * + * @param couponStockId + * 代金券批次id + * @param partnerTradeNo + * 商户发放凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性 + * @param openId + * 用户的openid + * @param opUserId + * 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限 可为空 + * @return 发放结果 + * @see CouponApi + * @see CouponResult + * @see + * 发放代金券接口 + * @throws WeixinException + */ + public CouponResult sendCoupon(String couponStockId, String partnerTradeNo, + String openId, String opUserId) throws WeixinException { + return couponApi.sendCoupon(couponStockId, partnerTradeNo, openId, + opUserId); + } + + /** + * 查询代金券批次 + * + * @param couponStockId + * 代金券批次ID + * @return 代金券批次信息 + * @see CouponApi + * @see CouponStock + * @see + * 查询代金券批次信息接口 + * @throws WeixinException + */ + public CouponStock queryCouponStock(String couponStockId) + throws WeixinException { + return couponApi.queryCouponStock(couponStockId); + } + + /** + * 查询代金券详细 + * + * @param openId + * 用户ID + * @param couponId + * 代金券ID + * @param stockId + * 代金劵对应的批次号 + * @return 代金券详细信息 + * @see CouponApi + * @see CouponDetail + * @see + * 查询代金券详细信息接口 + * @throws WeixinException + */ + public CouponDetail queryCouponDetail(String openId, String couponId, + String stockId) throws WeixinException { + return couponApi.queryCouponDetail(openId, couponId, stockId); + } + + /** + * 发放红包 企业向微信用户个人发现金红包 + * + * @param redpacket + * 红包信息 + * @return 发放结果 + * @see CashApi + * @see Redpacket + * @see RedpacketSendResult + * @see + * 发放现金红包接口 + * @see + * 发放裂变红包接口 + * @throws WeixinException + */ + public RedpacketSendResult sendRedpack(Redpacket redpacket) + throws WeixinException { + return cashApi.sendRedpack(redpacket); + } + + /** + * 批量发放红包 企业向微信用户个人发现金红包 + * + * @param redpacket + * 多个红包信息 + * @return 发放结果 + * @see CashApi + * @see #sendRedpacks(Redpacket...) + * @throws WeixinException + */ + public List> sendRedpacks( + Redpacket... redpackets) { + return cashApi.sendRedpacks(redpackets); + } + + /** + * 查询红包记录 + * + * @param outTradeNo + * 商户发放红包的商户订单号 + * @return 红包记录 + * @see CashApi + * @see RedpacketRecord + * @see + * 查询现金红包接口 + * @see + * 查询裂变红包接口 + * @throws WeixinException + */ + public RedpacketRecord queryRedpack(String outTradeNo) + throws WeixinException { + return cashApi.queryRedpack(outTradeNo); + } + + /** + * 企业付款 + * + * @see CashApi#sendCorpPayment(CorpPayment) + */ + public CorpPaymentResult sendCorpPayment(CorpPayment payment) + throws WeixinException { + return cashApi.sendCorpPayment(payment); + } + + /** + * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果 + * + * @param outTradeNo + * 商户调用企业付款API时使用的商户订单号 + * @return 付款记录 + * @see CashApi + * @see CorpPaymentRecord + * @see + * 企业付款查询接口 + * @throws WeixinException + */ + public CorpPaymentRecord queryCorpPayment(String outTradeNo) + throws WeixinException { + return cashApi.queryCorpPayment(outTradeNo); + } + + /** + * 授权码查询OPENID + * + * @param authCode + * 扫码支付授权码,设备读取用户微信中的条码或者二维码信息 + * @return 查询结果 + * @see CashApi + * @see OpenIdResult + * @see + * 授权码查询OPENID + * @throws WeixinException + */ + public OpenIdResult authCode2openId(String authCode) throws WeixinException { + return payApi.authCode2openId(authCode); + } + + /** + * 查询结算资金 + * + * @param status + * 是否结算 + * @param pageable + * 分页数据 + * @param start + * 开始日期 查询未结算记录时,该字段可不传 + * @param end + * 结束日期 查询未结算记录时,该字段可不传 + * @return 结算金额记录 + * @throws WeixinException + * @see CashApi + * @see SettlementRecord + * @see + * 查询结算资金接口 + */ + public SettlementRecord querySettlement(boolean status, Pageable pageable, + Date start, Date end) throws WeixinException { + return cashApi.querySettlement(status, pageable, start, end); + } + + /** + * 查询汇率 + * + * @param currencyType + * 外币币种 + * @param date + * 日期 不填则默认当天 + * @return 汇率对象 + * @throws WeixinException + * @see CashApi + * @see + * 查询汇率接口 + */ + public double queryExchageRate(CurrencyType currencyType, Date date) + throws WeixinException { + return cashApi.queryExchageRate(currencyType, date); + } + + /** + * 订单附加信息提交 + * + * @param customsOrder + * 附加订单信息 + * @return 报关结果 + * @see CustomsApi + * @see CustomsOrder + * @see CustomsOrderResult + * @see + * 附加订单信息提交接口 + * @throws WeixinException + */ + public CustomsOrderResult declareCustomsOrder(CustomsOrder customsOrder) + throws WeixinException { + return customsApi.declareCustomsOrder(customsOrder); + } + + /** + * 订单附加信息查询 + * + * @param idQuery + * out_trade_no,transaction_id,sub_order_no,sub_order_id四选一 + * @param customsCity + * 海关 + * @return 报关记录 + * @see CustomsOrderRecord + * @see CustomsApi + * @see + * 附加订单信息查询接口 + * @throws WeixinException + */ + public CustomsOrderRecord queryCustomsOrder(IdQuery idQuery, + CustomsCity customsCity) throws WeixinException { + return customsApi.queryCustomsOrder(idQuery, customsCity); + } + + public final static String VERSION = Consts.VERSION; +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/APPPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/APPPayRequest.java new file mode 100644 index 00000000..c531ec78 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/APPPayRequest.java @@ -0,0 +1,74 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.PayRequest; +import com.foxinmy.weixin4j.pay.type.SignType; +import com.foxinmy.weixin4j.pay.type.TradeType; +import com.foxinmy.weixin4j.util.DigestUtil; +import com.foxinmy.weixin4j.util.MapUtil; + +import java.util.HashMap; +import java.util.Map; + +/** + * APP支付 + * + * @className APPPayRequest + * @author jinyu(foxinmy@gmail.com) + * @date 2015年12月25日 + * @since JDK 1.6 + * @see PrePay + * @see PayRequest + * @see APP支付 + */ +public class APPPayRequest extends AbstractPayRequest { + public APPPayRequest(String prePayId, WeixinPayAccount payAccount) { + super(prePayId, payAccount); + } + + @Override + public TradeType getPaymentType() { + return TradeType.APP; + } + + /** + * 只做查看之用,请不要尝试作为支付请求 + */ + @Override + public PayRequest toRequestObject() { + PayRequest payRequest = new PayRequest(getPaymentAccount().getId(), "Sign=WXPay"); + payRequest.setPartnerId(getPaymentAccount().getMchId()); + payRequest.setPrepayId(getPrePayId()); + Map map = new HashMap(); + map.put("appid", payRequest.getAppId()); + // 因为partnerid和prepayid在PayRequest类中是不进行序列化的 + map.put("partnerid", payRequest.getPartnerId()); + map.put("prepayid", payRequest.getPrepayId()); + map.put("package", payRequest.getPackageInfo()); + map.put("timestamp", payRequest.getTimeStamp()); + map.put("noncestr", payRequest.getNonceStr()); + String sign = DigestUtil.MD5( + String.format("%s&key=%s", MapUtil.toJoinString(map, false, true), getPaymentAccount().getPaySignKey())) + .toUpperCase(); + payRequest.setPaySign(sign); + payRequest.setSignType(SignType.MD5); + return payRequest; + } + + @Override + public String toRequestString() { + PayRequest payRequest = toRequestObject(); + StringBuilder content = new StringBuilder(); + content.append(""); + content.append(String.format("", payRequest.getAppId())); + content.append(String.format("", payRequest.getPartnerId())); + content.append(String.format("", payRequest.getPrepayId())); + content.append(String.format("", payRequest.getPackageInfo())); + content.append(String.format("", payRequest.getNonceStr())); + content.append(String.format("", payRequest.getTimeStamp())); + content.append(String.format("", payRequest.getPaySign())); + content.append(""); + return content.toString(); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/AbstractPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/AbstractPayRequest.java new file mode 100644 index 00000000..77af4ee7 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/AbstractPayRequest.java @@ -0,0 +1,28 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.sign.WeixinPaymentSignature; +import com.foxinmy.weixin4j.pay.sign.WeixinSignature; + +public abstract class AbstractPayRequest implements MchPayRequest { + + private final String prePayId; + private final WeixinPayAccount paymentAccount; + protected final WeixinSignature weixinSignature; + + public AbstractPayRequest(String prePayId, WeixinPayAccount paymentAccount) { + this.prePayId = prePayId; + this.paymentAccount = paymentAccount; + this.weixinSignature = new WeixinPaymentSignature(paymentAccount.getPaySignKey()); + } + + @Override + public String getPrePayId() { + return this.prePayId; + } + + @Override + public WeixinPayAccount getPaymentAccount() { + return this.paymentAccount; + } +} \ No newline at end of file diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPayment.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPayment.java new file mode 100644 index 00000000..b5f5816f --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPayment.java @@ -0,0 +1,147 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.mch.CorpPaymentCheckNameType; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * 企业付款 + * + * @className CorpPayment + * @author jinyu(foxinmy@gmail.com) + * @date 2015年4月1日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class CorpPayment extends MerchantResult { + + private static final long serialVersionUID = 3734639674346425312L; + /** + * 商户订单号 + */ + @XmlElement(name = "partner_trade_no") + @JSONField(name = "partner_trade_no") + private String outTradeNo; + /** + * 接收红包的用户的openid + */ + @JSONField(name = "openid") + @XmlElement(name = "openid") + private String openId; + /** + * 校验用户姓名选项 + * + * @see CorpPaymentCheckNameType.type.MPPaymentCheckNameType + */ + @XmlElement(name = "check_name") + @JSONField(name = "check_name") + private CorpPaymentCheckNameType checkNameType; + /** + * 收款用户真实姓名。 如果check_name设置为FORCE_CHECK或OPTION_CHECK,则必填用户真实姓名 可选 + */ + @XmlElement(name = "re_user_name") + @JSONField(name = "re_user_name") + private String userName; + /** + * 企业付款描述信息 + */ + private String desc; + /** + * 付款金额 单位分 + */ + private int amount; + /** + * 调用接口的机器Ip地址 + */ + @XmlElement(name = "spbill_create_ip") + @JSONField(name = "spbill_create_ip") + private String clientIp; + + protected CorpPayment() { + // jaxb required + } + + /** + * 企业付款 + * + * @param outTradeNo + * 商户的订单号 + * @param openId + * 用户的openid + * @param checkNameType + * 校验用户姓名选项 + * @param desc + * 描述 + * @param amount + * 金额 单位元 + * @param clientIp + * 调用接口IP + */ + public CorpPayment(String outTradeNo, String openId, + CorpPaymentCheckNameType checkNameType, String desc, double amount, + String clientIp) { + this.outTradeNo = outTradeNo; + this.openId = openId; + this.checkNameType = checkNameType; + this.desc = desc; + this.amount = DateUtil.formatYuan2Fen(amount); + this.clientIp = clientIp; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public String getOpenId() { + return openId; + } + + public CorpPaymentCheckNameType getCheckNameType() { + return checkNameType; + } + + public String getUserName() { + return userName; + } + + public String getDesc() { + return desc; + } + + public int getAmount() { + return amount; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatAmount() { + return amount / 100d; + } + + public String getClientIp() { + return clientIp; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + @Override + public String toString() { + return "CorpPayment [outTradeNo=" + outTradeNo + ", openId=" + openId + + ", checkNameType=" + checkNameType + ", userName=" + userName + + ", desc=" + desc + ", amount=" + amount + ", clientIp=" + + clientIp + ", " + super.toString() + "]"; + } +} \ No newline at end of file diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentRecord.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentRecord.java new file mode 100644 index 00000000..5d93cc0a --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentRecord.java @@ -0,0 +1,202 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.mch.CorpPaymentCheckNameType; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.Date; + +/** + * 企业付款记录 + * + * @className CorpPaymentRecord + * @author jinyu(foxinmy@gmail.com) + * @date 2015年6月23日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class CorpPaymentRecord extends MerchantResult { + + private static final long serialVersionUID = -1926873539419750498L; + + /** + * 微信订单订单号 + */ + @JSONField(name = "detail_id") + @XmlElement(name = "detail_id") + private String transactionId; + /** + * 商户订单号 + */ + @JSONField(name = "partner_trade_no") + @XmlElement(name = "partner_trade_no") + private String outTradeNo; + /** + * 交易状态 SUCCESS:转账成功 FAILED:转账失败 + */ + @JSONField(name = "status") + @XmlElement(name = "status") + private String transactionStatus; + /** + * 如果失败则应该有原因 + */ + @JSONField(name = "reason") + @XmlElement(name = "reason") + private String failureReason; + /** + * 收款用户openid + */ + @JSONField(name = "openid") + @XmlElement(name = "openid") + private String openId; + /** + * 收款用户姓名 + */ + @JSONField(name = "transfer_name") + @XmlElement(name = "transfer_name") + private String transferName; + /** + * 付款金额(单位为分) + */ + @JSONField(name = "payment_amount") + @XmlElement(name = "payment_amount") + private int paymentAmount; + /** + * 转账时间 + */ + @JSONField(name = "transfer_time") + @XmlElement(name = "transfer_time") + private String transferTime; + /** + * 校验用户姓名选项 + * + * @see CorpPaymentCheckNameType.type.MPPaymentCheckNameType + */ + @XmlElement(name = "check_name") + @JSONField(name = "check_name") + private String checkNameType; + /** + * 企业付款描述信息 + */ + @XmlElement(name = "desc") + private String desc; + /** + * 实名验证结果 PASS:通过 FAILED:不通过 + */ + @JSONField(name = "check_name_result") + @XmlElement(name = "check_name_result") + private String checkNameResult; + + protected CorpPaymentRecord() { + // jaxb required + } + + public String getTransactionId() { + return transactionId; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public String getTransactionStatus() { + return transactionStatus; + } + + /** + * 格式化交易状态 + * + * @return + */ + @JSONField(serialize = false) + public boolean getFormatTransactionStatus() { + return "success".equalsIgnoreCase(transactionStatus); + } + + public String getFailureReason() { + return failureReason; + } + + public String getOpenId() { + return openId; + } + + public String getTransferName() { + return transferName; + } + + public int getPaymentAmount() { + return paymentAmount; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatPaymentAmount() { + return paymentAmount / 100d; + } + + public String getTransferTime() { + return transferTime; + } + + /** + * 格式化转账时间 + * + * @return + */ + @JSONField(serialize = false) + public Date getFormatTransferTime() { + return transferTime != null ? DateUtil + .parse2yyyyMMddHHmmss(transferTime) : null; + } + + public String getCheckNameType() { + return checkNameType; + } + + @JSONField(serialize = false) + public CorpPaymentCheckNameType getFormatCheckNameType() { + return checkNameType != null ? CorpPaymentCheckNameType + .valueOf(checkNameType) : null; + } + + public String getDesc() { + return desc; + } + + public String getCheckNameResult() { + return checkNameResult; + } + + /** + * 格式化交易状态 + * + * @return + */ + @JSONField(serialize = false) + public boolean getFormatCheckNameResult() { + return "pass".equalsIgnoreCase(checkNameResult); + } + + @Override + public String toString() { + return "CorpPaymentRecord [transactionId=" + transactionId + + ", outTradeNo=" + outTradeNo + ", transactionStatus=" + + getFormatTransactionStatus() + ", failureReason=" + + failureReason + ", openId=" + openId + ", transferName=" + + transferName + ", paymentAmount=" + getFormatPaymentAmount() + + ", transferTime=" + transferTime + ", checkNameType=" + + checkNameType + ", desc=" + desc + ", checkNameResult=" + + getFormatCheckNameResult() + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentResult.java new file mode 100644 index 00000000..dc4b67b7 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CorpPaymentResult.java @@ -0,0 +1,74 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.Date; + +/** + * 企业付款结果 + * + * @className CorpPaymentResult + * @author jinyu(foxinmy@gmail.com) + * @date 2015年4月1日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class CorpPaymentResult extends MerchantResult { + + private static final long serialVersionUID = 1110472826089211646L; + + /** + * 微信订单订单号 + */ + @JSONField(name = "payment_no") + @XmlElement(name = "payment_no") + private String transactionId; + /** + * 商户订单号 + */ + @JSONField(name = "partner_trade_no") + @XmlElement(name = "partner_trade_no") + private String outTradeNo; + /** + * 支付时间 + */ + @JSONField(name = "payment_time") + @XmlElement(name = "payment_time") + private String paymentTime; + + protected CorpPaymentResult() { + // jaxb required + } + + public String getTransactionId() { + return transactionId; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public String getPaymentTime() { + return paymentTime; + } + + @JSONField(serialize = false) + public Date getFormatPaymentTime() { + return paymentTime != null ? DateUtil.parseDate(paymentTime, + "yyyy-MM-dd HH:mm:ss") : null; + } + + @Override + public String toString() { + return "CorpPaymentResult [transactionId=" + transactionId + + ", outTradeNo=" + outTradeNo + ", paymentTime=" + paymentTime + + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrder.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrder.java new file mode 100644 index 00000000..e21da276 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrder.java @@ -0,0 +1,217 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.CredentialType; +import com.foxinmy.weixin4j.type.CurrencyType; +import com.foxinmy.weixin4j.type.CustomsCity; + +import javax.xml.bind.annotation.XmlElement; + +/** + * 报关对象 + * + * @className CustomsOrder + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月27日 + * @since JDK 1.6 + * @see + */ +public class CustomsOrder extends MerchantResult { + + private static final long serialVersionUID = 799510373861612386L; + /** + * 微信支付订单号 + */ + @XmlElement(name = "transaction_id") + @JSONField(name = "transaction_id") + private String transactionId; + /** + * 商户订单号 + */ + @XmlElement(name = "out_trade_no") + @JSONField(name = "out_trade_no") + private String outTradeNo; + /** + * 商户子订单号,如有拆单则必传 + */ + @XmlElement(name = "sub_order_no") + @JSONField(name = "sub_order_no") + private String subOrderNo; + /** + * 货币类型,符合 ISO 4217 标准的三位字母代码,默认人民币:CNY + * + * @see com.foxinmy.weixin4j.mp.type.CurrencyType + */ + @XmlElement(name = "fee_type") + @JSONField(name = "fee_type") + private CurrencyType feeType; + /** + * 子订单金额,以分为单位,不能超过原订单金额,order_fee=transport_fee+product_fee(应付金额=物流费+商品价格), + * 如有拆单则必传。 + */ + @XmlElement(name = "order_fee") + @JSONField(name = "order_fee") + private String orderFee; + /** + * 物流费用,以分为单位,如有拆单则必传。 + */ + @XmlElement(name = "transport_fee") + @JSONField(name = "transport_fee") + private String transportFee; + /** + * 商品费用,以分为单位,如有拆单则必传。 + */ + @XmlElement(name = "product_fee") + @JSONField(name = "product_fee") + private String productFee; + /** + * 关税,以分为单位 + */ + @XmlElement(name = "duty") + @JSONField(name = "duty") + private String dutyFee; + /** + * 海关 + */ + @XmlElement(name = "customs") + @JSONField(name = "customs") + private CustomsCity customsCity; + /** + * 商户在海关登记的备案号,customsCity非NO,此参数必填 + */ + @XmlElement(name = "mch_customs_no") + @JSONField(name = "mch_customs_no") + private String customsNo; + /** + * 证件类型:暂只支持身份证,该参数是指用户信息,商户若有用户信息,可上送,系统将以商户上传的数据为准,进行海关通关报备 + */ + @XmlElement(name = "cert_type") + @JSONField(name = "cert_type") + private CredentialType credentialType; + /** + * 证件号码:身份证号,该参数是指用户信息,商户若有用户信息,可上送,系统将以商户上传的数据为准,进行海关通关报备; + */ + @XmlElement(name = "cert_id") + @JSONField(name = "cert_id") + private String credentialId; + /** + * 用户姓名,该参数是指用户信息,商户若有用户信息,可上送,系统将以商户上传的数据为准,进行海关通关报备; + */ + @XmlElement(name = "name") + @JSONField(name = "name") + private String uname; + + public CustomsOrder(String transactionId, String outTradeNo) { + this.transactionId = transactionId; + this.outTradeNo = outTradeNo; + this.customsCity = CustomsCity.NO; + } + + public String getSubOrderNo() { + return subOrderNo; + } + + public void setSubOrderNo(String subOrderNo) { + this.subOrderNo = subOrderNo; + } + + public CurrencyType getFeeType() { + return feeType; + } + + public void setFeeType(CurrencyType feeType) { + this.feeType = feeType; + } + + public String getOrderFee() { + return orderFee; + } + + public void setOrderFee(String orderFee) { + this.orderFee = orderFee; + } + + public String getTransportFee() { + return transportFee; + } + + public void setTransportFee(String transportFee) { + this.transportFee = transportFee; + } + + public String getProductFee() { + return productFee; + } + + public void setProductFee(String productFee) { + this.productFee = productFee; + } + + public String getDutyFee() { + return dutyFee; + } + + public void setDutyFee(String dutyFee) { + this.dutyFee = dutyFee; + } + + public CustomsCity getCustomsCity() { + return customsCity; + } + + public void setCustomsCity(CustomsCity customsCity) { + this.customsCity = customsCity; + } + + public String getCustomsNo() { + return customsNo; + } + + public void setCustomsNo(String customsNo) { + this.customsNo = customsNo; + } + + public CredentialType getCredentialType() { + return credentialType; + } + + public void setCredentialType(CredentialType credentialType) { + this.credentialType = credentialType; + } + + public String getCredentialId() { + return credentialId; + } + + public void setCredentialId(String credentialId) { + this.credentialId = credentialId; + } + + public String getUname() { + return uname; + } + + public void setUname(String uname) { + this.uname = uname; + } + + public String getTransactionId() { + return transactionId; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + @Override + public String toString() { + return "CustomsOrder [transactionId=" + transactionId + ", outTradeNo=" + + outTradeNo + ", subOrderNo=" + subOrderNo + ", feeType=" + + feeType + ", orderFee=" + orderFee + ", transportFee=" + + transportFee + ", productFee=" + productFee + ", dutyFee=" + + dutyFee + ", customsCity=" + customsCity + ", customsNo=" + + customsNo + ", credentialType=" + credentialType + + ", credentialId=" + credentialId + ", uname=" + uname + ", " + + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderRecord.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderRecord.java new file mode 100644 index 00000000..7daf88a9 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderRecord.java @@ -0,0 +1,72 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.xml.ListsuffixResult; + +import javax.xml.bind.annotation.XmlElement; +import java.util.List; + +/** + * 报关记录 + * + * @className CustomsOrderRecord + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月27日 + * @since JDK 1.6 + * @see + */ +public class CustomsOrderRecord extends MerchantResult { + + private static final long serialVersionUID = -1675090110657154049L; + /** + * 微信支付订单号 + */ + @XmlElement(name = "transaction_id") + @JSONField(name = "transaction_id") + private String transactionId; + /** + * 笔数 + */ + @XmlElement(name = "count") + @JSONField(name = "count") + private int orderCount; + + /** + * 报关详情 + * + * @see CustomsOrderResult + */ + @ListsuffixResult + private List customsOrderList; + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public int getOrderCount() { + return orderCount; + } + + public void setOrderCount(int orderCount) { + this.orderCount = orderCount; + } + + public List getCustomsOrderList() { + return customsOrderList; + } + + public void setCustomsOrderList(List customsOrderList) { + this.customsOrderList = customsOrderList; + } + + @Override + public String toString() { + return "CustomsOrderRecord [transactionId=" + transactionId + + ", orderCount=" + orderCount + ", customsOrderList=" + + customsOrderList + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderResult.java new file mode 100644 index 00000000..ba58c2cf --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/CustomsOrderResult.java @@ -0,0 +1,123 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.CustomsSatus; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.XmlElement; +import java.util.Date; + +/** + * 报关结果 + * + * @className CustomsOrderResult + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月27日 + * @since JDK 1.6 + * @see + */ +public class CustomsOrderResult extends MerchantResult { + + private static final long serialVersionUID = 799510373861612386L; + /** + * 状态码 + */ + private String state; + /** + * 微信支付订单号 + */ + @XmlElement(name = "transaction_id") + @JSONField(name = "transaction_id") + private String transactionId; + /** + * 商户订单号 + */ + @XmlElement(name = "out_trade_no") + @JSONField(name = "out_trade_no") + private String outTradeNo; + /** + * 商户子订单号 + */ + @XmlElement(name = "sub_order_no") + @JSONField(name = "sub_order_no") + private String subOrderNo; + /** + * 微信子订单号 + * + */ + @XmlElement(name = "sub_order_id") + @JSONField(name = "sub_order_id") + private String subOrderId; + /** + * 最后更新时间 + */ + @XmlElement(name = "modify_time") + @JSONField(name = "modify_time") + private String modifyTime; + + public String getState() { + return state; + } + + @JSONField(serialize = false) + public CustomsSatus getFormatState() { + return CustomsSatus.valueOf(state.toUpperCase()); + } + + public void setState(String state) { + this.state = state; + } + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public void setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + } + + public String getSubOrderNo() { + return subOrderNo; + } + + public void setSubOrderNo(String subOrderNo) { + this.subOrderNo = subOrderNo; + } + + public String getSubOrderId() { + return subOrderId; + } + + public void setSubOrderId(String subOrderId) { + this.subOrderId = subOrderId; + } + + public String getModifyTime() { + return modifyTime; + } + + @JSONField(serialize = false) + public Date getFormatModifyTime() { + return DateUtil.parse2yyyyMMddHHmmss(modifyTime); + } + + public void setModifyTime(String modifyTime) { + this.modifyTime = modifyTime; + } + + @Override + public String toString() { + return "CustomsOrderResult [state=" + state + ", transactionId=" + + transactionId + ", outTradeNo=" + outTradeNo + + ", subOrderNo=" + subOrderNo + ", subOrderId=" + subOrderId + + ", modifyTime=" + modifyTime + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/JSAPIPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/JSAPIPayRequest.java new file mode 100644 index 00000000..804ba769 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/JSAPIPayRequest.java @@ -0,0 +1,50 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.JSON; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.PayRequest; +import com.foxinmy.weixin4j.pay.type.SignType; +import com.foxinmy.weixin4j.pay.type.TradeType; + +/** + * 公众号JS支付:get_brand_wcpay_request
+ *

+ * get_brand_wcpay_request:ok 支付成功
+ * get_brand_wcpay_request:cancel 支付过程中用户取消
+ * get_brand_wcpay_request:fail 支付失败 + *

+ * + * @className JSAPIPayRequest + * @author jinyu(foxinmy@gmail.com) + * @date 2015年12月25日 + * @since JDK 1.6 + * @see PrePay + * @see PayRequest + * @see 网页端调起支付API + */ +public class JSAPIPayRequest extends AbstractPayRequest { + + public JSAPIPayRequest(String prePayId, WeixinPayAccount payAccount) { + super(prePayId, payAccount); + } + + @Override + public TradeType getPaymentType() { + return TradeType.JSAPI; + } + + @Override + public PayRequest toRequestObject() { + PayRequest payRequest = new PayRequest(getPaymentAccount().getId(), + "prepay_id=" + getPrePayId()); + payRequest.setSignType(SignType.MD5); + payRequest.setPaySign(weixinSignature.sign(payRequest)); + return payRequest; + } + + @Override + public String toRequestString() { + return JSON.toJSONString(toRequestObject()); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MICROPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MICROPayRequest.java new file mode 100644 index 00000000..04521a9a --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MICROPayRequest.java @@ -0,0 +1,75 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.PayRequest; +import com.foxinmy.weixin4j.type.TradeType; + +import javax.xml.bind.annotation.XmlTransient; + +/** + * MICROPAY刷卡支付 + * + * @className MICROPayRequest + * @author jinyu(foxinmy@gmail.com) + * @date 2015年12月25日 + * @since JDK 1.6 + * @see PrePay + * @see PayRequest + * @see 刷卡支付 + */ +public class MICROPayRequest extends Order implements MchPayRequest { + + private static final long serialVersionUID = 6147576305404111278L; + + @XmlTransient + @JSONField(serialize = false) + private WeixinPayAccount paymentAccount; + + protected MICROPayRequest() { + // jaxb required + } + + @Override + @JSONField(serialize = false) + public TradeType getPaymentType() { + return TradeType.MICROPAY; + } + + /** + * 返回null,请不要尝试作为支付请求 + */ + @Override + @JSONField(serialize = false) + public String toRequestString() { + return null; + } + + /** + * 返回null,请不要尝试作为支付请求 + */ + @JSONField(serialize = false) + @Override + public PayRequest toRequestObject() { + return null; + } + + /** + * 返回null,请不要尝试作为支付请求 + */ + @JSONField(serialize = false) + @Override + public String getPrePayId() { + return null; + } + + public void setPaymentAccount(WeixinPayAccount paymentAccount) { + this.paymentAccount = paymentAccount; + } + + @Override + public WeixinPayAccount getPaymentAccount() { + return this.paymentAccount; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java new file mode 100644 index 00000000..e890dbbb --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayPackage.java @@ -0,0 +1,224 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.PayPackage; +import com.foxinmy.weixin4j.pay.type.CurrencyType; +import com.foxinmy.weixin4j.pay.type.TradeType; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.Date; + +/** + * 支付订单详情 + * + * @className MchPayPackage + * @author jinyu(foxinmy@gmail.com) + * @date 2014年10月21日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class MchPayPackage extends PayPackage { + + private static final long serialVersionUID = 8944928173669656177L; + + /** + * 交易类型JSAPI、NATIVE、APP 必须 + */ + @XmlElement(name = "trade_type") + @JSONField(name = "trade_type") + private String tradeType; + /** + * 符合ISO 4217标准的三位字母代码,默认人民币:CNY 非必须 + */ + @XmlElement(name = "fee_type") + @JSONField(name = "fee_type") + private String feeType; + /** + * 用户在商户 appid 下的唯一 标识, trade_type 为 JSAPI 时,此参数必传 + */ + @XmlElement(name = "openid") + @JSONField(name = "openid") + private String openId; + + /** + * 只在 trade_type 为 NATIVE 且【模式一】 时需要填写 非必须 + */ + @XmlElement(name = "product_id") + @JSONField(name = "product_id") + private String productId; + + /** + * 扫码支付授权码 ,设备读取用户微信中的条码或者二维码信息 + */ + @XmlElement(name = "auth_code") + @JSONField(name = "auth_code") + private String authCode; + /** + * 指定支付方式:no_credit--指定不能使用信用卡支付 + */ + @XmlElement(name = "limit_pay") + @JSONField(name = "limit_pay") + private String limitPay; + /** + * 服务商下的用户子标识 非必须 + */ + @XmlElement(name = "sub_openid") + @JSONField(name = "sub_openid") + private String subOpenId; + /** + * 场景信息 + */ + @XmlElement(name = "scene_info") + @JSONField(name = "scene_info") + private String sceneInfo; + + protected MchPayPackage() { + // jaxb required + } + + /** + * 微信支付 + * + * @param body + * 支付详情 必填 + * @param outTradeNo + * 商户侧订单号 必填 + * @param totalFee + * 支付金额(单位元) 必填 + * @param notifyUrl + * 支付回调URL 必填 + * @param createIp + * 发起支付的IP地址 必填 + * @param tradeType + * 支付类型 必填 + * @param openId + * 用户唯一标识 公众号JSAPI支付必填 + * @param authCode + * 支付授权码 刷卡MICROPAY支付必填 + * @param productId + * 商品ID 扫码NATIVE支付必填 + * @param attach + * 支付时附加信息 非必填 + */ + public MchPayPackage(String body, String outTradeNo, double totalFee, + String notifyUrl, String createIp, TradeType tradeType, + String openId, String authCode, String productId, String attach) { + this(body, null, outTradeNo, totalFee, CurrencyType.CNY, notifyUrl, + createIp, tradeType, openId, authCode, productId, attach, null, + null, null, null, null); + } + + /** + * 完整参数 + * + * @param body + * 商品描述 必填项 + * @param detial + * 商品名称明细列表 非必填项 + * @param outTradeNo + * 商户内部唯一订单号 必填项 + * @param totalFee + * 商品总额 单位元 必填项 + * @param notifyUrl + * 支付回调URL 必填项 + * @param createIp + * 订单生成的机器IP 必填项 + * @param tradeType + * 交易类型 必填项 + * @param feeType + * 货币类型 非必填项 + * @param openId + * 用户ID tradeType=JSAPI时必填 + * @param authCode + * 刷卡支付授权码 tradeType=MICROPAY时必填 + * @param productId + * 产品ID tradeType=NATIVE时必填 + * @param attach + * 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 非必填项 + * @param timeStart + * 订单生成时间,格式为yyyyMMddHHmmss 非必填项 + * @param timeExpire + * 订单失效时间,格式为yyyyMMddHHmmss;注意:最短失效时间间隔必须大于5分钟 非必填项 + * @param goodsTag + * 商品标记,代金券或立减优惠功能的参数 非必填项 + * @param limitPay + * 指定支付方式:no_credit--指定不能使用信用卡支付 非必填项 + * @param subOpenId + * 用户在子商户appid下的唯一标识 非必填 + * openid和sub_openid可以选传其中之一,如果选择传sub_openid ,则必须传sub_appid + */ + public MchPayPackage(String body, String detial, String outTradeNo, + double totalFee, CurrencyType feeType, String notifyUrl, + String createIp, TradeType tradeType, String openId, + String authCode, String productId, String attach, Date timeStart, + Date timeExpire, String goodsTag, String limitPay, String subOpenId) { + super(body, detial, outTradeNo, totalFee, notifyUrl, createIp, attach, + timeStart, timeExpire, goodsTag); + this.tradeType = tradeType != null ? tradeType.name() : null; + this.feeType = feeType == null ? CurrencyType.CNY.name() : feeType + .name(); + this.openId = openId; + this.authCode = authCode; + this.productId = productId; + this.limitPay = limitPay; + this.subOpenId = subOpenId; + } + + public String getTradeType() { + return tradeType; + } + + public String getFeeType() { + return feeType; + } + + public String getOpenId() { + return openId; + } + + public String getAuthCode() { + return authCode; + } + + public String getProductId() { + return productId; + } + + public String getLimitPay() { + return limitPay; + } + + public void setLimitPay(String limitPay) { + this.limitPay = limitPay; + } + + public String getSubOpenId() { + return subOpenId; + } + + public void setSubOpenId(String subOpenId) { + this.subOpenId = subOpenId; + } + + public String getSceneInfo() { + return sceneInfo; + } + + public void setSceneInfo(String sceneInfo) { + this.sceneInfo = sceneInfo; + } + + @Override + public String toString() { + return "MchPayPackage [tradeType=" + tradeType + ",feeType=" + feeType + + ", openId=" + openId + ", productId=" + productId + + ", authCode=" + authCode + ", limitPay=" + limitPay + + ", subOpenId=" + subOpenId + ", sceneInfo=" + sceneInfo + + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayRequest.java new file mode 100644 index 00000000..9bfce2a8 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MchPayRequest.java @@ -0,0 +1,55 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.PayRequest; +import com.foxinmy.weixin4j.pay.type.TradeType; + +/** + * 支付请求接口 + * + * @className MchPayRequest + * @author jinyu(foxinmy@gmail.com) + * @date 2015年12月25日 + * @since JDK 1.6 + * @see JSAPIPayRequest JS支付 + * @see NATIVEPayRequest 扫码支付 + * @see MICROPayRequest 刷卡支付 + * @see APPPayRequest APP支付 + * @see WAPPayRequest WAP支付 + */ +public interface MchPayRequest { + /** + * 预支付交易ID + * + * @return + */ + public String getPrePayId(); + + /** + * 支付账号 + * + * @return + */ + public WeixinPayAccount getPaymentAccount(); + + /** + * 支付类型 + * + * @return + */ + public TradeType getPaymentType(); + + /** + * 支付请求字符串 + * + * @return + */ + public String toRequestString(); + + /** + * 支付请求对象 + * + * @return + */ + public PayRequest toRequestObject(); +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantResult.java new file mode 100644 index 00000000..a2a940b4 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantResult.java @@ -0,0 +1,176 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.http.weixin.XmlResult; +import com.foxinmy.weixin4j.type.SignType; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * 调用商户平台接口返回的公用字段 + * + * @className MerchantResult + * @author jinyu(foxinmy@gmail.com) + * @date 2014年10月21日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class MerchantResult extends XmlResult { + + private static final long serialVersionUID = -8430005768959715444L; + + /** + * 微信分配的公众账号 ID商户号 非空 + */ + @XmlElement(name = "appid") + @JSONField(name = "appid") + private String appId; + /** + * 微信支付分配的商户号 非空 + */ + @XmlElement(name = "mch_id") + @JSONField(name = "mch_id") + private String mchId; + /** + * 微信分配的子商户公众账号ID 非必须 + */ + @XmlElement(name = "sub_appid") + @JSONField(name = "sub_appid") + private String subAppId; + /** + * 微信支付分配的子商户号 非必须 + */ + @XmlElement(name = "sub_mch_id") + @JSONField(name = "sub_mch_id") + private String subMchId; + /** + * 随机字符串 非空 + */ + @XmlElement(name = "nonce_str") + @JSONField(name = "nonce_str") + private String nonceStr; + /** + * 签名 调用者无需关心 + */ + private String sign; + /** + * 签名类型 默认MD5 + */ + @XmlElement(name = "sign_type") + @JSONField(name = "sign_type") + private String signType; + /** + * 微信支付分配的终端设备号 可能为空 + */ + @XmlElement(name = "device_info") + @JSONField(name = "device_info") + private String deviceInfo; + /** + * 是否需要继续调用接口 Y- 需要,N-不需要 + */ + private String recall; + + protected MerchantResult() { + // jaxb required + } + + public MerchantResult(String returnCode, String returnMsg) { + super(returnCode, returnMsg); + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getMchId() { + return mchId; + } + + public void setMchId(String mchId) { + this.mchId = mchId; + } + + public String getSubAppId() { + return subAppId; + } + + public void setSubAppId(String subAppId) { + this.subAppId = subAppId; + } + + public String getSubMchId() { + return subMchId; + } + + public void setSubMchId(String subMchId) { + this.subMchId = subMchId; + } + + public String getNonceStr() { + return nonceStr; + } + + public void setNonceStr(String nonceStr) { + this.nonceStr = nonceStr; + } + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + public String getSignType() { + return signType; + } + + @JSONField(serialize = false) + public SignType getFormatSignType() { + return signType != null ? SignType.valueOf(signType.toUpperCase()) + : null; + } + + public void setSignType(String signType) { + this.signType = signType; + } + + public String getDeviceInfo() { + return deviceInfo; + } + + public void setDeviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + } + + public String getRecall() { + return recall; + } + + public void setRecall(String recall) { + this.recall = recall; + } + + @JSONField(serialize = false) + public boolean getFormatRecall() { + return recall != null && recall.equalsIgnoreCase("y"); + } + + @Override + public String toString() { + return "appId=" + appId + ", mchId=" + mchId + ", subAppId=" + subAppId + + ", subMchId=" + subMchId + ", nonceStr=" + nonceStr + + ", sign=" + sign + ", deviceInfo=" + deviceInfo + ", recall=" + + getFormatRecall() + ", " + super.toString(); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantTradeResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantTradeResult.java new file mode 100644 index 00000000..3f297f3f --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/MerchantTradeResult.java @@ -0,0 +1,126 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.CurrencyType; + +import javax.xml.bind.annotation.XmlElement; + +/** + * 商户平台交易结果 + * + * @className MerchantTradeResult + * @author jinyu(foxinmy@gmail.com) + * @date 2016年7月21日 + * @since JDK 1.7 + * @see + */ +public class MerchantTradeResult extends MerchantResult { + + private static final long serialVersionUID = 4205906286092873877L; + /** + * 微信支付订单号 + */ + @XmlElement(name = "transaction_id") + @JSONField(name = "transaction_id") + private String transactionId; + /** + * 商户订单号 + */ + @XmlElement(name = "out_trade_no") + @JSONField(name = "out_trade_no") + private String outTradeNo; + /** + * 订单总金额,单位为分 + */ + @XmlElement(name = "total_fee") + @JSONField(name = "total_fee") + private Integer totalFee; + /** + * 应结订单金额,单位为分:应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。 + */ + @XmlElement(name = "settlement_total_fee") + @JSONField(name = "settlement_total_fee") + private Integer settlementTotalFee; + /** + * 货币类型,符合 ISO 4217 标准的三位字母代码,默认人民币:CNY + * + * @see com.foxinmy.weixin4j.mp.type.CurrencyType + */ + @XmlElement(name = "fee_type") + @JSONField(name = "fee_type") + private String feeType; + /** + * 现金支付金额 + */ + @XmlElement(name = "cash_fee") + @JSONField(name = "cash_fee") + private Integer cashFee; + + public Integer getCashFee() { + return cashFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCashFee() { + return cashFee != null ? cashFee / 100d : 0d; + } + + public Integer getTotalFee() { + return totalFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatTotalFee() { + return totalFee != null ? totalFee / 100d : 0d; + } + + @JSONField(serialize = false) + public CurrencyType getFormatFeeType() { + return feeType != null ? CurrencyType.valueOf(feeType.toUpperCase()) + : null; + } + + public String getFeeType() { + return feeType; + } + + public String getTransactionId() { + return transactionId; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public Integer getSettlementTotalFee() { + return settlementTotalFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatSettlementTotalFee() { + return settlementTotalFee != null ? settlementTotalFee / 100d : 0d; + } + + @Override + public String toString() { + return "transactionId=" + transactionId + ", outTradeNo=" + outTradeNo + + ", totalFee=" + totalFee + ", cashFee=" + cashFee + + ", feeType=" + feeType + ", settlementTotalFee=" + + settlementTotalFee + ", " + super.toString(); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NATIVEPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NATIVEPayRequest.java new file mode 100644 index 00000000..787dfacb --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NATIVEPayRequest.java @@ -0,0 +1,46 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.PayRequest; +import com.foxinmy.weixin4j.pay.type.TradeType; + +/** + * NATIVE扫码支付(模式二) + * + * @className NATIVEPayRequest + * @author jinyu(foxinmy@gmail.com) + * @date 2015年12月25日 + * @since JDK 1.6 + * @see PrePay + * @see PayRequest + * @see NATIVE扫码支付(模式二) + */ +public class NATIVEPayRequest extends AbstractPayRequest { + + private final String codeUrl; + + public NATIVEPayRequest(String prePayId, String codeUrl, + WeixinPayAccount payAccount) { + super(prePayId, payAccount); + this.codeUrl = codeUrl; + } + + @Override + public TradeType getPaymentType() { + return TradeType.NATIVE; + } + + /** + * 只做查看之用,请不要尝试作为支付请求 + */ + @Override + public PayRequest toRequestObject() { + return new PayRequest(getPaymentAccount().getId(), "code_url=" + codeUrl); + } + + @Override + public String toRequestString() { + return this.codeUrl; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayNotify.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayNotify.java new file mode 100644 index 00000000..57c9b697 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayNotify.java @@ -0,0 +1,54 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Native支付回调时POST的信息 + * + * @className PayNativeNotify + * @author jinyu(foxinmy@gmail.com) + * @date 2014年10月30日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class NativePayNotify extends OpenIdResult { + + private static final long serialVersionUID = 4515471400239795492L; + /** + * 用户是否关注公众账号,Y- 关注,N-未关注,仅在公众 账号类型支付有效 + */ + @XmlElement(name = "is_subscribe") + @JSONField(name = "is_subscribe") + private String isSubscribe; + /** + * 产品ID 可视为订单ID + */ + @XmlElement(name = "product_id") + @JSONField(name = "product_id") + private String productId; + + protected NativePayNotify() { + // jaxb required + } + + public String getProductId() { + return productId; + } + + public String getIsSubscribe() { + return isSubscribe; + } + + @Override + public String toString() { + return "NativePayNotify [productId=" + productId + ", isSubscribe=" + + isSubscribe + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayResponse.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayResponse.java new file mode 100644 index 00000000..04b2f253 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/NativePayResponse.java @@ -0,0 +1,79 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.sign.WeixinPaymentSignature; +import com.foxinmy.weixin4j.util.Consts; +import com.foxinmy.weixin4j.util.RandomUtil; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Native支付时的回调响应 + * + * @className NativePayResponse + * @author jinyu(foxinmy@gmail.com) + * @date 2014年10月28日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class NativePayResponse extends MerchantResult { + + private static final long serialVersionUID = 6119895998783333012L; + + @XmlElement(name = "prepay_id") + @JSONField(name = "prepay_id") + private String prepayId; + + protected NativePayResponse() { + // jaxb required + } + + /** + * 作为return_code 为 FAIL 的时候返回 + * + * @param returnMsg + * 失败消息 + * @param resultMsg + * 结果消息 + */ + public NativePayResponse(String returnMsg, String resultMsg) { + super(Consts.FAIL, returnMsg); + super.setErrCodeDes(resultMsg); + super.setResultCode(Consts.FAIL); + } + + /** + * 作为return_code 为 SUCCESS 的时候返回 + * + * @param weixinAccount + * 商户信息 + * @param prepayId + * 调用统一下单接口生成的预支付ID + */ + public NativePayResponse(WeixinPayAccount weixinAccount, String prepayId) { + super(Consts.SUCCESS, "OK"); + this.setResultCode(Consts.SUCCESS); + this.setMchId(weixinAccount.getMchId()); + this.setAppId(weixinAccount.getId()); + this.setNonceStr(RandomUtil.generateString(16)); + this.prepayId = prepayId; + this.setSign(new WeixinPaymentSignature(weixinAccount.getPaySignKey()) + .sign(this)); + } + + public String getPrepayId() { + return prepayId; + } + + @Override + public String toString() { + return "NativePayResponse [prepayId=" + prepayId + ", " + + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/OpenIdResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/OpenIdResult.java new file mode 100644 index 00000000..3c4cfd95 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/OpenIdResult.java @@ -0,0 +1,52 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * authcode2openid + * + * @className OpenIdResult + * @author jinyu(foxinmy@gmail.com) + * @date 2015年7月23日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class OpenIdResult extends MerchantResult { + + private static final long serialVersionUID = 902743989722741814L; + + /** + * 用户在商户appid下的唯一标识 + */ + @XmlElement(name = "openid") + @JSONField(name = "openid") + private String openId; + + /** + * 用户在商户appid下的唯一标识 + */ + @XmlElement(name = "sub_openid") + @JSONField(name = "sub_openid") + private String subOpenId; + + public String getOpenId() { + return openId; + } + + public String getSubOpenId() { + return subOpenId; + } + + @Override + public String toString() { + return "OpenIdResult [openId=" + openId + ", subOpenId=" + subOpenId + + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Order.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Order.java new file mode 100644 index 00000000..f1e7be19 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Order.java @@ -0,0 +1,247 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.coupon.OrderCouponInfo; +import com.foxinmy.weixin4j.type.BankType; +import com.foxinmy.weixin4j.type.CurrencyType; +import com.foxinmy.weixin4j.type.TradeState; +import com.foxinmy.weixin4j.type.TradeType; +import com.foxinmy.weixin4j.util.DateUtil; +import com.foxinmy.weixin4j.xml.ListsuffixResult; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.Date; +import java.util.List; + +/** + * 订单信息 + * + * @className Order + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月2日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class Order extends MerchantTradeResult { + + private static final long serialVersionUID = 5636828325595317079L; + /** + * 交易状态 + * + * @see TradeState + */ + @XmlElement(name = "trade_state") + @JSONField(name = "trade_state") + private String tradeState; + /** + * 用户的openid + */ + @XmlElement(name = "openid") + @JSONField(name = "openid") + private String openId; + /** + * 用户是否关注公众账号,Y- 关注,N-未关注,仅在公众 账号类型支付有效 + */ + @XmlElement(name = "is_subscribe") + @JSONField(name = "is_subscribe") + private String isSubscribe; + /** + * 交易类型 + * + * @see TradeType + */ + @XmlElement(name = "trade_type") + @JSONField(name = "trade_type") + private String tradeType; + /** + * 银行类型 + */ + @XmlElement(name = "bank_type") + @JSONField(name = "bank_type") + private String bankType; + + /** + * 现金支付货币类型,符合 ISO 4217 标准的三位字母代码,默认人民币:CNY + * + * @see com.foxinmy.weixin4j.mp.type.CurrencyType + */ + @XmlElement(name = "cash_fee_type") + @JSONField(name = "cash_fee_type") + private String cashFeeType; + /** + * 代金券金额:“代金券”金额<=订单金额,订单金额-“代金券”金额=现金支付金额 + */ + @XmlElement(name = "coupon_fee") + @JSONField(name = "coupon_fee") + private Integer couponFee; + /** + * 代金券或立减优惠使用数量 + */ + @XmlElement(name = "coupon_count") + @JSONField(name = "coupon_count") + private Integer couponCount; + /** + * 代金券信息 验证签名有点麻烦 + */ + @ListsuffixResult + private List couponList; + /** + * 商家数据包 + */ + private String attach; + /** + * 支付完成时间,格式为 yyyyMMddhhmmss + */ + @XmlElement(name = "time_end") + @JSONField(name = "time_end") + private String timeEnd; + /** + * 交易状态描述 + */ + @XmlElement(name = "trade_state_desc") + @JSONField(name = "trade_state_desc") + private String tradeStateDesc; + + /** + * 用户在子商户下的openid + */ + @XmlElement(name = "sub_openid") + @JSONField(name = "sub_openid") + private String subOpenId; + /** + * 是否关注子公众账号,Y- 关注,N-未关注,仅在公众 账号类型支付有效 + */ + @XmlElement(name = "sub_is_subscribe") + @JSONField(name = "sub_is_subscribe") + private String subIsSubscribe; + + protected Order() { + // jaxb required + } + + @JSONField(serialize = false) + public TradeState getFormatTradeState() { + return tradeState != null ? TradeState + .valueOf(tradeState.toUpperCase()) : null; + } + + public String getOpenId() { + return openId; + } + + public String getIsSubscribe() { + return isSubscribe; + } + + @JSONField(serialize = false) + public boolean getFormatIsSubscribe() { + return isSubscribe != null && isSubscribe.equalsIgnoreCase("y"); + } + + @JSONField(serialize = false) + public TradeType getFormatTradeType() { + return tradeType != null ? TradeType.valueOf(tradeType.toUpperCase()) + : null; + } + + public String getBankType() { + return bankType; + } + + @JSONField(serialize = false) + public BankType getFormatBankType() { + return bankType != null ? BankType.valueOf(bankType.toUpperCase()) + : null; + } + + public Integer getCouponFee() { + return couponFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponFee() { + return couponFee != null ? couponFee / 100d : 0d; + } + + public Integer getCouponCount() { + return couponCount; + } + + public String getTradeState() { + return tradeState; + } + + public String getTradeType() { + return tradeType; + } + + public String getAttach() { + return attach; + } + + public String getTimeEnd() { + return timeEnd; + } + + @JSONField(serialize = false) + public Date getFormatTimeEnd() { + return timeEnd != null ? DateUtil.parse2yyyyMMddHHmmss(timeEnd) : null; + } + + public String getTradeStateDesc() { + return tradeStateDesc; + } + + public List getCouponList() { + return couponList; + } + + public void setCouponList(List couponList) { + this.couponList = couponList; + } + + public String getSubOpenId() { + return subOpenId; + } + + public String getSubIsSubscribe() { + return subIsSubscribe; + } + + @JSONField(serialize = false) + public boolean getFormatSubIsSubscribe() { + return subIsSubscribe != null && subIsSubscribe.equalsIgnoreCase("y"); + } + + public String getCashFeeType() { + return cashFeeType; + } + + @JSONField(serialize = false) + public CurrencyType getFormatCashFeeType() { + return cashFeeType != null ? CurrencyType.valueOf(cashFeeType + .toUpperCase()) : null; + } + + @Override + public String toString() { + return "Order [tradeState=" + tradeState + ", openId=" + openId + + ", isSubscribe=" + isSubscribe + ", tradeType=" + tradeType + + ", bankType=" + bankType + ", cashFeeType=" + cashFeeType + + ", couponFee=" + couponFee + ", couponCount=" + couponCount + + ", couponList=" + couponList + ", attach=" + attach + + ", timeEnd=" + timeEnd + ", tradeStateDesc=" + tradeStateDesc + + ", subOpenId=" + subOpenId + ", subIsSubscribe=" + + subIsSubscribe + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/PrePay.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/PrePay.java new file mode 100644 index 00000000..a8059fbe --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/PrePay.java @@ -0,0 +1,79 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.foxinmy.weixin4j.type.TradeType; + +import javax.xml.bind.annotation.*; + +/** + * V3预订单信息 + * + * @className PrePay + * @author jinyu(foxinmy@gmail.com) + * @date 2014年10月21日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class PrePay extends MerchantResult { + + private static final long serialVersionUID = -8430005768959715444L; + + /** + * 调用接口提交的交易类型,取值如下:JSAPI,NATIVE,APP, + * + * @see com.foxinmy.weixin4j.mp.type.TradeType + */ + @XmlElement(name = "trade_type") + private TradeType tradeType; + /** + * 微信生成的预支付回话标识,用于后续接口调用中使用,该值有效期为2小时 + */ + @XmlElement(name = "prepay_id") + private String prepayId; + /** + * 对于trade_type 为 NATIVE 或者 MWEB 是有 返回
NATVIE支付:可直接生成二维码展示出来进行扫码支付可能为空
+ * MWEB支付:可直接作为跳转支付的URL + */ + @XmlElements({ @XmlElement(name = "code_url"), + @XmlElement(name = "mweb_url") }) + private String payUrl; + + protected PrePay() { + // jaxb required + } + + public PrePay(String returnCode, String returnMsg) { + super(returnCode, returnMsg); + } + + public TradeType getTradeType() { + return tradeType; + } + + public void setTradeType(TradeType tradeType) { + this.tradeType = tradeType; + } + + public String getPrepayId() { + return prepayId; + } + + public void setPrepayId(String prepayId) { + this.prepayId = prepayId; + } + + public String getPayUrl() { + return payUrl; + } + + public void setPayUrl(String payUrl) { + this.payUrl = payUrl; + } + + @Override + public String toString() { + return "PrePay [tradeType=" + tradeType + ", prepayId=" + prepayId + + ", payUrl=" + payUrl + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Redpacket.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Redpacket.java new file mode 100644 index 00000000..6888862e --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/Redpacket.java @@ -0,0 +1,269 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.mch.RedpacketSceneType; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * 红包 + * + * @className Redpacket + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月28日 + * @since JDK 1.6 + * @see 普通红包 + * @see 裂变红包 + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class Redpacket extends MerchantResult { + + private static final long serialVersionUID = -7021352305575714281L; + + /** + * 商户订单号(每个订单号必须唯一) 组成: mch_id+yyyymmdd+10位一天内不能重复的数字。 + */ + @XmlElement(name = "mch_billno") + @JSONField(name = "mch_billno") + private String outTradeNo; + /** + * 接受收红包的用户的openid 必填 + */ + @XmlElement(name = "re_openid") + @JSONField(name = "re_openid") + private String openId; + /** + * 红包发送者名称 必填 + */ + @XmlElement(name = "send_name") + @JSONField(name = "send_name") + private String sendName; + /** + * 付款金额,单位分 + */ + @XmlElement(name = "total_amount") + @JSONField(name = "total_amount") + private int totalAmount; + /** + * 红包发放总人数 + */ + @XmlElement(name = "total_num") + @JSONField(name = "total_num") + private int totalNum; + /** + * 红包金额设置方式(裂变红包) ALL_RAND—全部随机,商户指定总金额和红包发放总人数,由微信支付随机计算出各红包金额 + */ + @XmlElement(name = "amt_type") + @JSONField(name = "amt_type") + private String amtType; + /** + * 红包祝福语 + */ + private String wishing; + /** + * ip地址 + */ + @XmlElement(name = "client_ip") + @JSONField(name = "client_ip") + private String clientIp; + /** + * 活动名称 + */ + @XmlElement(name = "act_name") + @JSONField(name = "act_name") + private String actName; + /** + * 备注 + */ + private String remark; + + /** + * 服务商模式下触达用户时的appid(可填服务商自己的appid或子商户的appid),服务商模式下必填, + * 服务商模式下填入的子商户appid必须在微信支付商户平台中先录入,否则会校验不过。 非必须 + */ + @XmlElement(name = "msgappid") + @JSONField(name = "msgappid") + private String msgAppId; + /** + * 扣钱方mchid,常规模式下无效,服务商模式下选填,服务商模式下不填默认扣子商户的钱.非必须 + */ + @XmlElement(name = "consume_mch_id") + @JSONField(name = "consume_mch_id") + private String consumeMchId; + /** + * 发放红包使用场景,红包金额大于200时必传 + */ + @XmlElement(name = "scene_id") + @JSONField(name = "scene_id") + private RedpacketSceneType sceneType; + /** + * 活动信息 + */ + @XmlElement(name = "risk_info") + @JSONField(name = "risk_info") + private String risk; + + protected Redpacket() { + // jaxb required + } + + /** + * 红包 + * + * @param outTradeNo + * 商户侧一天内不可重复的订单号 接口根据商户订单号支持重入 如出现超时可再调用 必填 + * @param openId + * 接受收红包的用户的openid 必填 + * @param sendName + * 红包发送者名称 必填 + * @param totalAmount + * 付款金额 单位为元,自动格式化为分 必填 + * @param totalNum + * 红包发放总人数 大于1视为裂变红包 必填 + * @param wishing + * 红包祝福语 必填 + * @param clientIp + * Ip地址 必填 + * @param actName + * 活动名称 必填 + * @param remark + * 备注 必填 + */ + public Redpacket(String outTradeNo, String openId, String sendName, + double totalAmount, int totalNum, String wishing, String clientIp, + String actName, String remark) { + this.outTradeNo = outTradeNo; + this.openId = openId; + this.sendName = sendName; + this.totalAmount = DateUtil.formatYuan2Fen(totalAmount); + this.totalNum = totalNum; + this.wishing = wishing; + this.clientIp = clientIp; + this.actName = actName; + this.remark = remark; + this.amtType = totalNum > 1 ? "ALL_RAND" : null; + } + + /** + * 批量发送时可能需要 + * + * @param outTradeNo + * 订单号 + * @param openId + * 用户ID + * @return 红包实体 + */ + public Redpacket copy(String outTradeNo, String openId) { + Redpacket readpacket = new Redpacket(outTradeNo, openId, sendName, + totalAmount, totalNum, wishing, clientIp, actName, remark); + readpacket.setMsgAppId(msgAppId); + readpacket.setConsumeMchId(consumeMchId); + readpacket.setSceneType(sceneType); + readpacket.setRisk(risk); + return readpacket; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public String getOpenId() { + return openId; + } + + public String getSendName() { + return sendName; + } + + public int getTotalAmount() { + return totalAmount; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatTotalAmount() { + return totalAmount / 100d; + } + + public int getTotalNum() { + return totalNum; + } + + public String getWishing() { + return wishing; + } + + public String getAmtType() { + return amtType; + } + + public String getClientIp() { + return clientIp; + } + + public String getActName() { + return actName; + } + + public String getRemark() { + return remark; + } + + public String getMsgAppId() { + return msgAppId; + } + + public void setMsgAppId(String msgAppId) { + this.msgAppId = msgAppId; + } + + public String getConsumeMchId() { + return consumeMchId; + } + + public void setConsumeMchId(String consumeMchId) { + this.consumeMchId = consumeMchId; + } + + public RedpacketSceneType getSceneType() { + return sceneType; + } + + public void setSceneType(RedpacketSceneType sceneType) { + this.sceneType = sceneType; + } + + public String getRisk() { + return risk; + } + + public void setRisk(String risk) { + this.risk = risk; + } + + public void setRisk(RedpacketRisk risk) { + this.risk = risk.toContent(); + } + + @Override + public String toString() { + return "Redpacket [outTradeNo=" + outTradeNo + ", openId=" + openId + + ", sendName=" + sendName + ", totalAmount=" + totalAmount + + ", totalNum=" + totalNum + ", amtType=" + amtType + + ", wishing=" + wishing + ", clientIp=" + clientIp + + ", actName=" + actName + ", remark=" + remark + ", msgAppId=" + + msgAppId + ", consumeMchId=" + consumeMchId + ", sceneType=" + + sceneType + ", risk=" + risk + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRecord.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRecord.java new file mode 100644 index 00000000..2cee591b --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRecord.java @@ -0,0 +1,315 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.http.weixin.XmlResult; +import com.foxinmy.weixin4j.type.mch.RedpacketSendType; +import com.foxinmy.weixin4j.type.mch.RedpacketStatus; +import com.foxinmy.weixin4j.type.mch.RedpacketType; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.*; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 红包记录 + * + * @className RedpacketRecord + * @author jinyu(foxinmy@gmail.com) + * @date 2015年6月4日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class RedpacketRecord extends XmlResult { + + private static final long serialVersionUID = 929959747323918458L; + + /** + * 商户订单号(每个订单号必须唯一) 组成: mch_id+yyyymmdd+10位一天内不能重复的数字。 + */ + @XmlElement(name = "mch_billno") + @JSONField(name = "mch_billno") + private String outTradeNo; + /** + * 微信支付分配的商户号 + */ + @XmlElement(name = "mch_id") + @JSONField(name = "mch_id") + private String mchId; + /** + * 红包单号 + */ + @XmlElement(name = "detail_id") + @JSONField(name = "detail_id") + private String repacketId; + /** + * 红包状态 + */ + @XmlElement(name = "status") + private String status; + /** + * 发放类型 + */ + @XmlElement(name = "send_type") + @JSONField(name = "send_type") + private String sendType; + /** + * 红包类型 + */ + @XmlElement(name = "hb_type") + @JSONField(name = "hb_type") + private String hbType; + /** + * 红包个数 + */ + @XmlElement(name = "total_num") + @JSONField(name = "total_num") + private int totalNum; + /** + * 红包总金额(单位分) + */ + @XmlElement(name = "total_amount") + @JSONField(name = "total_amount") + private int totalAmount; + /** + * 发送失败原因 + */ + @XmlElement(name = "reason") + private String reason; + /** + * 发放时间 + */ + @XmlElement(name = "send_time") + @JSONField(name = "send_time") + private String sendTime; + /** + * 红包退款时间 + */ + @XmlElement(name = "refund_time") + @JSONField(name = "refund_time") + private String refundTime; + /** + * 红包退款金额 + */ + @XmlElement(name = "refund_amount") + @JSONField(name = "refund_amount") + private Integer refundAmount; + /** + * 祝福语 + */ + @XmlElement(name = "wishing") + private String wishing; + /** + * 活动描述 + */ + @XmlElement(name = "remark") + private String remark; + /** + * 活动名称 + */ + @XmlElement(name = "act_name") + @JSONField(name = "act_name") + private String actName; + /** + * 裂变红包领取列表 + */ + @XmlElement(name = "hbinfo") + @XmlElementWrapper(name = "hblist") + @JSONField(name = "hblist") + private List receivers; + + public String getOutTradeNo() { + return outTradeNo; + } + + public String getMchId() { + return mchId; + } + + public String getRepacketId() { + return repacketId; + } + + @JSONField(serialize = false) + public RedpacketStatus getFormatStatus() { + return status != null ? RedpacketStatus.valueOf(status.toUpperCase()) + : null; + } + + @JSONField(serialize = false) + public RedpacketSendType getFormatSendType() { + return sendType != null ? RedpacketSendType.valueOf(sendType) : null; + } + + @JSONField(serialize = false) + public RedpacketType getFomatHbType() { + return hbType != null ? RedpacketType.valueOf(hbType) : null; + } + + public String getStatus() { + return status; + } + + public String getSendType() { + return sendType; + } + + public String getHbType() { + return hbType; + } + + public int getTotalNum() { + return totalNum; + } + + public int getTotalAmount() { + return totalAmount; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatTotalAmount() { + return totalAmount / 100d; + } + + public String getReason() { + return reason; + } + + public String getSendTime() { + return sendTime; + } + + @JSONField(serialize = false) + public Date getFormatSendTime() { + return sendTime != null ? DateUtil.parse2yyyyMMddHHmmss(sendTime) + : null; + } + + public String getRefundTime() { + return refundTime; + } + + @JSONField(serialize = false) + public Date getFormatRefundTime() { + return refundTime != null ? DateUtil.parse2yyyyMMddHHmmss(refundTime) + : null; + } + + public Integer getRefundAmount() { + return refundAmount; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatRefundAmount() { + return refundAmount != null ? refundAmount.intValue() / 100d : 0d; + } + + public String getWishing() { + return wishing; + } + + public String getRemark() { + return remark; + } + + public String getActName() { + return actName; + } + + public List getReceivers() { + return receivers; + } + + @XmlRootElement + @XmlAccessorType(XmlAccessType.FIELD) + public static class RedpacketReceiver implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 领取红包的Openid + */ + @XmlElement(name = "openid") + private String openId; + /** + * 领取状态 + */ + @XmlElement(name = "status") + private RedpacketStatus status; + /** + * 领取金额 + */ + private int amount; + /** + * 领取时间 + */ + @XmlElement(name = "rcv_time") + @JSONField(name = "rcv_time") + private String receiveTime; + + public String getOpenId() { + return openId; + } + + public RedpacketStatus getStatus() { + return status; + } + + public int getAmount() { + return amount; + } + + public String getReceiveTime() { + return receiveTime; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatAmount() { + return amount / 100d; + } + + @JSONField(serialize = false) + public Date getFormatReceiveTime() { + return receiveTime != null ? DateUtil + .parse2yyyyMMddHHmmss(receiveTime) : null; + } + + @Override + public String toString() { + return "RedpacketReceiver [openId=" + openId + ", status=" + status + + ", amount=" + getFormatAmount() + ", receiveTime=" + + receiveTime + "]"; + } + } + + @Override + public String toString() { + return "RedpacketRecord [outTradeNo=" + outTradeNo + ", mchId=" + mchId + + ", repacketId=" + repacketId + ", status=" + status + + ", sendType=" + sendType + ", hbType=" + hbType + + ", totalNum=" + totalNum + ", totalAmount=" + + getFormatTotalAmount() + ", reason=" + reason + ", sendTime=" + + sendTime + ", refundTime=" + refundTime + ", refundAmount=" + + getFormatRefundAmount() + ", wishing=" + wishing + + ", remark=" + remark + ", actName=" + actName + + ", receivers=" + receivers + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRisk.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRisk.java new file mode 100644 index 00000000..05127d0b --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketRisk.java @@ -0,0 +1,85 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.foxinmy.weixin4j.util.Consts; +import com.foxinmy.weixin4j.util.DateUtil; +import com.foxinmy.weixin4j.util.MapUtil; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; + +/** + * 发送红包的活动信息 + * + * @className RedpacketRisk + * @author jinyu(foxinmy@gmail.com) + * @date 2017年1月4日 + * @since JDK 1.6 + * @see + */ +public class RedpacketRisk { + private Map risk; + + public RedpacketRisk() { + this.risk = new HashMap(); + } + + /** + * 用户操作的时间戳 + * + * @return + */ + public RedpacketRisk postTimestamp() { + risk.put("posttime", DateUtil.timestamp2string()); + return this; + } + + /** + * 业务系统账号的手机号,国家代码-手机号。不需要+号 + * + * @param mobile + * @return + */ + public RedpacketRisk mobile(String mobile) { + risk.put("mobile", mobile); + return this; + } + + /** + * 用户操作的客户端版本 + * + * @param clientVersion + * @return + */ + public RedpacketRisk clientVersion(String clientVersion) { + risk.put("clientversion", clientVersion); + return this; + } + + /** + * mac 地址或者设备唯一标识 + * + * @param deviceid + * @return + */ + public RedpacketRisk deviceid(String deviceid) { + risk.put("deviceid", deviceid); + return this; + } + + public Map getRisk() { + return risk; + } + + public String toContent() { + if (risk.isEmpty()) + return null; + try { + return URLEncoder.encode(MapUtil.toJoinString(risk, false, false), + Consts.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + return null; + } + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketSendResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketSendResult.java new file mode 100644 index 00000000..741c9e29 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RedpacketSendResult.java @@ -0,0 +1,102 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.Date; + +/** + * 发送红包结果 + * + * @className RedpacketSendResult + * @author jinyu(foxinmy@gmail.com) + * @date 2015年4月1日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class RedpacketSendResult extends MerchantResult { + + private static final long serialVersionUID = 5611847899634131711L; + /** + * 商户订单号(每个订单号必须唯一) 组成: mch_id+yyyymmdd+10位一天内不能重复的数字。 + */ + @XmlElement(name = "mch_billno") + @JSONField(name = "mch_billno") + private String outTradeNo; + /** + * 接收红包的用户的openid + */ + @XmlElement(name = "re_openid") + @JSONField(name = "re_openid") + private String openId; + /** + * 付款金额 单位为分 + */ + @XmlElement(name = "total_amount") + @JSONField(name = "total_amount") + private int totalAmount; + /** + * 发放成功时间 + */ + @XmlElement(name = "send_time") + @JSONField(name = "send_time") + private String sendTime; + /** + * 微信单号 + */ + @XmlElement(name = "send_listid") + @JSONField(name = "send_listid") + private String sendListid; + + protected RedpacketSendResult() { + // jaxb required + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public String getOpenId() { + return openId; + } + + public int getTotalAmount() { + return totalAmount; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatTotalAmount() { + return totalAmount / 100d; + } + + public String getSendTime() { + return sendTime; + } + + @JSONField(serialize = false) + public Date getFormatSendTime() { + return DateUtil.parse2yyyyMMddHHmmss(sendTime); + } + + public String getSendListid() { + return sendListid; + } + + @Override + public String toString() { + return "RedpacketSendResult [outTradeNo=" + outTradeNo + ", openId=" + + openId + ", totalAmount=" + totalAmount + ", " + + super.toString() + "]"; + } +} \ No newline at end of file diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundDetail.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundDetail.java new file mode 100644 index 00000000..8d81f4ee --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundDetail.java @@ -0,0 +1,218 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.pay.payment.coupon.RefundCouponInfo; +import com.foxinmy.weixin4j.type.mch.CouponType; +import com.foxinmy.weixin4j.type.mch.RefundChannel; +import com.foxinmy.weixin4j.type.mch.RefundStatus; +import com.foxinmy.weixin4j.util.DateUtil; +import com.foxinmy.weixin4j.xml.ListsuffixResult; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 退款详细 + * + * @className RefundDetail + * @author jinyu(foxinmy@gmail.com) + * @date 2016年7月21日 + * @since JDK 1.6 + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class RefundDetail implements Serializable { + private static final long serialVersionUID = 1402738803019986864L; + + protected RefundDetail() { + // jaxb required + } + + /** + * 商户退款单号 + */ + @XmlElement(name = "out_refund_no") + @JSONField(name = "out_refund_no") + private String outRefundNo; + /** + * 微信退款单号 + */ + @XmlElement(name = "refund_id") + @JSONField(name = "refund_id") + private String refundId; + /** + * 退款渠道:ORIGINAL—原路退款,默认 BALANCE—退回到余额 + */ + @XmlElement(name = "refund_channel") + @JSONField(name = "refund_channel") + private String refundChannel; + /** + * 退款总金额,单位为分,可以做部分退款 + */ + @XmlElement(name = "refund_fee") + @JSONField(name = "refund_fee") + private int refundFee; + /** + * 退款状态 + */ + @XmlElement(name = "refund_status") + @JSONField(name = "refund_status") + private String refundStatus; + /** + * 退款金额:退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额 + */ + @XmlElement(name = "settlement_refund_fee") + @JSONField(name = "settlement_refund_fee") + private Integer settlementRefundFee; + /** + * 代金券退款金额:代金券退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金, + */ + @XmlElement(name = "coupon_refund_fee") + @JSONField(name = "coupon_refund_fee") + private Integer couponRefundFee; + /** + * 代金券或立减优惠使用数量 + */ + @XmlElement(name = "coupon_refund_count") + @JSONField(name = "coupon_refund_count") + private Integer couponRefundCount; + /** + * 代金券类型 + * + * @see CouponType + */ + @XmlElement(name = "coupon_type") + @JSONField(name = "coupon_type") + private String couponType; + /** + * 退款入账账户:取当前退款单的退款入账方 1)退回银行卡: {银行名称}{卡类型}{卡尾号} 2)退回支付用户零钱: 支付用户零钱 + */ + @XmlElement(name = "refund_recv_accout") + @JSONField(name = "refund_recv_accout") + private String refundRecvAccout; + /** + * 退款成功时间,当退款状态为退款成功时有返回 + */ + @XmlElement(name = "refund_success_time") + @JSONField(name = "refund_success_time") + private String refundSuccessTime; + /** + * 退款代金券信息 + * + * @see RefundCouponInfo + */ + @ListsuffixResult + private List couponList; + + public String getOutRefundNo() { + return outRefundNo; + } + + public String getRefundId() { + return refundId; + } + + public String getRefundChannel() { + return refundChannel; + } + + @JSONField(serialize = false) + public RefundChannel getFormatRefundChannel() { + return refundChannel != null ? RefundChannel.valueOf(refundChannel + .toUpperCase()) : null; + } + + public int getRefundFee() { + return refundFee; + } + + public String getRefundStatus() { + return refundStatus; + } + + @JSONField(serialize = false) + public RefundStatus getFormatRefundStatus() { + return refundStatus != null ? RefundStatus.valueOf(refundStatus + .toUpperCase()) : null; + } + + public List getCouponList() { + return couponList; + } + + public void setCouponList(List couponList) { + this.couponList = couponList; + } + + public Integer getSettlementRefundFee() { + return settlementRefundFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatSettlementRefundFee() { + return settlementRefundFee != null ? settlementRefundFee / 100d : 0d; + } + + public Integer getCouponRefundFee() { + return couponRefundFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCouponRefundFee() { + return couponRefundFee != null ? couponRefundFee / 100d : 0d; + } + + public Integer getCouponRefundCount() { + return couponRefundCount; + } + + public String getCouponType() { + return couponType; + } + + @JSONField(serialize = false) + public CouponType getFormatCouponType() { + return couponType != null ? CouponType + .valueOf(couponType.toUpperCase()) : null; + } + + public String getRefundRecvAccout() { + return refundRecvAccout; + } + + public String getRefundSuccessTime() { + return refundSuccessTime; + } + + @JSONField(serialize = false) + public Date getFormatRefundSuccessTime() { + return refundSuccessTime != null ? DateUtil.parse2yyyyMMddHHmmss(refundSuccessTime) : null; + } + + @Override + public String toString() { + return "RefundDetail [outRefundNo=" + outRefundNo + ", refundId=" + + refundId + ", refundChannel=" + refundChannel + + ", refundFee=" + refundFee + ", refundStatus=" + refundStatus + + ", settlementRefundFee=" + settlementRefundFee + + ", couponRefundFee=" + couponRefundFee + + ", couponRefundCount=" + couponRefundCount + ", couponType=" + + couponType + ", refundRecvAccout=" + refundRecvAccout + + ", couponList=" + couponList + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundRecord.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundRecord.java new file mode 100644 index 00000000..9de5fd05 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundRecord.java @@ -0,0 +1,81 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.xml.ListsuffixResult; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +/** + * 退款记录 + * + * @className RefundRecord + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月1日 + * @since JDK 1.6 + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class RefundRecord extends MerchantTradeResult { + + private static final long serialVersionUID = -2971132874939642721L; + /** + * 退款笔数 + */ + @XmlElement(name = "refund_count") + @JSONField(name = "refund_count") + private int refundCount; + /** + * 退款总金额,单位为分,可以做部分退款 + */ + @XmlElement(name = "refund_fee") + @JSONField(name = "refund_fee") + private int refundFee; + /** + * 退款详情 + * + * @see RefundDetail + */ + @ListsuffixResult({ ".*(_\\d)$" }) + private List refundList; + + protected RefundRecord() { + // jaxb required + } + + public int getRefundCount() { + return refundCount; + } + + public int getRefundFee() { + return refundFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatRefundFee() { + return refundFee / 100d; + } + + public List getRefundList() { + return refundList; + } + + public void setRefundList(List refundList) { + this.refundList = refundList; + } + + @Override + public String toString() { + return "RefundRecord [refundCount=" + refundCount + ", refundFee=" + + refundFee + ", refundList=" + refundList + ", " + + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundResult.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundResult.java new file mode 100644 index 00000000..717c4bc5 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/RefundResult.java @@ -0,0 +1,128 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.mch.RefundChannel; +import com.foxinmy.weixin4j.xml.ListsuffixResult; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +/** + * 退款申请结果 + * + * @className RefundResult + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月6日 + * @since JDK 1.6 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class RefundResult extends MerchantTradeResult { + + private static final long serialVersionUID = -3687863914168618620L; + + /** + * 商户退款单号 + */ + @XmlElement(name = "out_refund_no") + @JSONField(name = "out_refund_no") + private String outRefundNo; + /** + * 微信退款单号 + */ + @XmlElement(name = "refund_id") + @JSONField(name = "refund_id") + private String refundId; + /** + * 退款渠道:ORIGINAL—原路退款,默认 BALANCE—退回到余额 + */ + @XmlElement(name = "refund_channel") + @JSONField(name = "refund_channel") + private String refundChannel; + /** + * 退款总金额,单位为分,可以做部分退款 + */ + @XmlElement(name = "refund_fee") + @JSONField(name = "refund_fee") + private int refundFee; + /** + * 现金退款金额 + */ + @XmlElement(name = "cash_refund_fee") + @JSONField(name = "cash_refund_fee") + private Integer cashRefundFee; + /** + * 退款详情 + * + * @see RefundDetail + */ + @ListsuffixResult({ ".*(_\\d)$" }) + private List refundList; + + protected RefundResult() { + // jaxb required + } + + public String getOutRefundNo() { + return outRefundNo; + } + + public String getRefundId() { + return refundId; + } + + public String getRefundChannel() { + return refundChannel; + } + + @JSONField(serialize = false) + public RefundChannel getFormatRefundChannel() { + return refundChannel != null ? RefundChannel.valueOf(refundChannel + .toUpperCase()) : null; + } + + public int getRefundFee() { + return refundFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatRefundFee() { + return refundFee / 100d; + } + + public Integer getCashRefundFee() { + return cashRefundFee; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatCashRefundFee() { + return cashRefundFee != null ? cashRefundFee.intValue() / 100d : 0d; + } + + public List getRefundList() { + return refundList; + } + + @Override + public String toString() { + return "RefundResult [" + super.toString() + ", outRefundNo=" + + outRefundNo + ", refundId=" + refundId + ", refundChannel=" + + refundChannel + ", refundFee=" + refundFee + + ", cashRefundFee=" + cashRefundFee + ", refundList=" + + refundList + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java new file mode 100644 index 00000000..48a5b763 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoApp.java @@ -0,0 +1,99 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class SceneInfoApp { + /** + * 终端类型 + */ + private String type; + /** + * 应用名称 + */ + private String name; + /** + * 应用路径 + */ + private String path; + private String sceneInfo; + + private SceneInfoApp(String type, String name, String path) { + this.type = type; + this.name = name; + this.path = path; + } + + public String getType() { + return type; + } + + public String getName() { + return name; + } + + public String getPath() { + return path; + } + + public String getSceneInfo() { + return sceneInfo; + } + + public void setSceneInfo(String sceneInfo) { + this.sceneInfo = sceneInfo; + } + + /** + * IOS应用 + * + * @param appName 应用名 + * @param bundleId 模块ID + * @return + */ + public static SceneInfoApp createIOSAPP(String appName, String bundleId) { + SceneInfoApp app = new SceneInfoApp("IOS", appName, bundleId); + String sceneInfo = String + .format("{\"type\": \"%s\",\"app_name\": \"%s\",\"bundle_id\": \"%s\"}", + app.getType(), app.getName(), app.getPath()); + app.setSceneInfo(sceneInfo); + return app; + } + + /** + * Android应用 + * + * @param appName 应用名 + * @param packageName 包名 + * @return + */ + public static SceneInfoApp createAndroidAPP(String appName, String packageName) { + SceneInfoApp app = new SceneInfoApp("Android", appName, packageName); + String sceneInfo = String + .format("{\"type\": \"%s\",\"app_name\": \"%s\",\"package_name\": \"%s\"}", + app.getType(), app.getName(), app.getPath()); + app.setSceneInfo(sceneInfo); + return app; + } + + /** + * Wap应用 + * + * @param name + * 网站名 + * @param url + * 网站URL地址 + * @return + */ + public static SceneInfoApp createWapAPP(String name, String url) { + SceneInfoApp app = new SceneInfoApp("Wap", name, url); + String sceneInfo = String.format( + "{\"type\": \"%s\",\"wap_name\": \"%s\",\"wap_url\": \"%s\"}", + app.getType(), app.getName(), app.getPath()); + app.setSceneInfo(sceneInfo); + return app; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java new file mode 100644 index 00000000..550e9edd --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SceneInfoStore.java @@ -0,0 +1,75 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class SceneInfoStore { + /** + * SZTX001 门店唯一标识 + */ + private String id; + /** + * 腾讯大厦腾大餐厅 门店名称 + */ + private String name; + /** + * 门店所在地行政区划码,详细见《最新县及县以上行政区划代码》 + */ + @XmlElement(name = "area_code") + @JSONField(name = "area_code") + private String areaCode; + /** + * 科技园中一路腾讯大厦 门店详细地址 + */ + private String address; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAreaCode() { + return areaCode; + } + + public void setAreaCode(String areaCode) { + this.areaCode = areaCode; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public SceneInfoStore(String id, String name) { + super(); + this.id = id; + this.name = name; + } + + @Override + public String toString() { + return "SceneInfoStore [id=" + id + ", name=" + name + ", areaCode=" + + areaCode + ", address=" + address + "]"; + } +} \ No newline at end of file diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SettlementRecord.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SettlementRecord.java new file mode 100644 index 00000000..501abd03 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/SettlementRecord.java @@ -0,0 +1,272 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.CurrencyType; +import com.foxinmy.weixin4j.util.DateUtil; + +import javax.xml.bind.annotation.XmlElement; +import java.util.Date; + +/** + * 结算资金 + * + * @className Settlement + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月26日 + * @since JDK 1.6 + * @see + */ +public class SettlementRecord extends MerchantResult { + + private static final long serialVersionUID = 7952659545609519979L; + + /** + * 付款批次号 + */ + @XmlElement(name = "fbatchno") + @JSONField(name = "fbatchno") + private String batchNo; + /** + * 结算日期 + */ + @XmlElement(name = "date_settlement") + @JSONField(name = "date_settlement") + private String settleDate; + /** + * 交易开始日期 + */ + @XmlElement(name = "date_start") + @JSONField(name = "date_start") + private String startDate; + /** + * 交易结束日期 + */ + @XmlElement(name = "date_end") + @JSONField(name = "date_end") + private String endDate; + /** + * 划账金额:外币标价,外币最小单位 + */ + @XmlElement(name = "transaction_id") + @JSONField(name = "transaction_id") + private int settleFee; + /** + * 未划账金额:外币标价,外币最小单位 + */ + @XmlElement(name = "unsettlement_fee") + @JSONField(name = "unsettlement_fee") + private int unSettleFee; + /** + * 结算币种 + */ + @XmlElement(name = "settlementfee_type") + @JSONField(name = "settlementfee_type") + private String settleFeeType; + /** + * 支付金额:外币标价,外币最小单位 + */ + @XmlElement(name = "pay_fee") + @JSONField(name = "pay_fee") + private int payFee; + /** + * 退款金额:外币标价,外币最小单位 + */ + @XmlElement(name = "refund_fee") + @JSONField(name = "refund_fee") + private int refundFee; + /** + * 支付净额:外币标价,外币最小单位 + */ + @XmlElement(name = "pay_net_fee") + @JSONField(name = "pay_net_fee") + private int payNetFee; + /** + * 手续费金额:外币标价,外币最小单位 + */ + @XmlElement(name = "poundage_fee") + @JSONField(name = "poundage_fee") + private int poundageFee; + + protected SettlementRecord() { + // jaxb required + } + + public String getBatchNo() { + return batchNo; + } + + public void setBatchNo(String batchNo) { + this.batchNo = batchNo; + } + + public String getSettleDate() { + return settleDate; + } + + @JSONField(serialize = false) + public Date getFormatSettleDate() { + return DateUtil.parse2yyyyMMddHHmmss(settleDate); + } + + public void setSettleDate(String settleDate) { + this.settleDate = settleDate; + } + + public String getStartDate() { + return startDate; + } + + @JSONField(serialize = false) + public Date getFormatStartDate() { + return DateUtil.parse2yyyyMMddHHmmss(startDate); + } + + public void setStartDate(String startDate) { + this.startDate = startDate; + } + + public String getEndDate() { + return endDate; + } + + @JSONField(serialize = false) + public Date getFormatEndDate() { + return DateUtil.parse2yyyyMMddHHmmss(settleDate); + } + + public void setEndDate(String endDate) { + this.endDate = endDate; + } + + public int getSettleFee() { + return settleFee; + } + + /** + * 最小单位除100得到的值 + * + * @return /100 + */ + @JSONField(serialize = false) + public double getFormatSettleFee() { + return settleFee / 100d; + } + + public void setSettleFee(int settleFee) { + this.settleFee = settleFee; + } + + public int getUnSettleFee() { + return unSettleFee; + } + + /** + * 最小单位除100得到的值 + * + * @return /100 + */ + @JSONField(serialize = false) + public double getFormatUnSettleFee() { + return unSettleFee / 100d; + } + + public void setUnSettleFee(int unSettleFee) { + this.unSettleFee = unSettleFee; + } + + public String getSettleFeeType() { + return settleFeeType; + } + + @JSONField(serialize = false) + public CurrencyType getFormatSettleFeeType() { + return CurrencyType.valueOf(settleFeeType.toUpperCase()); + } + + public void setSettleFeeType(String settleFeeType) { + this.settleFeeType = settleFeeType; + } + + public int getPayFee() { + return payFee; + } + + /** + * 最小单位除100得到的值 + * + * @return /100 + */ + @JSONField(serialize = false) + public double getFormatPayFee() { + return payFee / 100d; + } + + public void setPayFee(int payFee) { + this.payFee = payFee; + } + + public int getRefundFee() { + return refundFee; + } + + /** + * 最小单位除100得到的值 + * + * @return /100 + */ + @JSONField(serialize = false) + public double getFormatRefundFee() { + return refundFee / 100d; + } + + public void setRefundFee(int refundFee) { + this.refundFee = refundFee; + } + + public int getPayNetFee() { + return payNetFee; + } + + public void setPayNetFee(int payNetFee) { + this.payNetFee = payNetFee; + } + + /** + * 最小单位除100得到的值 + * + * @return /100 + */ + @JSONField(serialize = false) + public double getFormatPayNetFee() { + return payNetFee / 100d; + } + + public int getPoundageFee() { + return poundageFee; + } + + /** + * 最小单位除100得到的值 + * + * @return /100 + */ + @JSONField(serialize = false) + public double getFormatPoundageFee() { + return poundageFee / 100d; + } + + public void setPoundageFee(int poundageFee) { + this.poundageFee = poundageFee; + } + + @Override + public String toString() { + return "SettlementRecord [batchNo=" + batchNo + ", settleDate=" + + settleDate + ", startDate=" + startDate + ", endDate=" + + endDate + ", settleFee=" + settleFee + ", unSettleFee=" + + unSettleFee + ", settleFeeType=" + settleFeeType + + ", payFee=" + payFee + ", refundFee=" + refundFee + + ", payNetFee=" + payNetFee + ", poundageFee=" + poundageFee + + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/WAPPayRequest.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/WAPPayRequest.java new file mode 100644 index 00000000..f08eff1f --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/payment/mch/WAPPayRequest.java @@ -0,0 +1,61 @@ +package com.foxinmy.weixin4j.pay.payment.mch; + +import com.foxinmy.weixin4j.pay.model.WeixinPayAccount; +import com.foxinmy.weixin4j.pay.payment.PayRequest; +import com.foxinmy.weixin4j.pay.type.TradeType; + +/** + * WAP支付 + * + * @className WAPPayRequest + * @author jinyu(foxinmy@gmail.com) + * @date 2015年12月25日 + * @since JDK 1.6 + * @see PrePay + * @see PayRequest + * @see WAP支付 + */ +public class WAPPayRequest extends AbstractPayRequest { + /** + * 微信支付URL + */ + private final String payUrl; + + public WAPPayRequest(String prePayId, String payUrl, + WeixinPayAccount payAccount) { + super(prePayId, payAccount); + this.payUrl = payUrl; + + } + + @Override + public TradeType getPaymentType() { + return TradeType.MWEB; + } + + /** + * 只做查看之用,请不要尝试作为支付请求 + */ + @Override + public PayRequest toRequestObject() { + PayRequest payRequest = new PayRequest(getPaymentAccount().getId(), + getPaymentType().name()); + payRequest.setPrepayId(getPrePayId()); + return payRequest; + } + + @Override + public String toRequestString() { + // PayRequest payRequest = toRequestObject(); + // String original = MapUtil.toJoinString(payRequest, true, true); + // String sign = DigestUtil.MD5( + // String.format("%s&key=%s", original, getPaymentAccount() + // .getPaySignKey())).toUpperCase(); + // return String.format("weixin://wap/pay?%s", + // URLEncodingUtil.encoding( + // String.format("%s&sign=%s", original, sign), + // Consts.UTF_8, true)); + return this.payUrl; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/AbstractWeixinSignature.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/AbstractWeixinSignature.java new file mode 100644 index 00000000..6a077b99 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/AbstractWeixinSignature.java @@ -0,0 +1,45 @@ +package com.foxinmy.weixin4j.pay.sign; + +import com.foxinmy.weixin4j.util.MapUtil; + +/** + * 微信签名 + * + * @className AbstractWeixinSignature + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月26日 + * @since JDK 1.6 + * @see + */ +public abstract class AbstractWeixinSignature implements WeixinSignature { + /** + * 是否编码 + * + * @return 默认false不进行编码 + */ + @Override + public boolean encoder() { + return false; + } + + /** + * 是否转换小写 + * + * @return 默认false不转换小写 + */ + @Override + public boolean lowerCase() { + return false; + } + + /** + * 拼接字符串 + * + * @param obj + * @return + */ + protected StringBuilder join(Object obj) { + return new StringBuilder(MapUtil.toJoinString(obj, encoder(), + lowerCase())); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinPaymentSignature.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinPaymentSignature.java new file mode 100644 index 00000000..98200f04 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinPaymentSignature.java @@ -0,0 +1,36 @@ +package com.foxinmy.weixin4j.pay.sign; + +import com.foxinmy.weixin4j.pay.type.SignType; +import com.foxinmy.weixin4j.util.DigestUtil; + +/** + * 微信支付签名实现 + * + * @className WeixinPaymentSignature + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月26日 + * @since JDK 1.6 + * @see 支付签名说明 + */ +public class WeixinPaymentSignature extends AbstractWeixinSignature { + /** + * 支付密钥 + */ + private final String paySignKey; + + public WeixinPaymentSignature(String paySignKey) { + this.paySignKey = paySignKey; + } + + @Override + public SignType getSignType() { + return SignType.MD5; + } + + @Override + public String sign(Object obj) { + StringBuilder sb = join(obj).append("&key=").append(paySignKey); + return DigestUtil.MD5(sb.toString()).toUpperCase(); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinSignature.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinSignature.java new file mode 100644 index 00000000..88920e85 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/sign/WeixinSignature.java @@ -0,0 +1,43 @@ +package com.foxinmy.weixin4j.pay.sign; + +import com.foxinmy.weixin4j.pay.type.SignType; + +/** + * 微信签名 + * + * @className WeixinSignature + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月26日 + * @since JDK 1.6 + * @see + */ +public interface WeixinSignature { + /** + * 是否编码 + * + * @return + */ + public boolean encoder(); + + /** + * 是否转换小写 + * + * @return + */ + public boolean lowerCase(); + + /** + * 签名类型 + * + * @return + */ + public SignType getSignType(); + + /** + * 签名 + * + * @param obj + * @return + */ + public String sign(Object obj); +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/BankType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/BankType.java new file mode 100644 index 00000000..397f9a4e --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/BankType.java @@ -0,0 +1,260 @@ +package com.foxinmy.weixin4j.pay.type; + + +/** + * 银行类型 + * + * @className BankType + * @author jinyu(foxinmy@gmail.com) + * @date 2015年8月19日 + * @since JDK 1.6 + * @see + */ +public enum BankType { + /** + * 工商银行(借记卡) + */ + ICBC_DEBIT("工商银行(借记卡)"), + /** + * 工商银行(信用卡) + */ + ICBC_CREDIT("工商银行(信用卡)"), + /** + * 农业银行(借记卡) + */ + ABC_DEBIT("农业银行(借记卡)"), + /** + * 农业银行 (信用卡) + */ + ABC_CREDIT("农业银行 (信用卡)"), + /** + * 邮政储蓄(借记卡) + */ + PSBC_DEBIT("邮政储蓄(借记卡)"), + /** + * 邮政储蓄 (信用卡) + */ + PSBC_CREDIT("邮政储蓄 (信用卡)"), + /** + * 建设银行(借记卡) + */ + CCB_DEBIT("建设银行(借记卡)"), + /** + * 建设银行 (信用卡) + */ + CCB_CREDIT("建设银行 (信用卡)"), + /** + * 招商银行(借记卡) + */ + CMB_DEBIT("招商银行(借记卡)"), + /** + * 招商银行(信用卡) + */ + CMB_CREDIT("招商银行(信用卡)"), + /** + * 交通银行(借记卡) + */ + COMM_DEBIT("交通银行(借记卡)"), + /** + * 中国银行(信用卡) + */ + BOC_CREDIT("中国银行(信用卡)"), + /** + * 浦发银行(借记卡) + */ + SPDB_DEBIT("浦发银行(借记卡)"), + /** + * 浦发银行 (信用卡) + */ + SPDB_CREDIT("浦发银行 (信用卡)"), + /** + * 广发银行(借记卡) + */ + GDB_DEBIT("广发银行(借记卡)"), + /** + * 广发银行(信用卡) + */ + GDB_CREDIT("广发银行(信用卡)"), + /** + * 民生银行(借记卡) + */ + CMBC_DEBIT("民生银行(借记卡)"), + /** + * 民生银行(信用卡) + */ + CMBC_CREDIT("民生银行(信用卡)"), + /** + * 平安银行(借记卡) + */ + PAB_DEBIT("平安银行(借记卡)"), + /** + * 平安银行(信用卡) + */ + PAB_CREDIT("平安银行(信用卡)"), + /** + * 光大银行(借记卡) + */ + CEB_DEBIT("光大银行(借记卡)"), + /** + * 光大银行(信用卡) + */ + CEB_CREDIT("光大银行(信用卡)"), + /** + * 兴业银行 (借记卡) + */ + CIB_DEBIT("兴业银行 (借记卡)"), + /** + * 兴业银行(信用卡) + */ + CIB_CREDIT("兴业银行(信用卡)"), + /** + * 中信银行(借记卡) + */ + CITIC_DEBIT("中信银行(借记卡)"), + /** + * 中信银行(信用卡) + */ + CITIC_CREDIT("中信银行(信用卡)"), + /** + * 深发银行(信用卡) + */ + SDB_CREDIT("深发银行(信用卡)"), + /** + * 上海银行(借记卡) + */ + BOSH_DEBIT("上海银行(借记卡)"), + /** + * 上海银行 (信用卡) + */ + BOSH_CREDIT("上海银行 (信用卡)"), + /** + * 华润银行(借记卡) + */ + CRB_DEBIT("华润银行(借记卡)"), + /** + * 杭州银行(借记卡) + */ + HZB_DEBIT("杭州银行(借记卡)"), + /** + * 杭州银行(信用卡) + */ + HZB_CREDIT("杭州银行(信用卡)"), + /** + * 包商银行(借记卡) + */ + BSB_DEBIT("包商银行(借记卡)"), + /** + * 包商银行 (信用卡) + */ + BSB_CREDIT("包商银行 (信用卡)"), + /** + * 重庆银行(借记卡) + */ + CQB_DEBIT("重庆银行(借记卡)"), + /** + * 顺德农商行 (借记卡) + */ + SDEB_DEBIT("顺德农商行 (借记卡)"), + /** + * 深圳农商银行(借记卡) + */ + SZRCB_DEBIT("深圳农商银行(借记卡)"), + /** + * 哈尔滨银行(借记卡) + */ + HRBB_DEBIT("哈尔滨银行(借记卡)"), + /** + * 成都银行(借记卡) + */ + BOCD_DEBIT("成都银行(借记卡)"), + /** + * 南粤银行 (借记卡) + */ + GDNYB_DEBIT("南粤银行 (借记卡)"), + /** + * 南粤银行 (信用卡) + */ + GDNYB_CREDIT("南粤银行 (信用卡)"), + /** + * 广州银行(信用卡) + */ + GZCB_CREDIT("广州银行(信用卡)"), + /** + * 江苏银行(借记卡) + */ + JSB_DEBIT("江苏银行(借记卡)"), + /** + * 江苏银行(信用卡) + */ + JSB_CREDIT("江苏银行(信用卡)"), + /** + * 宁波银行(借记卡) + */ + NBCB_DEBIT("宁波银行(借记卡)"), + /** + * 宁波银行(信用卡) + */ + NBCB_CREDIT("宁波银行(信用卡)"), + /** + * 南京银行(借记卡) + */ + NJCB_DEBIT("南京银行(借记卡)"), + /** + * 青岛银行(借记卡) + */ + QDCCB_DEBIT("青岛银行(借记卡)"), + /** + * 浙江泰隆银行(借记卡) + */ + ZJTLCB_DEBIT("浙江泰隆银行(借记卡)"), + /** + * 西安银行(借记卡) + */ + XAB_DEBIT("西安银行(借记卡)"), + /** + * 常熟农商银行 (借记卡) + */ + CSRCB_DEBIT("常熟农商银行 (借记卡)"), + /** + * 齐鲁银行(借记卡) + */ + QLB_DEBIT("齐鲁银行(借记卡)"), + /** + * 龙江银行(借记卡) + */ + LJB_DEBIT("龙江银行(借记卡)"), + /** + * 华夏银行(借记卡) + */ + HXB_DEBIT("华夏银行(借记卡)"), + /** + * 测试银行借记卡快捷支付 (借记卡) + */ + CS_DEBIT("测试银行借记卡快捷支付 (借记卡)"), + /** + * AE (信用卡) + */ + AE_CREDIT("AE (信用卡)"), + /** + * JCB (信用卡) + */ + JCB_CREDIT("JCB (信用卡)"), + /** + * MASTERCARD (信用卡) + */ + MASTERCARD_CREDIT("MASTERCARD (信用卡)"), + /** + * VISA (信用卡) + */ + VISA_CREDIT("VISA (信用卡)"); + + private String desc; + + BankType(String desc) { + this.desc = desc; + } + + public String getDesc() { + return desc; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CredentialType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CredentialType.java new file mode 100644 index 00000000..4cd93298 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CredentialType.java @@ -0,0 +1,23 @@ +package com.foxinmy.weixin4j.pay.type; + +/** + * 证件类型 + * + * @className CredentialType + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月27日 + * @since JDK 1.6 + * @see + */ +public enum CredentialType { + IDCARD("身份证"); + CredentialType(String name) { + this.name = name; + } + + private String name; + + public String getName() { + return this.name; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CurrencyType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CurrencyType.java new file mode 100644 index 00000000..21c288bc --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CurrencyType.java @@ -0,0 +1,25 @@ +package com.foxinmy.weixin4j.pay.type; + +/** + * 币种 + * + * @className CurrencyType + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月2日 + * @since JDK 1.6 + * @see + */ +public enum CurrencyType { + CNY("人民币"), HKD("港元"), TWD("台币"), EUR("欧元"), USD("美元"), GBP("英镑"), JPY("日元"), CAD( + "加拿大元"), AUD("澳大利亚元"), NZD("新西兰元"), KRW("韩元"), THB("泰铢"); + + private String desc; + + CurrencyType(String desc) { + this.desc = desc; + } + + public String getDesc() { + return desc; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsCity.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsCity.java new file mode 100644 index 00000000..2922c1a4 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsCity.java @@ -0,0 +1,26 @@ +package com.foxinmy.weixin4j.pay.type; + +/** + * 海关 + * + * @className CustomsCity + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月27日 + * @since JDK 1.6 + * @see + */ +public enum CustomsCity { + NO("无需上报海关"), GUANGZHOU("广州"), HANGZHOU("杭州"), NINGBO("宁波"), ZHENGZHOU_BS( + "郑州(保税物流中心)"), CHONGQING("重庆"), XIAN("西安"), SHANGHAI("上海"), ZHENGZHOU_ZH( + "郑州(综保区)"); + + private String name; + + CustomsCity(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsSatus.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsSatus.java new file mode 100644 index 00000000..55442274 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/CustomsSatus.java @@ -0,0 +1,24 @@ +package com.foxinmy.weixin4j.pay.type; + +/** + * 报关状态 + * + * @className CustomsSatus + * @author jinyu(foxinmy@gmail.com) + * @date 2016年3月27日 + * @since JDK 1.6 + * @see + */ +public enum CustomsSatus { + UNDECLARED("未申报"), SUBMITTED("申报已提交"), PROCESSING("申报中"), SUCCESS("申报成功"), FAIL( + "申报失败"), EXCEPT("海关接口异常"); + private String sate; + + CustomsSatus(String sate) { + this.sate = sate; + } + + public String getSate() { + return this.sate; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdQuery.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdQuery.java new file mode 100644 index 00000000..175a87ba --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdQuery.java @@ -0,0 +1,45 @@ +package com.foxinmy.weixin4j.pay.type; + +import java.io.Serializable; + +/** + * ID查询 + * + * @className IdQuery + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月1日 + * @since JDK 1.6 + * @see + */ +public class IdQuery implements Serializable { + + private static final long serialVersionUID = -5273675987521807370L; + /** + * id值 + */ + private String id; + /** + * id类型 + * + * @see IdType + */ + private IdType type; + + public IdQuery(String id, IdType idType) { + this.id = id; + this.type = idType; + } + + public String getId() { + return id; + } + + public IdType getType() { + return type; + } + + @Override + public String toString() { + return String.format("%s=%s", type.getName(), id); + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdType.java new file mode 100644 index 00000000..8af90392 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/IdType.java @@ -0,0 +1,46 @@ +package com.foxinmy.weixin4j.pay.type; + +/** + * ID类型 + * + * @className IdType + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月1日 + * @since JDK 1.6 + * @see + */ +public enum IdType { + /** + * 微信退款单号 + */ + REFUNDID("refund_id"), + /** + * 微信订单号 + */ + TRANSACTIONID("transaction_id"), + /** + * 商户订单号 + */ + TRADENO("out_trade_no"), + /** + * 商户退款号 + */ + REFUNDNO("out_refund_no"), + /** + * 商户子订单号 + */ + SUBORDERNO("sub_order_no"), + /** + * 微信子订单号 + */ + SUBORDERID("sub_order_id"); + private String name; + + IdType(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/SignType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/SignType.java new file mode 100644 index 00000000..4335ec4b --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/SignType.java @@ -0,0 +1,14 @@ +package com.foxinmy.weixin4j.pay.type; + +/** + * 签名类型 + * + * @className SignType + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月5日 + * @since JDK 1.6 + * @see + */ +public enum SignType { + SHA1, MD5, HMAC$SHA256 +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TarType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TarType.java new file mode 100644 index 00000000..bc4e32bb --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TarType.java @@ -0,0 +1,14 @@ +package com.foxinmy.weixin4j.pay.type; + +/** + * 压缩类型 + * + * @className TarType + * @author jinyu(foxinmy@gmail.com) + * @date 2016年12月21日 + * @since JDK 1.6 + * @see + */ +public enum TarType { + GZIP +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeType.java new file mode 100644 index 00000000..14e321c5 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/TradeType.java @@ -0,0 +1,33 @@ +package com.foxinmy.weixin4j.pay.type; + +/** + * 微信支付类型 + * + * @className TradeType + * @author jinyu(foxinmy@gmail.com) + * @date 2014年10月21日 + * @since JDK 1.6 + * @see + */ +public enum TradeType { + /** + * JS支付 + */ + JSAPI, + /** + * 刷卡支付 + */ + MICROPAY, + /** + * 扫码支付 + */ + NATIVE, + /** + * APP支付 + */ + APP, + /** + * WAP支付 + */ + MWEB; +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/BillType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/BillType.java new file mode 100644 index 00000000..85f1ab14 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/BillType.java @@ -0,0 +1,34 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 对账单类型 + * + * @className BillType + * @author jinyu(foxinmy@gmail.com) + * @date 2014年10月31日 + * @since JDK 1.6 + * @see + */ +public enum BillType { + /** + * 全部 + */ + ALL(0), + /** + * 成功订单 + */ + SUCCESS(1), + /** + * 退款订单 + */ + REFUND(2); + private int val; + + BillType(int val) { + this.val = val; + } + + public int getVal() { + return val; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CorpPaymentCheckNameType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CorpPaymentCheckNameType.java new file mode 100644 index 00000000..c109432f --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CorpPaymentCheckNameType.java @@ -0,0 +1,25 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 企业付款检查收款人姓名的策略 + * + * @className CorpPaymentCheckNameType + * @author jinyu(foxinmy@gmail.com) + * @date 2015年4月1日 + * @since JDK 1.6 + * @see + */ +public enum CorpPaymentCheckNameType { + /** + * 不校验真实姓名 + */ + NO_CHECK, + /** + * 强校验真实姓名(未实名认证的用户会校验失败,无法转账) + */ + FORCE_CHECK, + /** + * 针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功) + */ + OPTION_CHECK; +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStatus.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStatus.java new file mode 100644 index 00000000..696e073c --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStatus.java @@ -0,0 +1,34 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 代金券状态 + * + * @className CouponStatus + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月27日 + * @since JDK 1.6 + * @see + */ +public enum CouponStatus { + /** + * 已激活 + */ + ACTIVATED(2), + /** + * 已锁定 + */ + LOCKED(4), + /** + * 已实扣 + */ + USED(8); + private int val; + + CouponStatus(int val) { + this.val = val; + } + + public int getVal() { + return val; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockStatus.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockStatus.java new file mode 100644 index 00000000..36b6bd4b --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockStatus.java @@ -0,0 +1,42 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 代金券批次状态 + * + * @className CouponStockStatus + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月27日 + * @since JDK 1.6 + * @see + */ +public enum CouponStockStatus { + /** + * 未激活 + */ + INACTIVE(1), + /** + * 审批中 + */ + APPROVAL_PROCESS(2), + /** + * 已激活 + */ + ACTIVATED(4), + /** + * 已作废 + */ + SUPERSEDED(8), + /** + * 中止发放 + */ + SUSPEND(16); + private int val; + + CouponStockStatus(int val) { + this.val = val; + } + + public int getVal() { + return val; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockType.java new file mode 100644 index 00000000..896b8d7f --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponStockType.java @@ -0,0 +1,30 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 代金券批次类型 + * + * @className CouponStockType + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月27日 + * @since JDK 1.6 + * @see + */ +public enum CouponStockType { + /** + * 批量型 + */ + BATCH(1), + /** + * 触发型 + */ + TRIGGER(2); + private int val; + + CouponStockType(int val) { + this.val = val; + } + + public int getVal() { + return val; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponType.java new file mode 100644 index 00000000..6dd536fb --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/CouponType.java @@ -0,0 +1,43 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 代金券类型 + * + * @className CouponType + * @author jinyu(foxinmy@gmail.com) + * @date 2015年3月27日 + * @since JDK 1.6 + * @see + */ +public enum CouponType { + /** + * 使用无门槛 + */ + NO_THRESHOLD(1), + /** + * 使用有门槛 + */ + HAS_THRESHOLD(2), + /** + * 门槛叠加 + */ + THRESHOLD_PLUS(3), + + /** + * 充值代金券 + */ + CASH(-1), + /** + * 非充值代金券 + */ + NO_CASH(-2); + private int val; + + CouponType(int val) { + this.val = val; + } + + public int getVal() { + return val; + } +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSceneType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSceneType.java new file mode 100644 index 00000000..341542b2 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSceneType.java @@ -0,0 +1,44 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 发放红包使用场景 + * + * @className RedpacketSceneType + * @author jinyu(foxinmy@gmail.com) + * @date 2017年1月4日 + * @since JDK 1.6 + */ +public enum RedpacketSceneType { + /** + * 商品促销 + */ + PRODUCT_1, + /** + * 抽奖 + */ + PRODUCT_2, + /** + * 虚拟物品兑奖 + */ + PRODUCT_3, + /** + * 企业内部福利 + */ + PRODUCT_4, + /** + * 渠道分润 + */ + PRODUCT_5, + /** + * 保险回馈 + */ + PRODUCT_6, + /** + * 彩票派奖 + */ + PRODUCT_7, + /** + * 税务刮奖 + */ + PRODUCT_8 +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSendType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSendType.java new file mode 100644 index 00000000..55ba69b3 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketSendType.java @@ -0,0 +1,25 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 红包发放类型 + * + * @className RedpacketSendType + * @author jinyu(foxinmy@gmail.com) + * @date 2015年6月4日 + * @since JDK 1.6 + * @see + */ +public enum RedpacketSendType { + /** + * 通过API接口发放 + */ + API, + /** + * 通过上传文件方式发放 + */ + UPLOAD, + /** + * 通过活动方式发放 + */ + ACTIVITY; +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketStatus.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketStatus.java new file mode 100644 index 00000000..5b440ae7 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketStatus.java @@ -0,0 +1,32 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 红包状态 + * @className RedpacketStatus + * @author jinyu(foxinmy@gmail.com) + * @date 2015年6月4日 + * @since JDK 1.6 + * @see + */ +public enum RedpacketStatus { + /** + * 发放中 + */ + SENDING, + /** + * 已发放待领取 + */ + SENT, + /** + * 发放失败 + */ + FAILED, + /** + * 已领取 + */ + RECEIVED, + /** + * 已退款 + */ + REFUND; +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketType.java new file mode 100644 index 00000000..d59ed2c9 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RedpacketType.java @@ -0,0 +1,21 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 红包类型 + * + * @className RedpacketType + * @author jinyu(foxinmy@gmail.com) + * @date 2015年6月4日 + * @since JDK 1.6 + * @see + */ +public enum RedpacketType { + /** + * 裂变红包 + */ + GROUP, + /** + * 普通红包 + */ + NORMAL; +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundAccountType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundAccountType.java new file mode 100644 index 00000000..4e64b914 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundAccountType.java @@ -0,0 +1,18 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 退款资金来源 + * @className RefundAccountType + * @author jinyu(foxinmy@gmail.com) + * @date 2016年12月12日 + */ +public enum RefundAccountType { + /** + * ---未结算资金退款(默认使用未结算资金退款) + */ + REFUND_SOURCE_UNSETTLED_FUNDS, + /** + * ---可用余额退款 + */ + REFUND_SOURCE_RECHARGE_FUNDS +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundChannel.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundChannel.java new file mode 100644 index 00000000..40b01e07 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundChannel.java @@ -0,0 +1,37 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 退款渠道 + * + * @className RefundChannel + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月6日 + * @since JDK 1.6 + * @see + */ +public enum RefundChannel { + /** + * 原路退款 + */ + ORIGINAL, + /** + * 退回到余额 + */ + BALANCE, + /** + * 财付通 + */ + TENPAY, + /** + * 银行 + */ + BANK, + /** + * 原账户异常退到其他余额账户 + */ + OTHER_BALANCE, + /** + * 原银行卡异常退到其他银行卡 + */ + OTHER_BANKCARD +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundStatus.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundStatus.java new file mode 100644 index 00000000..b4fe3e2a --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundStatus.java @@ -0,0 +1,34 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 退款状态 + * + * @className RefundStatus + * @author jinyu(foxinmy@gmail.com) + * @date 2014年11月2日 + * @since JDK 1.6 + * @see + */ +public enum RefundStatus { + /** + * 退款成功 + */ + SUCCESS, + /** + * 退款失败 + */ + FAIL, + /** + * 退款处理中 + */ + PROCESSING, + /** + * 未确定,需要商户 原退款单号重新发起 + */ + NOTSURE, + /** + * 转入代发,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,资金回流到商户的现金帐号,需要商户人工干预,通过线下或者财付通转 + * 账的方式进行退款。 + */ + CHANGE; +} diff --git a/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundType.java b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundType.java new file mode 100644 index 00000000..fd96a037 --- /dev/null +++ b/weixin4j-pay/src/main/java/com/foxinmy/weixin4j/pay/type/mch/RefundType.java @@ -0,0 +1,35 @@ +package com.foxinmy.weixin4j.pay.type.mch; + +/** + * 退款类型 + * + * @className RefundType + * @author jinyu(foxinmy@gmail.com) + * @date 2014年12月31日 + * @since JDK 1.6 + * @see + */ +public enum RefundType { + /** + * 1:商户号余额退款; + */ + BALANCE(1), + /** + * 2:现金帐号 退款; + */ + CASH(2), + /** + * 3:优先商户号退款,若商户号余额不足, 再做现金帐号退款。 使用 2 或 3 时,需联系财 付通开通此功能 + */ + BOTH(3); + + private int val; + + RefundType(int val) { + this.val = val; + } + + public int getVal() { + return val; + } +}