将支付API相关内容迁移到新的子模块weixin4j-pay

This commit is contained in:
Kit 2019-09-16 16:59:15 +08:00
parent 3af2db29d9
commit 86fc0712d0
68 changed files with 7551 additions and 0 deletions

46
weixin4j-pay/pom.xml Normal file
View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>weixin4j</artifactId>
<groupId>com.foxinmy</groupId>
<version>1.9.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<name>weixin4j-pay</name>
<artifactId>weixin4j-pay</artifactId>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-pay</url>
<description>微信支付商户平台API</description>
<developers>
<developer>
<id>kit-lee</id>
<name>Kit lee</name>
<email>ryuji.cn@gmail.com</email>
<url>https://github.com/kit-lee</url>
<properties>
<contact>kit_21cn@21cn.com</contact>
<forkRepo>https://github.com/kit-lee/weixin4j</forkRepo>
</properties>
</developer>
</developers>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.foxinmy</groupId>
<artifactId>weixin4j-base</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -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 <a href="https://pay.weixin.qq.com/wiki/doc/api/index.html">商户支付平台</a>
*/
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<String, String> createBaseRequestMap(IdQuery idQuery) {
Map<String, String> map = new HashMap<String, String>();
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 <T extends MerchantResult> 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));
}
}

View File

@ -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);
}
/**
* 统一下单接口</br>
* 除被扫支付场景以外商户系统先调用该接口在微信支付服务后台生成预支付交易单返回正确的预支付交易回话标识后再按扫码JSAPI
* APP等不同场景生成交易串调起支付
*
* @param payPackage
* 包含订单信息的对象
* @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 {
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<PrePay>() {
});
}
/**
* 创建支付请求对象
*
* @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>() {
});
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);
}
/**
* <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 <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) {
Map<String, String> map = new HashMap<String, String>();
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 <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) {
Map<String, String> map = new HashMap<String, String>();
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 <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 {
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 <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 {
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 <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 {
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 <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 {
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 <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 {
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);
}
/**
* 订单查询
* <p>
* 当商户后台网络服务器等出现异常商户系统最终未接收到支付通知</br> 调用支付接口后返回系统错误或未知交易状态情况</br>
* 调用被扫支付API返回USERPAYING的状态</br> 调用关单或撤销接口API之前需确认支付状态
* </P>
*
* @param idQuery
* 商户系统内部的订单号, transaction_idout_trade_no 选一,如果同时存在优先级:
* transaction_id> out_trade_no
* @return 订单信息
* @see Order
* @see <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2">
* 订单查询API</a>
* @since V3
* @throws WeixinException
*/
public Order queryOrder(IdQuery idQuery) throws WeixinException {
Map<String, String> 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);
}
/**
* 申请退款(请求需要双向证书)
*
* <p>
* 当交易发生之后一段时间内由于买家或者卖家的原因需要退款时卖家可以通过退款接口将支付款退还给买家微信支付将在收到退款请求并且验证成功之后
* 按照退款规则将支付款按原路退到买家帐号上
* </p>
*
* <ol>
* <li>交易时间超过一年的订单无法提交退款</li>
* <li>
* 微信支付退款支持单笔交易分多次退款多次退款需要提交原支付订单的商户订单号和设置不同的退款单号
* 申请退款总金额不能超过订单金额
* <span style="color:red">一笔退款失败后重新提交请不要更换退款单号请使用原商户退款单号</span>
* </li>
* <li>
* 请求频率限制150qps即每秒钟正常的申请退款请求次数不超过150次
* 错误或无效请求频率限制6qps即每秒钟异常或错误的退款申请请求不超过6次
* </li>
* <li>每个支付订单的部分退款次数不能超过50次</li>
* </ol>
*
* @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 <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4">
* 申请退款API</a>
* @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<String, String> 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<RefundResult>() {
});
}
/**
* 退款申请(全额退款)
*
* @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);
}
/**
* 冲正订单(需要证书)</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 撤销结果
* @since V3
* @throws WeixinException
*/
public MerchantResult reverseOrder(IdQuery idQuery) throws WeixinException {
Map<String, String> 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<MerchantResult>() {
});
}
/**
* native支付URL转短链接用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX)减小二维码数据量
* 提升扫描速度和精确度
*
* @param url
* 具有native标识的支付URL
* @return 转换后的短链接
* @throws WeixinException
* @see <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_9">
* 转换短链接API</a>
*/
public String getShorturl(String url) throws WeixinException {
Map<String, String> 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");
}
/**
* 关闭订单
* <p>
* 商户订单支付失败需要生成新单号重新发起支付要对原订单号调用关单避免重复支付系统下单后用户支付超时系统退出不再受理避免用户继续
* 请调用关单接口,如果关单失败,返回已完 成支付请按正常支付处理如果出现银行掉单,调用关单成功后,微信后台会主动发起退款
* </p>
*
* @param outTradeNo
* 商户系统内部的订单号
* @return 处理结果
* @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 {
Map<String, String> 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<MerchantResult>() {
});
}
/**
* 下载对账单<br>
* 1.微信侧未成功下单的交易不会出现在对账单中支付成功后撤销的交易会出现在对账 单中,跟原支付单订单号一致,bill_type
* REVOKED;<br>
* 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;<br>
* 3.对账单中涉及金额的字段单位为<br>
*
* @param billDate
* 下载对账单的日期
* @param billType
* 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单
* REFUND,返回当日退款订单
* @param outputStream
* 输出流
* @param tarType
* 非必传参数固定值GZIP返回格式为.gzip的压缩包账单不传则默认为数据流形式
* @since V3
* @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 {
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<String, String> 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) {
;
}
}
}
}
/**
* 退款查询
*
* <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 RefundRecord
* @see com.foxinmy.weixin4j.payment.mch.RefundDetail
* @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 {
Map<String, String> 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 <a href=
* "http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_8">
* 交易保障</a>
*/
@SuppressWarnings("unchecked")
public XmlResult reportInterface(String interfaceUrl, int executeTime,
String outTradeNo, String ip, Date time, XmlResult returnXml)
throws WeixinException {
Map<String, String> 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<String, String>) 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 <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 {
Map<String, String> 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<OpenIdResult>() {
});
}
}

