卡券、企业付款及海关API加入pay子模块

This commit is contained in:
Kit 2019-09-17 15:16:54 +08:00
parent 86fc0712d0
commit 1c62b5e665
12 changed files with 2420 additions and 0 deletions

View File

@ -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: 退款查询接口

View File

@ -0,0 +1,819 @@
package com.foxinmy.weixin4j.pay;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.pay.api.*;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
import com.foxinmy.weixin4j.model.paging.Pageable;
import com.foxinmy.weixin4j.pay.payment.coupon.*;
import com.foxinmy.weixin4j.pay.payment.mch.*;
import com.foxinmy.weixin4j.pay.sign.WeixinSignature;
import com.foxinmy.weixin4j.pay.type.*;
import com.foxinmy.weixin4j.pay.type.mch.BillType;
import com.foxinmy.weixin4j.pay.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 <a href="http://pay.weixin.qq.com/wiki/doc/api/index.html">商户平台支付API</a>
*/
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();
}
/**
* 统一下单接口</br>
* 除被扫支付场景以外商户系统先调用该接口在微信支付服务后台生成预支付交易单返回正确的预支付交易回话标识后再按扫码JSAPI
* APP等不同场景生成交易串调起支付
*
* @param payPackage
* 包含订单信息的对象
* @see PayApi
* @see MchPayPackage
* @see PrePay
* @see <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1">统一下单接口
* </a>
* @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);
}
/**
* <p>
* 生成编辑地址请求
* </p>
*
* err_msg edit_address:ok获取编辑收货地址成功</br> edit_address:fail获取编辑收货地址失败</br>
* userName 收货人姓名</br> telNumber 收货人电话</br> addressPostalCode 邮编</br>
* proviceFirstStageName 国标收货地址第一级地址</br> addressCitySecondStageName
* 国标收货地址第二级地址</br> addressCountiesThirdStageName 国标收货地址第三级地址</br>
* addressDetailInfo 详细收货地址信息</br> nationalCode 收货地址国家码</br>
*
* @param url
* 当前访问页的URL
* @param oauthToken
* oauth授权时产生的token
* @see PayApi
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_8&index=7">
* 收货地址共享</a>
* @return 编辑地址请求JSON串
*/
public String createAddressRequestJSON(String url, String oauthToken) {
return payApi.createAddressRequestJSON(url, oauthToken);
}
/**
* 创建Native支付(扫码支付)链接模式一
*
* @param productId
* 与订单ID等价
* @return 支付链接
* @see PayApi
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1">扫码支付
* </a>
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4">模式一
* </a>
*/
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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1">扫码支付
* </a>
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4">模式一
* </a>
* @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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1">扫码支付
* </a>
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5">模式二
* </a>
* @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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1">
* APP支付</a>
* @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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/wap.php?chapter=15_1">WAP支付
* </a>
* @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 <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10">
* 提交被扫支付API</a>
* @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);
}
/**
* 订单查询
* <p>
* 当商户后台网络服务器等出现异常商户系统最终未接收到支付通知</br> 调用支付接口后返回系统错误或未知交易状态情况</br>
* 调用被扫支付API返回USERPAYING的状态</br> 调用关单或撤销接口API之前需确认支付状态
* </P>
*
* @param idQuery
* 商户系统内部的订单号, transaction_idout_trade_no 选一,如果同时存在优先级:
* transaction_id> out_trade_no
* @since V3
* @see Order
* @see PayApi
* @see <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2">
* 订单查询API</a>
* @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);
}
/**
* 退款查询
* <p>
* 提交退款申请后通过调用该接口查询退款状态退款有一定延时用零钱支付的退款20分钟内到账银行卡支付的退款3个工作日后重新查询退款状态
* </p>
*
* @param idQuery
* 单号 refund_idout_refund_no out_trade_no transaction_id
* 四个参数必填一个,优先级为:
* refund_id>out_refund_no>transaction_id>out_trade_no
* @return 退款记录
* @see PayApi
* @see RefundRecord
* @see <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5">
* 退款查询API</a>
* @since V3
* @throws WeixinException
*/
public RefundRecord queryRefund(IdQuery idQuery) throws WeixinException {
return payApi.queryRefund(idQuery);
}
/**
* 下载对账单<br>
* 1.微信侧未成功下单的交易不会出现在对账单中支付成功后撤销的交易会出现在对账 单中,跟原支付单订单号一致,bill_type
* REVOKED;<br>
* 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;<br>
* 3.对账单中涉及金额的字段单位为<br>
*
* @param billDate
* 下载对账单的日期
* @param billType
* 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单
* REFUND,返回当日退款订单
* @para outputStream 输出流
* @param tarType
* 非必传参数固定值GZIP返回格式为.gzip的压缩包账单不传则默认为数据流形式
* @since V2 & V3
* @see PayApi
* @see <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">
* 下载对账单API</a>
* @throws WeixinException
*/
public void downloadBill(Date billDate, BillType billType,
OutputStream outputStream, TarType tarType) throws WeixinException {
payApi.downloadBill(billDate, billType, outputStream, tarType);
}
/**
* 冲正订单(需要证书)</br> 当支付返回失败,或收银系统超时需要取消交易,可以调用该接口</br> 接口逻辑:
* 付失败的关单,支付成功的撤销支付</br> <font color="red">7天以内的单可撤销,其他正常支付的单
* 如需实现相同功能请调用退款接口</font></br> <font
* color="red">调用扣款接口后请勿立即调用撤销,需要等待5秒以上先调用查单接口,如果没有确切的返回,再调用撤销</font> </br>
*
* @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);
}
/**
* 关闭订单
* <p>
* 商户订单支付失败需要生成新单号重新发起支付要对原订单号调用关单避免重复支付系统下单后用户支付超时系统退出不再受理避免用户继续
* 请调用关单接口,如果关单失败,返回已完 成支付请按正常支付处理如果出现银行掉单,调用关单成功后,微信后台会主动发起退款
* </p>
*
* @param outTradeNo
* 商户系统内部的订单号
* @return 执行结果
* @see PayApi
* @since V3
* @throws WeixinException
* @see <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3">
* 关闭订单API</a>
*/
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 <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_9">
* 转换短链接API</a>
* @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 <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_8">
* 接口测试上报API</a>
* @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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_3">
* 发放代金券接口</a>
* @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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_4">
* 查询代金券批次信息接口</a>
* @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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_5">
* 查询代金券详细信息接口</a>
* @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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5">
* 发放现金红包接口</a>
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=16_5">
* 发放裂变红包接口</a>
* @throws WeixinException
*/
public RedpacketSendResult sendRedpack(Redpacket redpacket)
throws WeixinException {
return cashApi.sendRedpack(redpacket);
}
/**
* 批量发放红包 企业向微信用户个人发现金红包
*
* @param redpackets
* 多个红包信息
* @return 发放结果
* @see CashApi
* @see #sendRedpacks(Redpacket...)
* @throws WeixinException
*/
public List<Future<RedpacketSendResult>> sendRedpacks(
Redpacket... redpackets) {
return cashApi.sendRedpacks(redpackets);
}
/**
* 查询红包记录
*
* @param outTradeNo
* 商户发放红包的商户订单号
* @return 红包记录
* @see CashApi
* @see RedpacketRecord
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_7&index=6">
* 查询现金红包接口</a>
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=16_6">
* 查询裂变红包接口</a>
* @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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3">
* 企业付款查询接口</a>
* @throws WeixinException
*/
public CorpPaymentRecord queryCorpPayment(String outTradeNo)
throws WeixinException {
return cashApi.queryCorpPayment(outTradeNo);
}
/**
* 授权码查询OPENID
*
* @param authCode
* 扫码支付授权码设备读取用户微信中的条码或者二维码信息
* @return 查询结果
* @see CashApi
* @see OpenIdResult
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_13&index=9">
* 授权码查询OPENID</a>
* @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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/external/micropay.php?chapter=9_14&index=7">
* 查询结算资金接口</a>
*/
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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/external/micropay.php?chapter=9_15&index=8">
* 查询汇率接口</a>
*/
public double queryExchageRate(CurrencyType currencyType, Date date)
throws WeixinException {
return cashApi.queryExchageRate(currencyType, date);
}
/**
* 订单附加信息提交
*
* @param customsOrder
* 附加订单信息
* @return 报关结果
* @see CustomsApi
* @see CustomsOrder
* @see CustomsOrderResult
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/external/declarecustom.php?chapter=18_1">
* 附加订单信息提交接口</a>
* @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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/external/declarecustom.php?chapter=18_1">
* 附加订单信息查询接口</a>
* @throws WeixinException
*/
public CustomsOrderRecord queryCustomsOrder(IdQuery idQuery,
CustomsCity customsCity) throws WeixinException {
return customsApi.queryCustomsOrder(idQuery, customsCity);
}
public final static String VERSION = Consts.VERSION;
}

