微信支付:新增查询结算金额、新增查询汇率接口

This commit is contained in:
jinyu 2016-03-26 23:14:42 +08:00
parent aec8c6bc45
commit 1f3ed92165
11 changed files with 430 additions and 28 deletions

View File

@ -654,3 +654,7 @@
+ weixin4j-base:支持服务商版支付
+ weixin4j-base:签名类接口化
+ weixin4j-base:新增查询结算金额接口
+ weixin4j-base:新增查询汇率接口

View File

@ -2,6 +2,8 @@ package com.foxinmy.weixin4j.api;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import com.alibaba.fastjson.JSON;
@ -9,6 +11,7 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.model.Pageable;
import com.foxinmy.weixin4j.model.WeixinPayAccount;
import com.foxinmy.weixin4j.payment.mch.CorpPayment;
import com.foxinmy.weixin4j.payment.mch.CorpPaymentRecord;
@ -16,6 +19,9 @@ import com.foxinmy.weixin4j.payment.mch.CorpPaymentResult;
import com.foxinmy.weixin4j.payment.mch.Redpacket;
import com.foxinmy.weixin4j.payment.mch.RedpacketRecord;
import com.foxinmy.weixin4j.payment.mch.RedpacketSendResult;
import com.foxinmy.weixin4j.payment.mch.SettlementRecord;
import com.foxinmy.weixin4j.type.CurrencyType;
import com.foxinmy.weixin4j.util.DateUtil;
import com.foxinmy.weixin4j.util.RandomUtil;
import com.foxinmy.weixin4j.xml.XmlStream;
@ -193,4 +199,76 @@ public class CashApi extends MchApi {
return response.getAsObject(new TypeReference<CorpPaymentRecord>() {
});
}
/**
* 查询结算资金
*
* @param status
* 是否结算
* @param pageable
* 分页数据
* @param start
* 开始日期 查询未结算记录时该字段可不传
* @param end
* 结束日期 查询未结算记录时该字段可不传
* @return 结算金额记录
* @throws WeixinException
* @see com.foxinmy.weixin4j.payment.mch.SettlementRecord
* @see <a
* href="https://pay.weixin.qq.com/wiki/doc/api/external/micropay.php?chapter=9_14&index=7">查询结算资金</a>
*/
public SettlementRecord querySettlement(boolean status, Pageable pageable,
Date start, Date end) throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("nonce_str", RandomUtil.generateString(16));
obj.put("mch_id", weixinAccount.getMchId());
obj.put("appid", weixinAccount.getId());
obj.put("usetag", status ? 1 : 2);
obj.put("offset", pageable.getOffset());
obj.put("limit", pageable.getPageSize());
if (start != null) {
obj.put("date_start", DateUtil.fortmat2yyyyMMdd(start));
}
if (end != null) {
obj.put("date_end", DateUtil.fortmat2yyyyMMdd(end));
}
obj.put("sign", weixinSignature.sign(obj));
String param = XmlStream.map2xml(obj);
WeixinResponse response = weixinExecutor.post(
getRequestUri("settlement_query_uri"), param);
return response.getAsObject(new TypeReference<SettlementRecord>() {
});
}
/**
* 查询汇率
*
* @param currencyType
* 外币币种
* @param date
* 日期 不填则默认当天
* @return 汇率 例如美元兑换人民币的比例为6.5
* @throws WeixinException
* @see <a
* href="https://pay.weixin.qq.com/wiki/doc/api/external/micropay.php?chapter=9_15&index=8">查询汇率</a>
*/
public double queryExchageRate(CurrencyType currencyType, Date date)
throws WeixinException {
if (date == null) {
date = new Date();
}
JSONObject obj = new JSONObject();
obj.put("mch_id", weixinAccount.getMchId());
obj.put("appid", weixinAccount.getId());
obj.put("sub_mch_id", weixinAccount.getSubMchId());
obj.put("fee_type", currencyType.name());
obj.put("date", DateUtil.fortmat2yyyyMMdd(date));
obj.put("sign", weixinSignature.sign(obj));
String param = XmlStream.map2xml(obj);
WeixinResponse response = weixinExecutor.post(
getRequestUri("exchagerate_query_uri"), param);
BigDecimal rate = new BigDecimal(XmlStream.xml2map(
response.getAsString()).get("rate"));
return rate.divide(new BigDecimal(100000000d)).doubleValue();
}
}

View File