View File

@ -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 + "]";
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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
* 订单总额 必填 <font color="red">单位为元</font>
* @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
* 订单总额 必填 <font color="red">单位为分</font>
* @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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatTotalFee() {
return totalFee / 100d;
}
/**
* <font color="red">单位为元,自动格式化为分</font>
*
* @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;
}
}

View File

@ -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();
}
}

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,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 <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 redpacket
* 多个红包信息
* @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,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 <a href=
* "https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1">APP支付</a>
*/
public class APPPayRequest extends AbstractPayRequest {
public APPPayRequest(String prePayId, WeixinPayAccount payAccount) {
super(prePayId, payAccount);
}
@Override
public TradeType getPaymentType() {
return TradeType.APP;
}
/**
* <font color="red">只做查看之用,请不要尝试作为支付请求</font>
*/
@Override
public PayRequest toRequestObject() {
PayRequest payRequest = new PayRequest(getPaymentAccount().getId(), "Sign=WXPay");
payRequest.setPartnerId(getPaymentAccount().getMchId());
payRequest.setPrepayId(getPrePayId());
Map<String, String> map = new HashMap<String, String>();
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("<xml>");
content.append(String.format("<appid><![CDATA[%s]]></appid>", payRequest.getAppId()));
content.append(String.format("<partnerid><![CDATA[%s]]></partnerid>", payRequest.getPartnerId()));
content.append(String.format("<prepayid><![CDATA[%s]]></prepayid>", payRequest.getPrepayId()));
content.append(String.format("<package><![CDATA[%s]]></package>", payRequest.getPackageInfo()));
content.append(String.format("<noncestr><![CDATA[%s]]></noncestr>", payRequest.getNonceStr()));
content.append(String.format("<timestamp><![CDATA[%s]]></timestamp>", payRequest.getTimeStamp()));
content.append(String.format("<sign><![CDATA[%s]]></sign>", payRequest.getPaySign()));
content.append("</xml>");
return content.toString();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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() + "]";
}
}