View File

@ -0,0 +1,269 @@
package com.foxinmy.weixin4j.pay.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
import com.foxinmy.weixin4j.model.paging.Pageable;
import com.foxinmy.weixin4j.pay.payment.mch.*;
import com.foxinmy.weixin4j.pay.type.CurrencyType;
import com.foxinmy.weixin4j.util.DateUtil;
import com.foxinmy.weixin4j.util.RandomUtil;
import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.xml.XmlStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
/**
* 现金API
*
* @className CashApi
* @author jinyu(foxinmy@gmail.com)
* @date 2015年3月28日
* @since JDK 1.6
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_1">
* 现金红包</a>
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1">
* 企业付款</a>
*/
public class CashApi extends MchApi {
public CashApi(WeixinPayAccount weixinAccount) {
super(weixinAccount);
}
/**
* 发放红包 企业向微信用户个人发现金红包
*
* @param redpacket
* 红包信息
* @return 发放结果
* @see Redpacket
* @see RedpacketSendResult
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5">
* 发放现金红包接口</a>
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=16_5">
* 发放裂变红包接口</a>
* @throws WeixinException
*/
public RedpacketSendResult sendRedpack(Redpacket redpacket)
throws WeixinException {
String appId = redpacket.getAppId();
super.declareMerchant(redpacket);
final JSONObject obj = (JSONObject) JSON.toJSON(redpacket);
if (StringUtil.isNotBlank(appId)) {
obj.put("appid", appId);
}
obj.put("wxappid", obj.remove("appid"));
final String redpack_uri = redpacket.getTotalNum() > 1 ? getRequestUri("groupredpack_send_uri")
: getRequestUri("redpack_send_uri");
obj.put("sign", weixinSignature.sign(obj));
String param = XmlStream.map2xml(obj);
WeixinResponse response = getWeixinSSLExecutor().post(redpack_uri,
param);
String text = response.getAsString()
.replaceFirst("<wxappid>", "<appid>")
.replaceFirst("</wxappid>", "</appid>");
return XmlStream.fromXML(text, RedpacketSendResult.class);
}
/**
* 批量发放红包 企业向微信用户个人发现金红包
*
* 多个红包信息
* @return 发放结果
* @see #sendRedpacks(Redpacket...)
* @throws WeixinException
*/
public List<Future<RedpacketSendResult>> sendRedpacks(
Redpacket... redpackets) {
ExecutorService sendExecutor = Executors.newFixedThreadPool(Math.max(1,
redpackets.length / 10)); // 十分之一?
CompletionService<RedpacketSendResult> completion = new ExecutorCompletionService<RedpacketSendResult>(
sendExecutor);
List<Future<RedpacketSendResult>> callSendList = new ArrayList<Future<RedpacketSendResult>>(
redpackets.length);
for (final Redpacket redpacket : redpackets) {
Future<RedpacketSendResult> futureSend = completion
.submit(new Callable<RedpacketSendResult>() {
@Override
public RedpacketSendResult call() throws Exception {
return sendRedpack(redpacket);
}
});
callSendList.add(futureSend);
}
// 关闭启动线程,不再接受新的任务
sendExecutor.shutdown();
return callSendList;
}
/**
* 查询红包记录
*
* @param outTradeNo
* 商户发放红包的商户订单号
* @return 红包记录
* @see RedpacketRecord
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_7&index=6">
* 查询现金红包接口</a>
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=16_6">
* 查询裂变红包接口</a>
* @throws WeixinException
*/
public RedpacketRecord queryRedpack(String outTradeNo)
throws WeixinException {
Map<String, String> para = createBaseRequestMap(null);
para.put("bill_type", "MCHT");
para.put("mch_billno", outTradeNo);
para.put("sign", weixinSignature.sign(para));
String param = XmlStream.map2xml(para);
WeixinResponse response = getWeixinSSLExecutor().post(
getRequestUri("redpack_query_uri"), param);
return response.getAsObject(new TypeReference<RedpacketRecord>() {
});
}
/**
* 企业付款为企业提供付款至用户零钱的能力
*
* @param payment 付款信息
* @return 付款结果
* @see CorpPayment
* @see CorpPaymentResult
* @see <a href="https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2">企业付款</a>
* @see <a href="https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1">场景介绍使用条件付款资金付款规则等</a>
* @throws WeixinException
*/
public CorpPaymentResult sendCorpPayment(CorpPayment payment)
throws WeixinException {
super.declareMerchant(payment);
JSONObject obj = (JSONObject) JSON.toJSON(payment);
obj.put("mchid", obj.remove("mch_id"));
obj.put("mch_appid", obj.remove("appid"));
obj.put("sign", weixinSignature.sign(obj));
String param = XmlStream.map2xml(obj);
WeixinResponse response = getWeixinSSLExecutor().post(
getRequestUri("corppayment_send_uri"), param);
String text = response.getAsString()
.replaceFirst("<mch_appid>", "<appid>")
.replaceFirst("</mch_appid>", "</appid>")
.replaceFirst("<mchid>", "<mch_id>")
.replaceFirst("</mchid>", "</mch_id>");
return XmlStream.fromXML(text, CorpPaymentResult.class);
}
/**
* 企业付款查询 用于商户的企业付款操作进行结果查询返回付款操作详细结果
*
* @param outTradeNo
* 商户调用企业付款API时使用的商户订单号
* @return 付款记录
* @see CorpPaymentRecord
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3">
* 企业付款查询接口</a>
* @throws WeixinException
*/
public CorpPaymentRecord queryCorpPayment(String outTradeNo)
throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("nonce_str", RandomUtil.generateString(16));
obj.put("mch_id", weixinAccount.getMchId());
obj.put("appid", weixinAccount.getId());
obj.put("partner_trade_no", outTradeNo);
obj.put("sign", weixinSignature.sign(obj));
String param = XmlStream.map2xml(obj);
WeixinResponse response = getWeixinSSLExecutor().post(
getRequestUri("corppayment_query_uri"), param);
return response.getAsObject(new TypeReference<CorpPaymentRecord>() {
});
}
/**
* 查询结算资金
*
* @param status
* 是否结算
* @param pageable
* 分页数据
* @param start
* 开始日期 查询未结算记录时该字段可不传
* @param end
* 结束日期 查询未结算记录时该字段可不传
* @return 结算金额记录
* @throws WeixinException
* @see SettlementRecord
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/external/micropay.php?chapter=9_14&index=7">
* 查询结算资金接口</a>
*/
public SettlementRecord querySettlement(boolean status, Pageable pageable,
Date start, Date end) throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("nonce_str", RandomUtil.generateString(16));
obj.put("mch_id", weixinAccount.getMchId());
obj.put("appid", weixinAccount.getId());
obj.put("usetag", status ? 1 : 2);
obj.put("offset", pageable.getOffset());
obj.put("limit", pageable.getPageSize());
if (start != null) {
obj.put("date_start", DateUtil.fortmat2yyyyMMdd(start));
}
if (end != null) {
obj.put("date_end", DateUtil.fortmat2yyyyMMdd(end));
}
obj.put("sign", weixinSignature.sign(obj));
String param = XmlStream.map2xml(obj);
WeixinResponse response = weixinExecutor.post(
getRequestUri("settlement_query_uri"), param);
return response.getAsObject(new TypeReference<SettlementRecord>() {
});
}
/**
* 查询汇率
*
* @param currencyType
* 外币币种
* @param date
* 日期 不填则默认当天
* @return 汇率 例如美元兑换人民币的比例为6.5
* @throws WeixinException
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/external/micropay.php?chapter=9_15&index=8">
* 查询汇率接口</a>
*/
public double queryExchageRate(CurrencyType currencyType, Date date)
throws WeixinException {
if (date == null) {
date = new Date();
}
JSONObject obj = new JSONObject();
obj.put("mch_id", weixinAccount.getMchId());
obj.put("appid", weixinAccount.getId());
obj.put("sub_mch_id", weixinAccount.getSubMchId());
obj.put("fee_type", currencyType.name());
obj.put("date", DateUtil.fortmat2yyyyMMdd(date));
obj.put("sign", weixinSignature.sign(obj));
String param = XmlStream.map2xml(obj);
WeixinResponse response = weixinExecutor.post(
getRequestUri("exchagerate_query_uri"), param);
BigDecimal rate = new BigDecimal(XmlStream.xml2map(
response.getAsString()).get("rate"));
return rate.divide(new BigDecimal(100000000d)).doubleValue();
}
}