@ -12,6 +12,7 @@ import com.foxinmy.weixin4j.api.PayApi;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.exception.WeixinPayException;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
import com.foxinmy.weixin4j.model.Pageable;
import com.foxinmy.weixin4j.model.WeixinPayAccount;
import com.foxinmy.weixin4j.payment.coupon.CouponDetail;
import com.foxinmy.weixin4j.payment.coupon.CouponResult;
@ -31,6 +32,7 @@ import com.foxinmy.weixin4j.payment.mch.RedpacketRecord;
import com.foxinmy.weixin4j.payment.mch.RedpacketSendResult;
import com.foxinmy.weixin4j.payment.mch.RefundRecord;
import com.foxinmy.weixin4j.payment.mch.RefundResult;
import com.foxinmy.weixin4j.payment.mch.SettlementRecord;
import com.foxinmy.weixin4j.type.BillType;
import com.foxinmy.weixin4j.type.CurrencyType;
import com.foxinmy.weixin4j.type.IdQuery;
@ -459,10 +461,9 @@ public class WeixinPayProxy {
* @since V3
* @throws WeixinException
*/
public RefundResult applyRefund(
InputStream certificate, IdQuery idQuery, String outRefundNo,
double totalFee, double refundFee, CurrencyType refundFeeType,
String opUserId) throws WeixinException {
public RefundResult applyRefund(InputStream certificate, IdQuery idQuery,
String outRefundNo, double totalFee, double refundFee,
CurrencyType refundFeeType, String opUserId) throws WeixinException {
return payApi.applyRefund(certificate, idQuery, outRefundNo, totalFee,
refundFee, refundFeeType, opUserId);
}
@ -474,9 +475,8 @@ public class WeixinPayProxy {
*
* @see {@link #applyRefund(InputStream, IdQuery, String, double, double, String,CurrencyType)}
*/
public RefundResult applyRefund(
IdQuery idQuery, String outRefundNo, double totalFee)
throws WeixinException, IOException {
public RefundResult applyRefund(IdQuery idQuery, String outRefundNo,
double totalFee) throws WeixinException, IOException {
return payApi.applyRefund(
new FileInputStream(settings.getCertificateFile0()), idQuery,
outRefundNo, totalFee);
@ -846,5 +846,46 @@ public class WeixinPayProxy {
return payApi.authCode2openId(authCode);
}
/**
* 查询结算资金
*
* @param status
* 是否结算
* @param pageable
* 分页数据
* @param start
* 开始日期 查询未结算记录时该字段可不传
* @param end
* 结束日期 查询未结算记录时该字段可不传
* @return 结算金额记录
* @throws WeixinException
* @see com.foxinmy.weixin4j.api.CashApi
* @see com.foxinmy.weixin4j.payment.mch.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 com.foxinmy.weixin4j.api.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);
}
public final static String VERSION = "1.6.7";
}

View File

@ -9,7 +9,7 @@ import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
/**
* 调用V3.x接口返回的公用字段
* 调用商户平台接口返回的公用字段
*
* @className ApiResult
* @author jy

View File

@ -0,0 +1,273 @@
package com.foxinmy.weixin4j.payment.mch;
import java.util.Date;
import javax.xml.bind.annotation.XmlElement;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.type.CurrencyType;
import com.foxinmy.weixin4j.util.DateUtil;
/**
* 结算资金
*
* @className Settlement
* @author jy
* @date 2016年3月26日
* @since JDK 1.6
* @see
*/
public class SettlementRecord extends ApiResult {
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
+ "]";
}
}

View File

@ -49,3 +49,7 @@ interface_report_uri={mch_base_url}/payitil/report
authcode_openid_uri={mch_base_url}/tools/authcodetoopenid
# native\u652f\u4ed8url(\u6a21\u5f0f1)
native_pay_uri=weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s
# \u67e5\u8be2\u7ed3\u7b97\u8d44\u91d1
settlement_query_uri={mch_base_url}/pay/settlementquery
# \u67e5\u8be2\u6c47\u7387
exchagerate_query_uri={mch_base_url}/pay/queryexchagerate

View File

@ -10,7 +10,9 @@ package com.foxinmy.weixin4j.type;
* @see
*/
public enum CurrencyType {
CNY("人民币"), HKD("港元"), TWD("台币"), EUR("欧元"), USD("美元"), GBP("英镑"), JPY("日元");
CNY("人民币"), HKD("港元"), TWD("台币"), EUR("欧元"), USD("美元"), GBP("英镑"), JPY("日元"), CAD(
"加拿大元"), AUD("澳大利亚元"), NZD("新西兰元"), KRW("韩元"), THB("泰铢");
private String desc;
CurrencyType(String desc) {

View File

@ -33,12 +33,12 @@ import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.http.weixin.WeixinSSLRequestExecutor;
import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinPayOldAccount;
import com.foxinmy.weixin4j.mp.oldpayment.OrderV2;
import com.foxinmy.weixin4j.mp.oldpayment.PayPackageV2;
import com.foxinmy.weixin4j.mp.oldpayment.RefundRecordV2;
import com.foxinmy.weixin4j.mp.oldpayment.RefundResultV2;
import com.foxinmy.weixin4j.mp.oldpayment.WeixinOldPaymentSignature;
import com.foxinmy.weixin4j.mp.oldpayment.WeixinOldPayAccount;
import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator;
import com.foxinmy.weixin4j.payment.PayRequest;
import com.foxinmy.weixin4j.sign.WeixinPaymentSignature;
@ -69,7 +69,7 @@ import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer;
*/
public class PayOldApi extends MpApi {
private final WeixinPayOldAccount weixinAccount;
private final WeixinOldPayAccount weixinAccount;
private final TokenHolder tokenHolder;
private final WeixinSignature weixinMD5Signature;
private final WeixinOldPaymentSignature weixinOldSignature;
@ -79,12 +79,12 @@ public class PayOldApi extends MpApi {
*/
public PayOldApi() {
this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"),
WeixinPayOldAccount.class), new FileTokenStorager(
WeixinOldPayAccount.class), new FileTokenStorager(
Weixin4jConfigUtil.getClassPathValue("weixin4j.tmpdir",
System.getProperty("java.io.tmpdir"))));
}
public PayOldApi(WeixinPayOldAccount payAccount) {
public PayOldApi(WeixinOldPayAccount payAccount) {
this(payAccount, new FileTokenStorager(
Weixin4jConfigUtil.getClassPathValue("weixin4j.tmpdir",
System.getProperty("java.io.tmpdir"))));
@ -92,10 +92,10 @@ public class PayOldApi extends MpApi {
public PayOldApi(TokenStorager tokenStorager) {
this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"),
WeixinPayOldAccount.class), tokenStorager);
WeixinOldPayAccount.class), tokenStorager);
}
public PayOldApi(WeixinPayOldAccount weixinAccount,
public PayOldApi(WeixinOldPayAccount weixinAccount,
TokenStorager tokenStorager) {
this.weixinAccount = weixinAccount;
this.tokenHolder = new TokenHolder(new WeixinTokenCreator(
@ -106,7 +106,7 @@ public class PayOldApi extends MpApi {
this.weixinOldSignature = new WeixinOldPaymentSignature();
}
public WeixinPayOldAccount getPayAccount() {
public WeixinOldPayAccount getPayAccount() {
return this.weixinAccount;
}

View File

@ -9,7 +9,6 @@ import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.model.WeixinPayOldAccount;
import com.foxinmy.weixin4j.payment.PayRequest;
/**
@ -61,7 +60,7 @@ public class NativePayResponseV2 extends PayRequest {
* @param payPackage
* 订单信息
*/
public NativePayResponseV2(WeixinPayOldAccount weixinAccount,
public NativePayResponseV2(WeixinOldPayAccount weixinAccount,
PayPackageV2 payPackage) {
super(weixinAccount.getId(), null);
this.retCode = "0";

View File

@ -1,18 +1,19 @@
package com.foxinmy.weixin4j.model;
package com.foxinmy.weixin4j.mp.oldpayment;
import com.alibaba.fastjson.annotation.JSONCreator;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.model.WeixinAccount;
/**
* 微信支付账户(2014年10月申请支付的老版本)
*
* @className WeixinPayOldAccount
* @className WeixinOldPayAccount
* @author jy
* @date 2015年6月26日
* @since JDK 1.6
* @see
*/
public class WeixinPayOldAccount extends WeixinAccount {
public class WeixinOldPayAccount extends WeixinAccount {
private static final long serialVersionUID = -2791256176906048632L;
/**
@ -43,7 +44,7 @@ public class WeixinPayOldAccount extends WeixinAccount {
* 财付通商户权限密钥Key(必填)
*/
@JSONCreator
public WeixinPayOldAccount(@JSONField(name = "id") String appId,
public WeixinOldPayAccount(@JSONField(name = "id") String appId,
@JSONField(name = "secret") String appSecret,
@JSONField(name = "paySignKey") String paySignKey,
@JSONField(name = "partnerId") String partnerId,
@ -68,7 +69,7 @@ public class WeixinPayOldAccount extends WeixinAccount {
@Override
public String toString() {
return "WeixinPayOldAccount [" + super.toString() + ", paySignKey="
return "WeixinOldPayAccount [" + super.toString() + ", paySignKey="
+ paySignKey + ", partnerId=" + partnerId + ", partnerKey="
+ partnerKey + "]";
}

View File

@ -8,8 +8,8 @@ import java.util.Calendar;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.WeixinPayOldAccount;
import com.foxinmy.weixin4j.mp.api.PayOldApi;
import com.foxinmy.weixin4j.mp.oldpayment.WeixinOldPayAccount;
import com.foxinmy.weixin4j.type.IdQuery;
import com.foxinmy.weixin4j.type.IdType;
@ -24,9 +24,9 @@ import com.foxinmy.weixin4j.type.IdType;
*/
public class PayTest {
protected final static PayOldApi PAY2;
protected final static WeixinPayOldAccount ACCOUNT2;
protected final static WeixinOldPayAccount ACCOUNT2;
static {
ACCOUNT2 = new WeixinPayOldAccount("请填入v2版本的appid",
ACCOUNT2 = new WeixinOldPayAccount("请填入v2版本的appid",
"请填入v2版本的appSecret", "请填入v2版本的paysignkey", "请填入v2版本的partnerId",
"请填入v2版本的partnerKey");
PAY2 = new PayOldApi(ACCOUNT2);