View File

@ -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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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() + "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -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<CustomsOrderResult> 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<CustomsOrderResult> getCustomsOrderList() {
return customsOrderList;
}
public void setCustomsOrderList(List<CustomsOrderResult> customsOrderList) {
this.customsOrderList = customsOrderList;
}
@Override
public String toString() {
return "CustomsOrderRecord [transactionId=" + transactionId
+ ", orderCount=" + orderCount + ", customsOrderList="
+ customsOrderList + "]";
}
}

View File

@ -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 + "]";
}
}

View File

@ -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</br>
* <p>
* get_brand_wcpay_request:ok 支付成功<br>
* get_brand_wcpay_request:cancel 支付过程中用户取消<br>
* get_brand_wcpay_request:fail 支付失败
* </p>
*
* @className JSAPIPayRequest
* @author jinyu(foxinmy@gmail.com)
* @date 2015年12月25日
* @since JDK 1.6
* @see PrePay
* @see PayRequest
* @see <a
* href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1">网页端调起支付API</a>
*/
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());
}
}

View File

@ -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 <a
* href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=5_1">刷卡支付</a>
*/
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;
}
/**
* <font color="red">返回null,请不要尝试作为支付请求</font>
*/
@Override
@JSONField(serialize = false)
public String toRequestString() {
return null;
}
/**
* <font color="red">返回null,请不要尝试作为支付请求</font>
*/
@JSONField(serialize = false)
@Override
public PayRequest toRequestObject() {
return null;
}
/**
* <font color="red">返回null,请不要尝试作为支付请求</font>
*/
@JSONField(serialize = false)
@Override
public String getPrePayId() {
return null;
}
public void setPaymentAccount(WeixinPayAccount paymentAccount) {
this.paymentAccount = paymentAccount;
}
@Override
public WeixinPayAccount getPaymentAccount() {
return this.paymentAccount;
}
}

View File

@ -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;
/**
* 交易类型JSAPINATIVEAPP 必须
*/
@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
* 商品描述 <font color="red">必填项</font>
* @param detial
* 商品名称明细列表 非必填项
* @param outTradeNo
* 商户内部唯一订单号 <font color="red">必填项</font>
* @param totalFee
* 商品总额 单位元 <font color="red">必填项</font>
* @param notifyUrl
* 支付回调URL <font color="red">必填项</font>
* @param createIp
* 订单生成的机器IP <font color="red">必填项</font>
* @param tradeType
* 交易类型 <font color="red">必填项</font>
* @param feeType
* 货币类型 非必填项
* @param openId
* 用户ID <font color="red">tradeType=JSAPI时必填</font>
* @param authCode
* 刷卡支付授权码 <font color="red">tradeType=MICROPAY时必填</font>
* @param productId
* 产品ID <font color="red">tradeType=NATIVE时必填</font>
* @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() + "]";
}
}

View File

@ -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();
}

View File

@ -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;
/**
* 签名 <font color="red">调用者无需关心</font>
*/
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();
}
}

View File

@ -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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCashFee() {
return cashFee != null ? cashFee / 100d : 0d;
}
public Integer getTotalFee() {
return totalFee;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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();
}
}

View File

@ -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 <a
* href="https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1">NATIVE扫码支付(模式二)</a>
*/
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;
}
/**
* <font color="red">只做查看之用,请不要尝试作为支付请求</font>
*/
@Override
public PayRequest toRequestObject() {
return new PayRequest(getPaymentAccount().getId(), "code_url=" + codeUrl);
}
@Override
public String toRequestString() {
return this.codeUrl;
}
}

View File

@ -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() + "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -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<OrderCouponInfo> 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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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<OrderCouponInfo> getCouponList() {
return couponList;
}
public void setCouponList(List<OrderCouponInfo> 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() + "]";
}
}

View File

@ -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;
/**
* 调用接口提交的交易类型取值如下JSAPINATIVEAPP
*
* @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 是有 返回</br> NATVIE支付可直接生成二维码展示出来进行扫码支付可能为空</br>
* 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() + "]";
}
}

View File

@ -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 <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/cash_coupon.php?chapter=16_1">裂变红包</a>
*/
@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
* 付款金额 <font color="red">单位为元,自动格式化为分</font> 必填
* @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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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() + "]";
}
}