View File

@ -0,0 +1,122 @@
package com.foxinmy.weixin4j.pay.api;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
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.util.StringUtil;
import com.foxinmy.weixin4j.xml.XmlStream;
import java.util.Map;
/**
* 代金券API
*
* @className CouponApi
* @author jinyu(foxinmy@gmail.com)
* @date 2015年3月25日
* @since JDK 1.6
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_1">代金券</a>
*/
public class CouponApi extends MchApi {
public CouponApi(WeixinPayAccount weixinAccount) {
super(weixinAccount);
}
/**
* 发放代金券(需要证书)
*
* @param couponStockId
* 代金券批次id
* @param partnerTradeNo
* 商户发放凭据号格式商户id+日期+流水号商户侧需保持唯一性
* @param openId
* 用户的openid
* @param opUserId
* 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限 可为空
* @return 发放结果
* @see CouponResult
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_3">发放代金券接口</a>
* @throws WeixinException
*/
public CouponResult sendCoupon(String couponStockId, String partnerTradeNo,
String openId, String opUserId) throws WeixinException {
Map<String, String> map = createBaseRequestMap(null);
map.put("coupon_stock_id", couponStockId);
map.put("partner_trade_no", partnerTradeNo);
map.put("openid", openId);
// openid记录数目前支持num=1
map.put("openid_count", "1");
// 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限
if (StringUtil.isBlank(opUserId)) {
opUserId = weixinAccount.getMchId();
}
map.put("op_user_id", opUserId);
map.put("version", "1.0");
map.put("type", "XML");
map.put("sign", weixinSignature.sign(map));
String param = XmlStream.map2xml(map);
WeixinResponse response = getWeixinSSLExecutor().post(
getRequestUri("coupon_send_uri"), param);
return response.getAsObject(new TypeReference<CouponResult>() {
});
}
/**
* 查询代金券批次
*
* @param couponStockId
* 代金券批次ID
* @return 代金券批次信息
* @see CouponStock
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_4">查询代金券批次信息接口</a>
* @throws WeixinException
*/
public CouponStock queryCouponStock(String couponStockId)
throws WeixinException {
Map<String, String> map = createBaseRequestMap(null);
map.put("coupon_stock_id", couponStockId);
map.put("sign", weixinSignature.sign(map));
String param = XmlStream.map2xml(map);
WeixinResponse response = weixinExecutor.post(
getRequestUri("couponstock_query_uri"), param);
return response.getAsObject(new TypeReference<CouponStock>() {
});
}
/**
* 查询代金券详细
*
* @param openId
* 用户ID
* @param couponId
* 代金券ID
* @param stockId
* 代金劵对应的批次号
* @return 代金券详细信息
* @see CouponDetail
* @see <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_5">查询代金券详细信息接口</a>
* @throws WeixinException
*/
public CouponDetail queryCouponDetail(String openId, String couponId,
String stockId) throws WeixinException {
Map<String, String> map = createBaseRequestMap(null);
map.put("openid", openId);
map.put("coupon_id", couponId);
map.put("stock_id", stockId);
map.put("sign", weixinSignature.sign(map));
String param = XmlStream.map2xml(map);
WeixinResponse response = weixinExecutor.post(
getRequestUri("coupondetail_query_uri"), param);
return response.getAsObject(new TypeReference<CouponDetail>() {
});
}
}

View File

@ -0,0 +1,84 @@
package com.foxinmy.weixin4j.pay.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
import com.foxinmy.weixin4j.pay.payment.mch.CustomsOrder;
import com.foxinmy.weixin4j.pay.payment.mch.CustomsOrderRecord;
import com.foxinmy.weixin4j.pay.payment.mch.CustomsOrderResult;
import com.foxinmy.weixin4j.pay.type.CustomsCity;
import com.foxinmy.weixin4j.pay.type.IdQuery;
import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer;
import com.foxinmy.weixin4j.xml.XmlStream;
/**
* 报关接口
*
* @className CustomsApi
* @author jinyu(foxinmy@gmail.com)
* @date 2016年3月67日
* @since JDK 1.6
* @see
*/
public class CustomsApi extends MchApi {
public CustomsApi(WeixinPayAccount weixinAccount) {
super(weixinAccount);
}
/**
* 订单附加信息提交
*
* @param customsOrder
* 附加订单信息
* @return 报关结果
* @see CustomsOrder
* @see CustomsOrderResult
* @see <a
* href="https://pay.weixin.qq.com/wiki/doc/api/external/declarecustom.php?chapter=18_1">附加订单信息提交接口</a>
* @throws WeixinException
*/
public CustomsOrderResult declareCustomsOrder(CustomsOrder customsOrder)
throws WeixinException {
JSONObject para = (JSONObject) JSON.toJSON(customsOrder);
para.put("appid", weixinAccount.getId());
para.put("mch_id", weixinAccount.getMchId());
para.put("sign", weixinSignature.sign(para));
String param = XmlStream.map2xml(para);
WeixinResponse response = weixinExecutor.post(
getRequestUri("customsorder_declare_uri"), param);
return response.getAsObject(new TypeReference<CustomsOrderResult>() {
});
}
/**
* 订单附加信息查询
*
* @param idQuery
* out_trade_no,transaction_id,sub_order_no,sub_order_id四选一
* @param customsCity
* 海关
* @return 报关记录
* @see CustomsOrderRecord
* @see <a
* href="https://pay.weixin.qq.com/wiki/doc/api/external/declarecustom.php?chapter=18_1">附加订单信息查询接口</a>
* @throws WeixinException
*/
public CustomsOrderRecord queryCustomsOrder(IdQuery idQuery,
CustomsCity customsCity) throws WeixinException {
JSONObject para = new JSONObject();
para.put("appid", weixinAccount.getId());
para.put("mch_id", weixinAccount.getMchId());
para.put(idQuery.getType().getName(), idQuery.getId());
para.put("customs", customsCity.name());
para.put("sign", weixinSignature.sign(para));
String param = XmlStream.map2xml(para);
WeixinResponse response = weixinExecutor.post(
getRequestUri("customsorder_query_uri"), param);
return ListsuffixResultDeserializer.deserialize(response.getAsString(),
CustomsOrderRecord.class);
}
}

View File