View File

@ -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<RedpacketReceiver> 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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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<RedpacketReceiver> 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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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 + "]";
}
}

View File

@ -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<String, String> risk;
public RedpacketRisk() {
this.risk = new HashMap<String, String>();
}
/**
* 用户操作的时间戳
*
* @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<String, String> 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;
}
}
}

View File

@ -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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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() + "]";
}
}

View File

@ -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<RefundCouponInfo> 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<RefundCouponInfo> getCouponList() {
return couponList;
}
public void setCouponList(List<RefundCouponInfo> couponList) {
this.couponList = couponList;
}
public Integer getSettlementRefundFee() {
return settlementRefundFee;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatSettlementRefundFee() {
return settlementRefundFee != null ? settlementRefundFee / 100d : 0d;
}
public Integer getCouponRefundFee() {
return couponRefundFee;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @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 + "]";
}
}

View File

@ -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<RefundDetail> refundList;
protected RefundRecord() {
// jaxb required
}
public int getRefundCount() {
return refundCount;
}
public int getRefundFee() {
return refundFee;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatRefundFee() {
return refundFee / 100d;
}
public List<RefundDetail> getRefundList() {
return refundList;
}
public void setRefundList(List<RefundDetail> refundList) {
this.refundList = refundList;
}
@Override
public String toString() {
return "RefundRecord [refundCount=" + refundCount + ", refundFee="
+ refundFee + ", refundList=" + refundList + ", "
+ super.toString() + "]";
}
}

View File

@ -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<RefundDetail> 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;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatRefundFee() {
return refundFee / 100d;
}
public Integer getCashRefundFee() {
return cashRefundFee;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(serialize = false)
public double getFormatCashRefundFee() {
return cashRefundFee != null ? cashRefundFee.intValue() / 100d : 0d;
}
public List<RefundDetail> getRefundList() {
return refundList;
}
@Override
public String toString() {
return "RefundResult [" + super.toString() + ", outRefundNo="
+ outRefundNo + ", refundId=" + refundId + ", refundChannel="
+ refundChannel + ", refundFee=" + refundFee
+ ", cashRefundFee=" + cashRefundFee + ", refundList="
+ refundList + "]";
}
}

View File

@ -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;
}
}

View File

@ -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 + "]";
}
}

View File

@ -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;
}
/**
* <font color="red">最小单位除100得到的值</font>
*
* @return /100
*/
@JSONField(serialize = false)
public double getFormatSettleFee() {
return settleFee / 100d;
}
public void setSettleFee(int settleFee) {
this.settleFee = settleFee;
}
public int getUnSettleFee() {
return unSettleFee;
}
/**
* <font color="red">最小单位除100得到的值</font>
*
* @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;
}
/**
* <font color="red">最小单位除100得到的值</font>
*
* @return /100
*/
@JSONField(serialize = false)
public double getFormatPayFee() {
return payFee / 100d;
}
public void setPayFee(int payFee) {
this.payFee = payFee;
}
public int getRefundFee() {
return refundFee;
}
/**
* <font color="red">最小单位除100得到的值</font>
*
* @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;
}
/**
* <font color="red">最小单位除100得到的值</font>
*
* @return /100
*/
@JSONField(serialize = false)
public double getFormatPayNetFee() {
return payNetFee / 100d;
}
public int getPoundageFee() {
return poundageFee;
}
/**
* <font color="red">最小单位除100得到的值</font>
*
* @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() + "]";
}
}

View File

@ -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 <a
* href="https://pay.weixin.qq.com/wiki/doc/api/wap.php?chapter=15_1">WAP支付</a>
*/
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;
}
/**
* <font color="red">只做查看之用,请不要尝试作为支付请求</font>
*/
@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;
}
}

View File

@ -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()));
}
}

View File

@ -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 <a
* href="https://pay.weixin.qq.com/wiki/doc/api/external/jsapi.php?chapter=4_3">支付签名说明</a>
*/
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();
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;
}
}