@ -0,0 +1,377 @@
package com.foxinmy.weixin4j.pay.payment.coupon;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult;
import com.foxinmy.weixin4j.pay.type.mch.CouponStatus;
import com.foxinmy.weixin4j.pay.type.mch.CouponStockType;
import com.foxinmy.weixin4j.pay.type.mch.CouponType;
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 CouponDetail
* @author jinyu(foxinmy@gmail.com)
* @date 2015年3月27日
* @since JDK 1.6
* @see
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class CouponDetail extends MerchantResult {
private static final long serialVersionUID = -311265355895457070L;
/**
* 代金券批次Id
*/
@XmlElement(name = "coupon_stock_id")
@JSONField(name = "coupon_stock_id")
private String couponStockId;
/**
* 批次类型1-批量型2-触发型
*/
@XmlElement(name = "coupon_stock_type")
@JSONField(name = "coupon_stock_type")
private int couponStockType;
/**
* 代金券id
*/
@XmlElement(name = "coupon_id")
@JSONField(name = "coupon_id")
private String couponId;
/**
* 代金券面值,单位是分
*/
@XmlElement(name = "coupon_value")
@JSONField(name = "coupon_value")
private int couponValue;
/**
* 代金券使用最低限额,单位是分
*/
@XmlElement(name = "coupon_mininum")
@JSONField(name = "coupon_mininum")
private int couponMininum;
/**
* 代金券名称
*/
@XmlElement(name = "coupon_name")
@JSONField(name = "coupon_name")
private String couponName;
/**
* 代金券状态2-已激活4-已锁定8-已实扣
*/
@XmlElement(name = "coupon_state")
@JSONField(name = "coupon_state")
private int couponStatus;
/**
* 代金券类型1-代金券无门槛2-代金券有门槛互斥3-代金券有门槛叠加
*/
@XmlElement(name = "coupon_type")
@JSONField(name = "coupon_type")
private int couponType;
/**
* 代金券描述
*/
@XmlElement(name = "coupon_desc")
@JSONField(name = "coupon_desc")
private String couponDesc;
/**
* 代金券实际使用金额
*/
@XmlElement(name = "coupon_use_value")
@JSONField(name = "coupon_use_value")
private int couponUseValue;
/**
* 代金券剩余金额部分使用情况下可能会存在券剩余金额
*/
@XmlElement(name = "coupon_remain_value")
@JSONField(name = "coupon_remain_value")
private int couponRemainValue;
/**
* 生效开始时间:格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XmlElement(name = "begin_time")
@JSONField(name = "begin_time")
private String beginTime;
/**
* 生效结束时间:格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XmlElement(name = "end_time")
@JSONField(name = "end_time")
private String endTime;
/**
* 发放时间:格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XmlElement(name = "send_time")
@JSONField(name = "send_time")
private String sendTime;
/**
* 使用时间:格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XmlElement(name = "use_time")
@JSONField(name = "use_time")
private String useTime;
/**
* 使用单号:代金券使用后关联的大单收单单号
*/
@XmlElement(name = "trade_no")
@JSONField(name = "trade_no")
private String tradeNo;
/**
* 消耗方商户id:代金券使用后消耗方商户id
*/
@XmlElement(name = "consumer_mch_id")
@JSONField(name = "consumer_mch_id")
private String consumerMchId;
/**
* 消耗方商户名称:代金券使用后消耗方商户名称
*/
@XmlElement(name = "consumer_mch_name")
@JSONField(name = "consumer_mch_name")
private String consumerMchName;
/**
* 消耗方商户appid:代金券使用后消耗方商户appid
*/
@XmlElement(name = "consumer_mch_appid")
@JSONField(name = "consumer_mch_appid")
private String consumerMchAppid;
/**
* 发放来源:代金券发放来源
*/
@XmlElement(name = "send_source")
@JSONField(name = "send_source")
private String sendSource;
/**
* 是否允许部分使用:该代金券是否允许部分使用标识1-表示支持部分使用
*/
@XmlElement(name = "is_partial_use")
@JSONField(name = "is_partial_use")
private int isPartialUse;
public CouponDetail() {
}
public String getCouponStockId() {
return couponStockId;
}
public int getCouponStockType() {
return couponStockType;
}
@JSONField(serialize = false)
public CouponStockType getFormatCouponStockType() {
for (CouponStockType couponStockType : CouponStockType.values()) {
if (couponStockType.getVal() == this.couponStockType) {
return couponStockType;
}
}
return null;
}
public String getCouponId() {
return couponId;
}
public int getCouponValue() {
return couponValue;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCouponValue() {
return couponValue / 100d;
}
public int getCouponMininum() {
return couponMininum;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCouponMininum() {
return couponMininum / 100d;
}
public String getCouponName() {
return couponName;
}
public int getCouponStatus() {
return couponStatus;
}
@JSONField(serialize = false)
public CouponStatus getFormatCouponStatus() {
for (CouponStatus couponStatus : CouponStatus.values()) {
if (couponStatus.getVal() == this.couponStatus) {
return couponStatus;
}
}
return null;
}
public int getCouponType() {
return couponType;
}
@JSONField(deserialize = false, serialize = false)
public CouponType getFormatCouponType() {
for (CouponType couponType : CouponType.values()) {
if (couponType.getVal() == this.couponType) {
return couponType;
}
}
return null;
}
public String getCouponDesc() {
return couponDesc;
}
public int getCouponUseValue() {
return couponUseValue;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCouponUseValue() {
return couponUseValue / 100d;
}
public int getCouponRemainValue() {
return couponRemainValue;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCouponRemainValue() {
return couponRemainValue / 100d;
}
public String getBeginTime() {
return beginTime;
}
@JSONField(serialize = false)
public Date getFormatBeginTime() {
return beginTime != null ? DateUtil.parse2yyyyMMddHHmmss(beginTime)
: null;
}
public String getEndTime() {
return endTime;
}
@JSONField(serialize = false)
public Date getFormatEndTime() {
return endTime != null ? DateUtil.parse2yyyyMMddHHmmss(endTime) : null;
}
public String getSendTime() {
return sendTime;
}
@JSONField(serialize = false)
public Date getFormatSendTime() {
return sendTime != null ? DateUtil.parse2yyyyMMddHHmmss(sendTime)
: null;
}
public String getUseTime() {
return useTime;
}
@JSONField(serialize = false)
public Date getFormatUseTime() {
return useTime != null ? DateUtil.parse2yyyyMMddHHmmss(useTime) : null;
}
public String getTradeNo() {
return tradeNo;
}
public String getConsumerMchId() {
return consumerMchId;
}
public String getConsumerMchName() {
return consumerMchName;
}
public String getConsumerMchAppid() {
return consumerMchAppid;
}
public String getSendSource() {
return sendSource;
}
public int getIsPartialUse() {
return isPartialUse;
}
@JSONField(serialize = false)
public boolean getFormatIsPartialUse() {
return isPartialUse == 1;
}
@Override
public String toString() {
return "CouponDetail [couponStockId=" + couponStockId
+ ", couponStockType=" + getFormatCouponStockType()
+ ", couponId=" + couponId + ", couponValue="
+ getFormatCouponValue() + ", couponMininum="
+ getFormatCouponMininum() + ", couponName=" + couponName
+ ", couponStatus=" + getCouponStatus() + ", couponType="
+ getFormatCouponType() + ", couponDesc=" + couponDesc
+ ", couponUseValue=" + getFormatCouponUseValue()
+ ", couponRemainValue=" + getFormatCouponRemainValue()
+ ", beginTime=" + getFormatBeginTime() + ", endTime="
+ getFormatEndTime() + ", sendTime=" + getFormatSendTime()
+ ", useTime=" + getFormatUseTime() + ", tradeNo=" + tradeNo
+ ", consumerMchId=" + consumerMchId + ", consumerMchName="
+ consumerMchName + ", consumerMchAppid=" + consumerMchAppid
+ ", sendSource=" + sendSource + ", isPartialUse="
+ getFormatIsPartialUse() + ", " + super.toString() + "]";
}
}

View File

@ -0,0 +1,119 @@
package com.foxinmy.weixin4j.pay.payment.coupon;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult;
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 CouponResult
* @author jinyu(foxinmy@gmail.com)
* @date 2015年3月25日
* @since JDK 1.6
* @see
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class CouponResult extends MerchantResult {
private static final long serialVersionUID = -1996967923720149124L;
/**
* 代金券批次id
*/
@XmlElement(name = "coupon_stock_id")
@JSONField(name = "coupon_stock_id")
private String couponStockId;
/**
* 返回记录数
*/
@XmlElement(name = "resp_count")
@JSONField(name = "resp_count")
private int responseCount;
/**
* 成功记录数
*/
@XmlElement(name = "success_count")
@JSONField(name = "success_count")
private int successCount;
/**
* 失败记录数
*/
@XmlElement(name = "failed_count")
@JSONField(name = "failed_count")
private int failedCount;
/**
* 用户在商户appid下的唯一标识
*/
@XmlElement(name = "openid")
@JSONField(name = "openid")
private String openId;
/**
* 返回码 SUCCESS或者FAILED
*/
@XmlElement(name = "ret_code")
@JSONField(name = "ret_code")
private String retCode;
/**
* 代金券id
*/
@XmlElement(name = "coupon_id")
@JSONField(name = "coupon_id")
private String couponId;
/**
* 失败描述信息例如用户已达领用上限
*/
@XmlElement(name = "ret_msg")
@JSONField(name = "ret_msg")
private String retMsg;
public CouponResult() {
}
public String getCouponStockId() {
return couponStockId;
}
public int getResponseCount() {
return responseCount;
}
public int getSuccessCount() {
return successCount;
}
public int getFailedCount() {
return failedCount;
}
public String getOpenId() {
return openId;
}
public String getRetCode() {
return retCode;
}
public String getCouponId() {
return couponId;
}
public String getRetMsg() {
return retMsg;
}
@Override
public String toString() {
return "CouponResult [couponStockId=" + couponStockId
+ ", responseCount=" + responseCount + ", successCount="
+ successCount + ", failedCount=" + failedCount + ", openId="
+ openId + ", retCode=" + retCode + ", couponId=" + couponId
+ ", retMsg=" + retMsg + "]";
}
}

View File

@ -0,0 +1,307 @@
package com.foxinmy.weixin4j.pay.payment.coupon;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.pay.payment.mch.MerchantResult;
import com.foxinmy.weixin4j.pay.type.mch.CouponStockStatus;
import com.foxinmy.weixin4j.pay.type.mch.CouponType;
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 CouponStock
* @author jinyu(foxinmy@gmail.com)
* @date 2015年3月27日
* @since JDK 1.6
* @see
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class CouponStock extends MerchantResult {
private static final long serialVersionUID = -8627202879200080499L;
/**
* 代金券批次ID
*/
@XmlElement(name = "coupon_stock_id")
@JSONField(name = "coupon_stock_id")
private String couponStockId;
/**
* 代金券名称
*/
@XmlElement(name = "coupon_name")
@JSONField(name = "coupon_name")
private String couponName;
/**
* 代金券面额
*/
@XmlElement(name = "coupon_value")
@JSONField(name = "coupon_value")
private int couponValue;
/**
* 代金券使用最低限额
*/
@XmlElement(name = "coupon_mininumn")
@JSONField(name = "coupon_mininumn")
private Integer couponMininumn;
/**
* 代金券类型1-代金券无门槛2-代金券有门槛互斥3-代金券有门槛叠加
*/
@XmlElement(name = "coupon_type")
@JSONField(name = "coupon_type")
private int couponType;
/**
* 批次状态: 1-未激活2-审批中4-已激活8-已作废16-中止发放
*/
@XmlElement(name = "coupon_stock_status")
@JSONField(name = "coupon_stock_status")
private int couponStockStatus;
/**
* 代金券数量
*/
@XmlElement(name = "coupon_total")
@JSONField(name = "coupon_total")
private int couponTotal;
/**
* 代金券每个人最多能领取的数量, 如果为0则表示没有限制
*/
@XmlElement(name = "max_quota")
@JSONField(name = "max_quota")
private Integer maxQuota;
/**
* 代金券锁定数量
*/
@XmlElement(name = "locked_num")
@JSONField(name = "locked_num")
private Integer lockedNum;
/**
* 代金券已使用数量
*/
@XmlElement(name = "used_num")
@JSONField(name = "used_num")
private Integer usedNum;
/**
* 代金券已经发送的数量
*/
@XmlElement(name = "is_send_num")
@JSONField(name = "is_send_num")
private Integer sendNum;
/**
* 生效开始时间 格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XmlElement(name = "begin_time")
@JSONField(name = "begin_time")
private String beginTime;
/**
* 生效结束时间 格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XmlElement(name = "end_time")
@JSONField(name = "end_time")
private String endTime;
/**
* 创建时间 格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XmlElement(name = "create_time")
@JSONField(name = "create_time")
private String createTime;
/**
* 代金券预算额度
*/
@XmlElement(name = "coupon_budget")
@JSONField(name = "coupon_budget")
private Integer couponBudget;
public CouponStock() {
}
public String getCouponStockId() {
return couponStockId;
}
public String getCouponName() {
return couponName;
}
public int getCouponValue() {
return couponValue;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCouponValue() {
return couponValue / 100d;
}
public Integer getCouponMininumn() {
return couponMininumn;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCouponMininumn() {
return couponMininumn != null ? couponMininumn.intValue() / 100d : 0d;
}
public int getCouponType() {
return couponType;
}
@JSONField(serialize = false)
public CouponType getFormatCouponType() {
for (CouponType couponType : CouponType.values()) {
if (couponType.getVal() == this.couponType) {
return couponType;
}
}
return null;
}
public int getCouponStockStatus() {
return couponStockStatus;
}
@JSONField(serialize = false)
public CouponStockStatus getFormatCouponStockStatus() {
for (CouponStockStatus couponStockStatus : CouponStockStatus.values()) {
if (couponStockStatus.getVal() == this.couponStockStatus) {
return couponStockStatus;
}
}
return null;
}
public int getCouponTotal() {
return couponTotal;
}
public Integer getMaxQuota() {
return maxQuota;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatMaxQuota() {
return maxQuota != null ? maxQuota.intValue() / 100d : 0d;
}
public Integer getLockedNum() {
return lockedNum;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatLockedNum() {
return lockedNum != null ? lockedNum.intValue() / 100d : 0d;
}
public Integer getUsedNum() {
return usedNum;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatUsedNum() {
return usedNum != null ? usedNum.intValue() / 100d : 0d;
}
public Integer getSendNum() {
return sendNum;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatSendNum() {
return sendNum != null ? sendNum.intValue() / 100d : 0d;
}
public String getBeginTime() {
return beginTime;
}
@JSONField(serialize = false)
public Date getFormatBeginTime() {
return beginTime != null ? DateUtil.parse2yyyyMMddHHmmss(beginTime)
: null;
}
public String getEndTime() {
return endTime;
}
@JSONField(serialize = false)
public Date getFormatEndTime() {
return endTime != null ? DateUtil.parse2yyyyMMddHHmmss(endTime) : null;
}
public String getCreateTime() {
return createTime;
}
@JSONField(serialize = false)
public Date getFormatCreateTime() {
return createTime != null ? DateUtil.parse2yyyyMMddHHmmss(createTime)
: null;
}
public Integer getCouponBudget() {
return couponBudget;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCouponBudget() {
return couponBudget != null ? couponBudget.intValue() / 100d : 0d;
}
@Override
public String toString() {
return "CouponDetail [couponStockId=" + couponStockId + ", couponName="
+ couponName + ", couponValue=" + getFormatCouponValue()
+ ", couponMininumn=" + getFormatCouponMininumn()
+ ", couponType=" + getFormatCouponType()
+ ", couponStockStatus=" + getFormatCouponStockStatus()
+ ", couponTotal=" + couponTotal + ", maxQuota="
+ getFormatMaxQuota() + ", lockedNum=" + getFormatLockedNum()
+ ", usedNum=" + getFormatUsedNum() + ", sendNum="
+ getFormatSendNum() + ", beginTime=" + beginTime
+ ", endTime=" + endTime + ", createTime=" + createTime
+ ", couponBudget=" + getFormatCouponBudget() + ", "
+ super.toString() + "]";
}
}

View File

@ -0,0 +1,95 @@
package com.foxinmy.weixin4j.pay.payment.coupon;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.pay.type.mch.CouponType;
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;
/**
* 订单代金券信息
*
* @className OrderCouponInfo
* @author jinyu(foxinmy@gmail.com)
* @date 2015年3月24日
* @since JDK 1.6
* @see
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class OrderCouponInfo implements Serializable {
private static final long serialVersionUID = -8744999305258786901L;
/**
* 代金券或立减优惠批次ID
*/
@XmlElement(name = "coupon_batch_id")
@JSONField(name = "coupon_batch_id")
private String couponBatchId;
/**
* 代金券类型
*
* @see CouponType
*/
@XmlElement(name = "coupon_type")
@JSONField(name = "coupon_type")
private String couponType;
/**
* 代金券或立减优惠ID
*/
@XmlElement(name = "coupon_id")
@JSONField(name = "coupon_id")
private String couponId;
/**
* 单个代金券或立减优惠支付金额
*/
@XmlElement(name = "coupon_fee")
@JSONField(name = "coupon_fee")
private Integer couponFee;
protected OrderCouponInfo() {
// jaxb requried
}
public String getCouponBatchId() {
return couponBatchId;
}
public String getCouponType() {
return couponType;
}
@JSONField(serialize = false)
public CouponType getFormatCouponType() {
return couponType != null ? CouponType
.valueOf(couponType.toUpperCase()) : null;
}
public String getCouponId() {
return couponId;
}
public Integer getCouponFee() {
return couponFee;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCouponFee() {
return couponFee != null ? couponFee.doubleValue() / 100d : 0d;
}
@Override
public String toString() {
return "couponBatchId=" + couponBatchId + ", couponType=" + couponType
+ ", couponId=" + couponId + ", couponFee=" + couponFee;
}
}

View File

@ -0,0 +1,76 @@
package com.foxinmy.weixin4j.pay.payment.coupon;
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;
import java.io.Serializable;
/**
* 退款代金券信息
*
* @className RefundCouponInfo
* @author jinyu(foxinmy@gmail.com)
* @date 2015年3月24日
* @since JDK 1.6
* @see
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class RefundCouponInfo implements Serializable {
private static final long serialVersionUID = -8744999305258786901L;
/**
* 代金券或立减优惠批次ID
*/
@XmlElement(name = "coupon_refund_batch_id")
@JSONField(name = "coupon_refund_batch_id")
private String couponBatchId;
/**
* 退款代金券ID
*/
@XmlElement(name = "coupon_refund_id")
@JSONField(name = "coupon_refund_id")
private String couponId;
/**
* 单个代金券或立减优惠支付金额
*/
@XmlElement(name = "coupon_refund_fee")
@JSONField(name = "coupon_refund_fee")
private Integer couponFee;
protected RefundCouponInfo() {
// jaxb requried
}
public String getCouponBatchId() {
return couponBatchId;
}
public String getCouponId() {
return couponId;
}
public Integer getCouponFee() {
return couponFee;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCouponFee() {
return couponFee != null ? couponFee.doubleValue() / 100d : 0d;
}
@Override
public String toString() {
return "couponBatchId=" + couponBatchId + ", couponId=" + couponId
+ ", couponFee=" + couponFee;
}
}

View File

@ -0,0 +1,46 @@
package com.foxinmy.weixin4j.pay.type;
/**
* 交易状态
*
* @className TradeState
* @author jinyu(foxinmy@gmail.com)
* @date 2014年11月2日
* @since JDK 1.6
* @see
* @deprecated 迁移到子模块weixin4j-pay
*/
public enum TradeState {
/**
* 支付成功
*/
SUCCESS,
/**
* 转入退款
*/
REFUND,
/**
* 未支付
*/
NOTPAY,
/**
* 已关闭
*/
CLOSED,
/**
* 已撤销
*/
REVOKED,
/**
* 用户支付中
*/
USERPAYING,
/**
* 未支付(输入密码或 确认支付超时)
*/
NOPAY,
/**
* 支付失败(其他 原因,如银行返回失败)
*/
PAYERROR;
}

View File

@ -0,0 +1,59 @@
# \u5fae\u4fe1\u5546\u6237\u5e73\u53f0\u6587\u6863\u8bf4\u660e
# https://pay.weixin.qq.com/
# https://pay.weixin.qq.com/wiki/doc/api/index.php
# ----------------------------------------------------------------------------
mch_base_url=https://api.mch.weixin.qq.com
# \u53d1\u9001\u73b0\u91d1\u7ea2\u5305
redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack
# \u53d1\u9001\u73b0\u91d1\u88c2\u53d8\u7ea2\u5305
groupredpack_send_uri={mch_base_url}/mmpaymkttransfers/sendgroupredpack
# \u67e5\u8be2\u73b0\u91d1\u7ea2\u5305
redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo
# \u7edf\u4e00\u8ba2\u5355\u751f\u6210
order_create_uri={mch_base_url}/pay/unifiedorder
# \u88ab\u626b\u652f\u4ed8
micropay_uri={mch_base_url}/pay/micropay
# \u8ba2\u5355\u67e5\u8be2
order_query_uri={mch_base_url}/pay/orderquery
# \u5173\u95ed\u8ba2\u5355
order_close_uri={mch_base_url}/pay/closeorder
# \u5bf9\u8d26\u5355\u4e0b\u8f7d
downloadbill_uri={mch_base_url}/pay/downloadbill
# \u9000\u6b3e\u67e5\u8be2
refund_query_uri={mch_base_url}/pay/refundquery
# \u9000\u6b3e\u7533\u8bf7
refund_apply_uri={mch_base_url}/secapi/pay/refund
# \u51b2\u6b63\u64a4\u9500
order_reverse_uri={mch_base_url}/secapi/pay/reverse
# \u957f\u94fe\u63a5\u8f6c\u6362
longurl_convert_uri={mch_base_url}/tools/shorturl
# \u53d1\u653e\u4ee3\u91d1\u5238
coupon_send_uri={mch_base_url}/mmpaymkttransfers/send_coupon
# \u67e5\u8be2\u4ee3\u91d1\u5238\u6279\u6b21\u4fe1\u606f
couponstock_query_uri={mch_base_url}/mmpaymkttransfers/query_coupon_stock
# \u67e5\u8be2\u4ee3\u91d1\u5238\u8be6\u7ec6\u4fe1\u606f
coupondetail_query_uri={mch_base_url}/mmpaymkttransfers/querycouponsinfo
# \u53d1\u9001\u73b0\u91d1\u7ea2\u5305
redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack
# \u67e5\u8be2\u73b0\u91d1\u7ea2\u5305
redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo
# \u4f01\u4e1a\u5411\u4e2a\u4eba\u4ed8\u6b3e
corppayment_send_uri={mch_base_url}/mmpaymkttransfers/promotion/transfers
# \u4f01\u4e1a\u4ed8\u6b3e\u67e5\u8be2
corppayment_query_uri={mch_base_url}/mmpaymkttransfers/gettransferinfo
# \u63a5\u53e3\u4e0a\u62a5
interface_report_uri={mch_base_url}/payitil/report
# \u6388\u6743\u7801\u67e5\u8be2OPENID\u63a5\u53e3
authcode_openid_uri={mch_base_url}/tools/authcodetoopenid
# native\u652f\u4ed8url(\u6a21\u5f0f1)
native_pay_uri=weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s
# \u67e5\u8be2\u7ed3\u7b97\u8d44\u91d1
settlement_query_uri={mch_base_url}/pay/settlementquery
# \u67e5\u8be2\u6c47\u7387
exchagerate_query_uri={mch_base_url}/pay/queryexchagerate
# \u8ba2\u5355\u9644\u52a0\u4fe1\u606f\u63d0\u4ea4
customsorder_declare_uri={mch_base_url}/mch/customs/customdeclareorder
# \u8ba2\u5355\u9644\u52a0\u4fe1\u606f\u67e5\u8be2
customsorder_query_uri={mch_base_url}/mch/customs/customdeclarequery