根据《微信商户平台文档》修缮Pay3Api类 & mp-server新增客服创建、关闭、转接会话的事件
This commit is contained in:
parent
a40ff51cd6
commit
e4e05e5370
@ -194,3 +194,9 @@
|
||||
|
||||
+ **weixin-mp**: 新增多客服会话管理多个接口
|
||||
|
||||
* 2015-03-25
|
||||
|
||||
+ **weixin-mp**: 根据《微信商户平台文档》修缮[Pay3Api](./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/Pay3Api.java)类
|
||||
|
||||
+ **weixin-mp**: 新增客服创建、关闭、转接会话事件
|
||||
|
||||
@ -10,7 +10,7 @@ weixin4j
|
||||
|
||||
`公众平台API封装`
|
||||
|
||||
`微信支付(公众号)`
|
||||
`微信支付(刷卡/扫码/公众号)`
|
||||
|
||||
`netty服务器&消息分发`
|
||||
|
||||
@ -71,6 +71,8 @@ netty的代码没有放到maven中心仓库,也没什么意义,因为最终需
|
||||
|
||||
接下来
|
||||
------
|
||||
* 代金券 & 红包接口
|
||||
|
||||
* 公众号服务应用
|
||||
|
||||
* 企业号第三方应用
|
||||
|
||||
@ -189,3 +189,9 @@ weixin4j-mp
|
||||
+ **weixin-mp-api**: 新增素材管理多个接口
|
||||
|
||||
+ **weixin-mp-api**: 新增多客服会话管理多个接口
|
||||
|
||||
* 2015-03-25
|
||||
|
||||
+ **weixin-mp-api**: 根据《微信商户平台文档》修缮[Pay3Api](./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/Pay3Api.java)类
|
||||
|
||||
+ **weixin-mp-server**: 新增客服创建、关闭、转接会话事件
|
||||
@ -168,3 +168,7 @@ weixin.properties说明
|
||||
+ 新增素材管理多个接口
|
||||
|
||||
+ 新增多客服会话管理多个接口
|
||||
|
||||
* 2015-03-25
|
||||
|
||||
+ 根据《微信商户平台文档》修缮[Pay3Api](./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/Pay3Api.java)类
|
||||
@ -12,6 +12,7 @@ import com.foxinmy.weixin4j.mp.api.Pay3Api;
|
||||
import com.foxinmy.weixin4j.mp.api.PayApi;
|
||||
import com.foxinmy.weixin4j.mp.payment.v3.ApiResult;
|
||||
import com.foxinmy.weixin4j.mp.type.BillType;
|
||||
import com.foxinmy.weixin4j.mp.type.CurrencyType;
|
||||
import com.foxinmy.weixin4j.mp.type.IdQuery;
|
||||
import com.foxinmy.weixin4j.mp.type.IdType;
|
||||
import com.foxinmy.weixin4j.mp.type.RefundType;
|
||||
@ -30,6 +31,7 @@ import com.foxinmy.weixin4j.util.ConfigUtil;
|
||||
* @since JDK 1.7
|
||||
* @see com.foxinmy.weixin4j.mp.api.Pay2Api
|
||||
* @see com.foxinmy.weixin4j.mp.api.Pay3Api
|
||||
* @see <a href="http://pay.weixin.qq.com/wiki/doc/api/index.html">商户平台支付API</a>
|
||||
*/
|
||||
public class WeixinPayProxy {
|
||||
private final PayApi payApi;
|
||||
@ -122,6 +124,10 @@ public class WeixinPayProxy {
|
||||
|
||||
/**
|
||||
* V3订单查询
|
||||
* <p>
|
||||
* 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;</br> 调用支付接口后,返回系统错误或未知交易状态情况;</br>
|
||||
* 调用被扫支付API,返回USERPAYING的状态;</br> 调用关单或撤销接口API之前,需确认支付状态;
|
||||
* </P>
|
||||
*
|
||||
* @param idQuery
|
||||
* 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级:
|
||||
@ -130,6 +136,8 @@ public class WeixinPayProxy {
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.Order
|
||||
* @see com.foxinmy.weixin4j.mp.api.PayApi
|
||||
* @see com.foxinmy.weixin4j.mp.api.Pay3Api
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2">订单查询API</a>
|
||||
* @return 订单详情
|
||||
* @throws WeixinException
|
||||
*/
|
||||
@ -253,9 +261,14 @@ public class WeixinPayProxy {
|
||||
|
||||
/**
|
||||
* V3申请退款(请求需要双向证书)</br>
|
||||
* <p>
|
||||
* 当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,微信支付将在收到退款请求并且验证成功之后,
|
||||
* 按照退款规则将支付款按原路退到买家帐号上。
|
||||
* </p>
|
||||
* <p style="color:red">
|
||||
* 交易时间超过 1 年的订单无法提交退款; </br> 支持部分退款,部分退需要设置相同的订单号和不同的 out_refund_no。一笔退款失
|
||||
* 败后重新提交,要采用原来的 out_refund_no。总退款金额不能超过用户实际支付金额。</br>
|
||||
* 1.交易时间超过半年的订单无法提交退款;
|
||||
* 2.微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。一笔退款失败后重新提交
|
||||
* ,要采用原来的退款单号。总退款金额不能超过用户实际支付金额。
|
||||
* </p>
|
||||
*
|
||||
* @param caFile
|
||||
@ -269,6 +282,8 @@ public class WeixinPayProxy {
|
||||
* 订单总金额,单位为元
|
||||
* @param refundFee
|
||||
* 退款总金额,单位为元,可以做部分退款
|
||||
* @param refundFeeType
|
||||
* 货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY
|
||||
* @param opUserId
|
||||
* 操作员帐号, 默认为商户号
|
||||
*
|
||||
@ -276,31 +291,37 @@ public class WeixinPayProxy {
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.RefundResult
|
||||
* @see com.foxinmy.weixin4j.mp.api.PayApi
|
||||
* @see com.foxinmy.weixin4j.mp.api.Pay3Api
|
||||
* @since V3
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4">申请退款API</a>
|
||||
* @since V3 TODO
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public com.foxinmy.weixin4j.mp.payment.v3.RefundResult refundV3(
|
||||
File caFile, IdQuery idQuery, String outRefundNo, double totalFee,
|
||||
double refundFee, String opUserId) throws WeixinException {
|
||||
double refundFee, CurrencyType refundFeeType, String opUserId)
|
||||
throws WeixinException {
|
||||
return pay3Api.refund(caFile, idQuery, outRefundNo, totalFee,
|
||||
refundFee, opUserId);
|
||||
refundFee, refundFeeType, opUserId);
|
||||
}
|
||||
|
||||
/**
|
||||
* V3退款申请采用properties中配置的ca文件
|
||||
*
|
||||
* @see {@link com.foxinmy.weixin4j.mp.WeixinPayProxy#refundV3(File, IdQuery, String, double, double, String)}
|
||||
* @see {@link com.foxinmy.weixin4j.mp.WeixinPayProxy#refundV3(File, IdQuery, String, double, double,CurrencyType, String)}
|
||||
*/
|
||||
public com.foxinmy.weixin4j.mp.payment.v3.RefundResult refundV3(
|
||||
IdQuery idQuery, String outRefundNo, double totalFee,
|
||||
double refundFee, String opUserId) throws WeixinException {
|
||||
File caFile = new File(ConfigUtil.getClassPathValue("ca_file"));
|
||||
return pay3Api.refund(caFile, idQuery, outRefundNo, totalFee,
|
||||
refundFee, opUserId);
|
||||
refundFee, CurrencyType.CNY, opUserId);
|
||||
}
|
||||
|
||||
/**
|
||||
* V3退款查询</br> 退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款 3 个工作日后重新查询退款状态
|
||||
* V3退款查询
|
||||
* <p>
|
||||
* 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
|
||||
* </p>
|
||||
*
|
||||
* @param idQuery
|
||||
* 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id
|
||||
@ -310,6 +331,8 @@ public class WeixinPayProxy {
|
||||
* @see com.foxinmy.weixin4j.mp.api.PayApi
|
||||
* @see com.foxinmy.weixin4j.mp.api.Pay3Api
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.RefundRecord
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5">退款查询API</a>
|
||||
* @since V3
|
||||
* @throws WeixinException
|
||||
*/
|
||||
@ -333,6 +356,8 @@ public class WeixinPayProxy {
|
||||
* @return excel表格
|
||||
* @since V2 & V3
|
||||
* @see com.foxinmy.weixin4j.mp.api.PayApi
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单API</a>
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public File downloadbill(Date billDate, BillType billType)
|
||||
@ -378,8 +403,11 @@ public class WeixinPayProxy {
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭订单</br> 当订单支付失败,调用关单接口后用新订单号重新发起支付,如果关单失败,返回已完
|
||||
* 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。
|
||||
* 关闭订单
|
||||
* <p>
|
||||
* 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续
|
||||
* ,请调用关单接口,如果关单失败,返回已完 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。
|
||||
* </p>
|
||||
*
|
||||
* @param outTradeNo
|
||||
* 商户系统内部的订单号
|
||||
@ -388,13 +416,16 @@ public class WeixinPayProxy {
|
||||
* @see com.foxinmy.weixin4j.mp.api.Pay3Api
|
||||
* @since V3
|
||||
* @throws WeixinException
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3">关闭订单API</a>
|
||||
*/
|
||||
public ApiResult closeOrder(String outTradeNo) throws WeixinException {
|
||||
return payApi.closeOrder(outTradeNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* native支付URL转短链接
|
||||
* native支付URL转短链接:用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),减小二维码数据量
|
||||
* ,提升扫描速度和精确度。
|
||||
*
|
||||
* @param url
|
||||
* 具有native标识的支付URL
|
||||
@ -402,6 +433,8 @@ public class WeixinPayProxy {
|
||||
* @see com.foxinmy.weixin4j.mp.api.PayApi
|
||||
* @see com.foxinmy.weixin4j.mp.api.Pay2Api
|
||||
* @see com.foxinmy.weixin4j.mp.api.Pay3Api
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_9">转换短链接API</a>
|
||||
* @since V2 & V3
|
||||
* @throws WeixinException
|
||||
*/
|
||||
@ -428,6 +461,8 @@ public class WeixinPayProxy {
|
||||
* @return 处理结果
|
||||
* @see com.foxinmy.weixin4j.mp.api.PayApi
|
||||
* @see com.foxinmy.weixin4j.mp.api.Pay3Api
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_8">接口测试上报API</a>
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public XmlResult interfaceReport(String interfaceUrl, int executeTime,
|
||||
|
||||
@ -39,7 +39,7 @@ import com.foxinmy.weixin4j.http.SSLHttpRequest;
|
||||
import com.foxinmy.weixin4j.model.Token;
|
||||
import com.foxinmy.weixin4j.model.WeixinMpAccount;
|
||||
import com.foxinmy.weixin4j.mp.payment.PayUtil;
|
||||
import com.foxinmy.weixin4j.mp.payment.RefundConverter;
|
||||
import com.foxinmy.weixin4j.mp.payment.conver.RefundConverter;
|
||||
import com.foxinmy.weixin4j.mp.payment.v2.Order;
|
||||
import com.foxinmy.weixin4j.mp.payment.v2.RefundRecord;
|
||||
import com.foxinmy.weixin4j.mp.payment.v2.RefundResult;
|
||||
|
||||
@ -30,12 +30,14 @@ import com.foxinmy.weixin4j.http.SSLHttpRequest;
|
||||
import com.foxinmy.weixin4j.http.XmlResult;
|
||||
import com.foxinmy.weixin4j.model.WeixinMpAccount;
|
||||
import com.foxinmy.weixin4j.mp.payment.PayUtil;
|
||||
import com.foxinmy.weixin4j.mp.payment.RefundConverter;
|
||||
import com.foxinmy.weixin4j.mp.payment.conver.CouponConverter;
|
||||
import com.foxinmy.weixin4j.mp.payment.conver.RefundConverter;
|
||||
import com.foxinmy.weixin4j.mp.payment.v3.ApiResult;
|
||||
import com.foxinmy.weixin4j.mp.payment.v3.Order;
|
||||
import com.foxinmy.weixin4j.mp.payment.v3.RefundRecord;
|
||||
import com.foxinmy.weixin4j.mp.payment.v3.RefundResult;
|
||||
import com.foxinmy.weixin4j.mp.type.BillType;
|
||||
import com.foxinmy.weixin4j.mp.type.CurrencyType;
|
||||
import com.foxinmy.weixin4j.mp.type.IdQuery;
|
||||
import com.foxinmy.weixin4j.mp.type.IdType;
|
||||
import com.foxinmy.weixin4j.mp.util.ExcelUtil;
|
||||
@ -51,7 +53,7 @@ import com.foxinmy.weixin4j.util.RandomUtil;
|
||||
* @author jy
|
||||
* @date 2014年10月28日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
* @see <a href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php">公众号支付API</a>
|
||||
*/
|
||||
public class Pay3Api extends PayApi {
|
||||
|
||||
@ -61,12 +63,18 @@ public class Pay3Api extends PayApi {
|
||||
|
||||
/**
|
||||
* 订单查询
|
||||
* <p>
|
||||
* 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;</br> 调用支付接口后,返回系统错误或未知交易状态情况;</br>
|
||||
* 调用被扫支付API,返回USERPAYING的状态;</br> 调用关单或撤销接口API之前,需确认支付状态;
|
||||
* </P>
|
||||
*
|
||||
* @param idQuery
|
||||
* 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级:
|
||||
* transaction_id> out_trade_no
|
||||
* @return 订单信息
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.Order
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2">订单查询API</a>
|
||||
* @since V3
|
||||
* @throws WeixinException
|
||||
*/
|
||||
@ -77,15 +85,19 @@ public class Pay3Api extends PayApi {
|
||||
String param = map2xml(map);
|
||||
String orderquery_uri = getRequestUri("orderquery_v3_uri");
|
||||
Response response = request.post(orderquery_uri, param);
|
||||
return response.getAsObject(new TypeReference<Order>() {
|
||||
});
|
||||
return CouponConverter.fromXML(response.getAsString(), Order.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请退款(请求需要双向证书)</br>
|
||||
* 申请退款(请求需要双向证书)
|
||||
* <p>
|
||||
* 当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,微信支付将在收到退款请求并且验证成功之后,
|
||||
* 按照退款规则将支付款按原路退到买家帐号上。
|
||||
* </p>
|
||||
* <p style="color:red">
|
||||
* 交易时间超过 1 年的订单无法提交退款; </br> 支持部分退款,部分退需要设置相同的订单号和不同的 out_refund_no。一笔退款失
|
||||
* 败后重新提交,要采用原来的 out_refund_no。总退款金额不能超过用户实际支付金额。</br>
|
||||
* 1.交易时间超过半年的订单无法提交退款;
|
||||
* 2.微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。一笔退款失败后重新提交
|
||||
* ,要采用原来的退款单号。总退款金额不能超过用户实际支付金额。
|
||||
* </p>
|
||||
*
|
||||
* @param caFile
|
||||
@ -104,6 +116,8 @@ public class Pay3Api extends PayApi {
|
||||
*
|
||||
* @return 退款申请结果
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.RefundResult
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4">申请退款API</a>
|
||||
* @since V3
|
||||
* @throws WeixinException
|
||||
*/
|
||||
@ -147,15 +161,15 @@ public class Pay3Api extends PayApi {
|
||||
}
|
||||
}
|
||||
}
|
||||
return response.getAsObject(new TypeReference<RefundResult>() {
|
||||
});
|
||||
return CouponConverter.fromXML(response.getAsString(),
|
||||
RefundResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款申请
|
||||
*
|
||||
* @param caFile
|
||||
* 证书文件(V2版本后缀为*.pfx)
|
||||
* 证书文件(V3版本后缀为*.p12)
|
||||
* @param idQuery
|
||||
* 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级:
|
||||
* transaction_id> out_trade_no
|
||||
@ -165,15 +179,22 @@ public class Pay3Api extends PayApi {
|
||||
* 订单总金额,单位为元
|
||||
* @param refundFee
|
||||
* 退款总金额,单位为元,可以做部分退款
|
||||
* @param refundFeeType
|
||||
* 货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY
|
||||
* @param opUserId
|
||||
* 操作员帐号, 默认为商户号
|
||||
* @see {@link com.foxinmy.weixin4j.mp.api.Pay3Api#refund(File, IdQuery, String, double, double, String, Map)}
|
||||
*/
|
||||
public RefundResult refund(File caFile, IdQuery idQuery,
|
||||
String outRefundNo, double totalFee, double refundFee,
|
||||
String opUserId) throws WeixinException {
|
||||
CurrencyType refundFeeType, String opUserId) throws WeixinException {
|
||||
Map<String, String> mopara = new HashMap<String, String>();
|
||||
if (refundFeeType == null) {
|
||||
refundFeeType = CurrencyType.CNY;
|
||||
}
|
||||
mopara.put("refund_fee_type", refundFeeType.name());
|
||||
return refund(caFile, idQuery, outRefundNo, totalFee, refundFee,
|
||||
opUserId, null);
|
||||
opUserId, mopara);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -221,12 +242,15 @@ public class Pay3Api extends PayApi {
|
||||
}
|
||||
|
||||
/**
|
||||
* native支付URL转短链接
|
||||
* 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 = baseMap(null);
|
||||
@ -245,14 +269,19 @@ public class Pay3Api extends PayApi {
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭订单</br> 当订单支付失败,调用关单接口后用新订单号重新发起支付,如果关单失败,返回已完
|
||||
* 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。
|
||||
* 关闭订单
|
||||
* <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 ApiResult closeOrder(String outTradeNo) throws WeixinException {
|
||||
Map<String, String> map = baseMap(new IdQuery(outTradeNo,
|
||||
@ -280,6 +309,8 @@ public class Pay3Api extends PayApi {
|
||||
* REFUND,返回当日退款订单
|
||||
* @return excel表格
|
||||
* @since V3
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单API</a>
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public File downloadbill(Date billDate, BillType billType)
|
||||
@ -349,7 +380,11 @@ public class Pay3Api extends PayApi {
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款查询</br> 退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款 3 个工作日后重新查询退款状态
|
||||
* 退款查询
|
||||
*
|
||||
* <p>
|
||||
* 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
|
||||
* </p>
|
||||
*
|
||||
* @param idQuery
|
||||
* 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id
|
||||
@ -358,6 +393,8 @@ public class Pay3Api extends PayApi {
|
||||
* @return 退款记录
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.RefundRecord
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.RefundDetail
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5">退款查询API</a>
|
||||
* @since V3
|
||||
* @throws WeixinException
|
||||
*/
|
||||
@ -390,6 +427,8 @@ public class Pay3Api extends PayApi {
|
||||
* 调用接口返回的基本数据
|
||||
* @return 处理结果
|
||||
* @throws WeixinException
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_8">接口测试上报API</a>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public XmlResult interfaceReport(String interfaceUrl, int executeTime,
|
||||
|
||||
@ -21,6 +21,7 @@ public class PayPackage implements Serializable {
|
||||
private static final long serialVersionUID = 3450161267802545790L;
|
||||
|
||||
private String body; // 商品描述 必须
|
||||
private String detail; // 商品详情 非必须
|
||||
private String attach; // 附加数据,原样返回 非必须
|
||||
@XStreamAlias("out_trade_no")
|
||||
@JSONField(name = "out_trade_no")
|
||||
@ -56,6 +57,14 @@ public class PayPackage implements Serializable {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public String getDetail() {
|
||||
return detail;
|
||||
}
|
||||
|
||||
public void setDetail(String detail) {
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
public String getAttach() {
|
||||
return attach;
|
||||
}
|
||||
@ -151,10 +160,10 @@ public class PayPackage implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PayPackage [body=" + body + ", attach=" + attach
|
||||
+ ", outTradeNo=" + outTradeNo + ", totalFee=" + totalFee
|
||||
+ ", spbillCreateIp=" + spbillCreateIp + ", timeStart="
|
||||
+ timeStart + ", timeExpire=" + timeExpire + ", goodsTag="
|
||||
+ goodsTag + ", notifyUrl=" + notifyUrl + "]";
|
||||
return "PayPackage [body=" + body + ", detail=" + detail + ", attach="
|
||||
+ attach + ", outTradeNo=" + outTradeNo + ", totalFee="
|
||||
+ totalFee + ", spbillCreateIp=" + spbillCreateIp
|
||||
+ ", timeStart=" + timeStart + ", timeExpire=" + timeExpire
|
||||
+ ", goodsTag=" + goodsTag + ", notifyUrl=" + notifyUrl + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,7 +208,9 @@ public class PayUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建预支付对象</br>
|
||||
* 统一下单接口</br>
|
||||
* 除被扫支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPI
|
||||
* 、APP等不同场景生成交易串调起支付。
|
||||
*
|
||||
* @param payPackage
|
||||
* 包含订单信息的对象
|
||||
@ -216,6 +218,8 @@ public class PayUtil {
|
||||
* <font color="red">如果sign为空 则拿paysignkey进行签名</font>
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.PayPackageV3
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.PrePay
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1">统一下单接口</a>
|
||||
* @return 预支付对象
|
||||
*/
|
||||
public static PrePay createPrePay(PayPackageV3 payPackage, String paySignKey)
|
||||
@ -306,13 +310,14 @@ public class PayUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建V3.x NativePay支付链接
|
||||
* 创建V3.x NativePay支付(扫码支付)链接
|
||||
*
|
||||
* @param weixinAccount
|
||||
* 支付配置信息
|
||||
* @param productId
|
||||
* 与订单ID等价
|
||||
* @return
|
||||
* @see <a href="http://pay.weixin.qq.com/wiki/doc/api/native.php">扫码支付</a>
|
||||
*/
|
||||
public static String createNativePayRequestURLV3(
|
||||
WeixinMpAccount weixinAccount, String productId) {
|
||||
@ -330,7 +335,7 @@ public class PayUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* NATIVE回调时的响应
|
||||
* 创建V2.x NATIVE回调时的响应字符串
|
||||
*
|
||||
* @param weixinAccount
|
||||
* 商户信息
|
||||
@ -360,7 +365,7 @@ public class PayUtil {
|
||||
* 提交被扫支付
|
||||
*
|
||||
* @param authCode
|
||||
* 扫码支付授权码 ,设备读取用 户微信中的条码或者二维码 信息
|
||||
* 扫码支付授权码 ,设备读取用户微信中的条码或者二维码信息
|
||||
* @param body
|
||||
* 商品描述
|
||||
* @param attach
|
||||
@ -373,7 +378,7 @@ public class PayUtil {
|
||||
* 订单生成的机器 IP
|
||||
* @param weixinAccount
|
||||
* 商户信息
|
||||
* @return 返回数据
|
||||
* @return 支付的订单信息
|
||||
* @see {@link com.foxinmy.weixin4j.mp.payment.PayUtil#createMicroPay(MicroPayPackage, WeixinMpAccount)}
|
||||
* @throws WeixinException
|
||||
*/
|
||||
@ -387,14 +392,17 @@ public class PayUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交被扫支付
|
||||
* 提交被扫支付:收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,由商户收银台或者商户后台调用该接口发起支付.
|
||||
*
|
||||
* @param payPackage
|
||||
* 订单信息
|
||||
* @param weixinAccount
|
||||
* 商户信息
|
||||
* @return 返回数据
|
||||
* @return 支付的订单信息
|
||||
* @throws WeixinException
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.Order
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10">提交被扫支付API</a>
|
||||
*/
|
||||
public static com.foxinmy.weixin4j.mp.payment.v3.Order createMicroPay(
|
||||
MicroPayPackage payPackage, WeixinMpAccount weixinAccount)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.foxinmy.weixin4j.mp.payment;
|
||||
package com.foxinmy.weixin4j.mp.payment.conver;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
@ -9,6 +9,9 @@ import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.foxinmy.weixin4j.mp.payment.coupon.CouponInfo;
|
||||
import com.foxinmy.weixin4j.mp.payment.v3.Order;
|
||||
import com.foxinmy.weixin4j.mp.payment.v3.RefundResult;
|
||||
import com.foxinmy.weixin4j.xml.XmlStream;
|
||||
import com.thoughtworks.xstream.converters.Converter;
|
||||
import com.thoughtworks.xstream.converters.MarshallingContext;
|
||||
@ -20,45 +23,41 @@ import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
import com.thoughtworks.xstream.mapper.Mapper;
|
||||
|
||||
/**
|
||||
* 退款查询接口调用结果转换类
|
||||
* V3订单详情转换类
|
||||
*
|
||||
* @className RefundConverter
|
||||
* @className OrderConverter
|
||||
* @author jy
|
||||
* @date 2014年11月2日
|
||||
* @date 2015年3月24日
|
||||
* @since JDK 1.7
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v2.RefundRecord
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v2.RefundDetail
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.RefundRecord
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.RefundDetail
|
||||
* @see
|
||||
*/
|
||||
public class RefundConverter {
|
||||
public class CouponConverter {
|
||||
|
||||
private final static XmlStream xStream = XmlStream.get();
|
||||
private final static Mapper mapper;
|
||||
private final static ReflectionProvider reflectionProvider;
|
||||
private final static Pattern pattern = Pattern.compile("(_\\d)$");
|
||||
private static Class<CouponInfo> COUPON_CLASS = CouponInfo.class;
|
||||
private static Class<?> clazz;
|
||||
private final static Class<com.foxinmy.weixin4j.mp.payment.v2.RefundRecord> REFUNDRECORD2 = com.foxinmy.weixin4j.mp.payment.v2.RefundRecord.class;
|
||||
private final static Class<com.foxinmy.weixin4j.mp.payment.v3.RefundRecord> REFUNDRECORD3 = com.foxinmy.weixin4j.mp.payment.v3.RefundRecord.class;
|
||||
|
||||
static {
|
||||
xStream.processAnnotations(new Class[] { REFUNDRECORD2, REFUNDRECORD3,
|
||||
com.foxinmy.weixin4j.mp.payment.v2.RefundDetail.class,
|
||||
com.foxinmy.weixin4j.mp.payment.v3.RefundDetail.class });
|
||||
xStream.aliasField("refund_state", com.foxinmy.weixin4j.mp.payment.v2.RefundDetail.class, "refundStatus");
|
||||
xStream.processAnnotations(new Class[] { COUPON_CLASS });
|
||||
xStream.registerConverter(new $());
|
||||
mapper = xStream.getMapper();
|
||||
reflectionProvider = xStream.getReflectionProvider();
|
||||
}
|
||||
|
||||
public static <T> T fromXML(String xml, Class<T> clazz) {
|
||||
RefundConverter.clazz = clazz;
|
||||
CouponConverter.clazz = clazz;
|
||||
xStream.processAnnotations(clazz);
|
||||
return xStream.fromXML(xml, clazz);
|
||||
}
|
||||
|
||||
private static class $ implements Converter {
|
||||
@Override
|
||||
public boolean canConvert(@SuppressWarnings("rawtypes") Class clazz) {
|
||||
return clazz.equals(REFUNDRECORD2) || clazz.equals(REFUNDRECORD3);
|
||||
return clazz.equals(Order.class)
|
||||
|| clazz.equals(RefundResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -71,9 +70,9 @@ public class RefundConverter {
|
||||
@Override
|
||||
public Object unmarshal(HierarchicalStreamReader reader,
|
||||
UnmarshallingContext context) {
|
||||
Object refund = null;
|
||||
Object object = null;
|
||||
try {
|
||||
refund = clazz.newInstance();
|
||||
object = clazz.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
@ -88,9 +87,9 @@ public class RefundConverter {
|
||||
Field field = reflectionProvider.getFieldOrNull(clazz,
|
||||
fieldName);
|
||||
if (field != null) {
|
||||
Object value = context.convertAnother(refund,
|
||||
Object value = context.convertAnother(object,
|
||||
field.getType());
|
||||
reflectionProvider.writeField(refund, fieldName, value,
|
||||
reflectionProvider.writeField(object, fieldName, value,
|
||||
field.getDeclaringClass());
|
||||
} else if ((matcher = pattern.matcher(nodeName)).find()) {
|
||||
String key = matcher.group();
|
||||
@ -103,27 +102,34 @@ public class RefundConverter {
|
||||
}
|
||||
reader.moveUp();
|
||||
}
|
||||
StringBuilder detailXml = new StringBuilder();
|
||||
detailXml.append("<list>");
|
||||
String detailCanonicalName = clazz.getCanonicalName().replaceFirst(
|
||||
"RefundRecord", "RefundDetail");
|
||||
if (!outMap.isEmpty()) {
|
||||
StringBuilder couponXml = new StringBuilder();
|
||||
couponXml.append("<list>");
|
||||
for (Iterator<Entry<String, Map<String, String>>> outIt = outMap
|
||||
.entrySet().iterator(); outIt.hasNext();) {
|
||||
detailXml.append("<").append(detailCanonicalName).append(">");
|
||||
couponXml.append("<")
|
||||
.append(COUPON_CLASS.getCanonicalName())
|
||||
.append(">");
|
||||
for (Iterator<Entry<String, String>> innerIt = outIt.next()
|
||||
.getValue().entrySet().iterator(); innerIt.hasNext();) {
|
||||
.getValue().entrySet().iterator(); innerIt
|
||||
.hasNext();) {
|
||||
Entry<String, String> entry = innerIt.next();
|
||||
detailXml.append("<").append(entry.getKey()).append(">");
|
||||
detailXml.append(entry.getValue());
|
||||
detailXml.append("</").append(entry.getKey()).append(">");
|
||||
couponXml.append("<").append(entry.getKey())
|
||||
.append(">");
|
||||
couponXml.append(entry.getValue());
|
||||
couponXml.append("</").append(entry.getKey())
|
||||
.append(">");
|
||||
}
|
||||
detailXml.append("</").append(detailCanonicalName).append(">");
|
||||
couponXml.append("</")
|
||||
.append(COUPON_CLASS.getCanonicalName())
|
||||
.append(">");
|
||||
}
|
||||
detailXml.append("</list>");
|
||||
reflectionProvider.writeField(refund, "details",
|
||||
xStream.fromXML(detailXml.toString(), List.class),
|
||||
couponXml.append("</list>");
|
||||
reflectionProvider.writeField(object, "couponList",
|
||||
xStream.fromXML(couponXml.toString(), List.class),
|
||||
List.class.getDeclaringClass());
|
||||
return refund;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
package com.foxinmy.weixin4j.mp.payment.conver;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.foxinmy.weixin4j.mp.payment.coupon.CouponInfo;
|
||||
import com.foxinmy.weixin4j.xml.XmlStream;
|
||||
import com.thoughtworks.xstream.converters.Converter;
|
||||
import com.thoughtworks.xstream.converters.MarshallingContext;
|
||||
import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
|
||||
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
import com.thoughtworks.xstream.mapper.Mapper;
|
||||
|
||||
/**
|
||||
* 退款查询接口调用结果转换类
|
||||
*
|
||||
* @className RefundConverter
|
||||
* @author jy
|
||||
* @date 2014年11月2日
|
||||
* @since JDK 1.7
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v2.RefundRecord
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v2.RefundDetail
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.RefundRecord
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.RefundDetail
|
||||
*/
|
||||
public class RefundConverter {
|
||||
private final static XmlStream xStream = XmlStream.get();
|
||||
private final static Mapper mapper;
|
||||
private final static ReflectionProvider reflectionProvider;
|
||||
private final static Pattern REFUND_PATTERN = Pattern.compile("_\\d{1,}$");
|
||||
private final static Pattern COUPON_PATTERN = Pattern
|
||||
.compile("_\\d{1,}_\\d{1,}$");
|
||||
private static Class<?> clazz;
|
||||
private final static Class<CouponInfo> COUPON_CLASS = CouponInfo.class;
|
||||
private final static Class<com.foxinmy.weixin4j.mp.payment.v2.RefundRecord> REFUNDRECORD2 = com.foxinmy.weixin4j.mp.payment.v2.RefundRecord.class;
|
||||
private final static Class<com.foxinmy.weixin4j.mp.payment.v3.RefundRecord> REFUNDRECORD3 = com.foxinmy.weixin4j.mp.payment.v3.RefundRecord.class;
|
||||
|
||||
static {
|
||||
xStream.processAnnotations(new Class[] { REFUNDRECORD2, REFUNDRECORD3 });
|
||||
xStream.aliasField("refund_state",
|
||||
com.foxinmy.weixin4j.mp.payment.v2.RefundDetail.class,
|
||||
"refundStatus");
|
||||
xStream.registerConverter(new $());
|
||||
mapper = xStream.getMapper();
|
||||
reflectionProvider = xStream.getReflectionProvider();
|
||||
}
|
||||
|
||||
public static <T> T fromXML(String xml, Class<T> clazz) {
|
||||
RefundConverter.clazz = clazz;
|
||||
xStream.processAnnotations(clazz);
|
||||
return xStream.fromXML(xml, clazz);
|
||||
}
|
||||
|
||||
private static class $ implements Converter {
|
||||
@Override
|
||||
public boolean canConvert(@SuppressWarnings("rawtypes") Class clazz) {
|
||||
return clazz.equals(REFUNDRECORD2) || clazz.equals(REFUNDRECORD3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(Object source, HierarchicalStreamWriter writer,
|
||||
MarshallingContext context) {
|
||||
new ReflectionConverter(mapper, reflectionProvider).marshal(source,
|
||||
writer, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object unmarshal(HierarchicalStreamReader reader,
|
||||
UnmarshallingContext context) {
|
||||
Object refund = null;
|
||||
try {
|
||||
refund = clazz.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Matcher matcher = null;
|
||||
Map<String, Map<String, String>> refundMap = new HashMap<String, Map<String, String>>();
|
||||
Map<String, Map<String, String>> couponMap = new HashMap<String, Map<String, String>>();
|
||||
while (reader.hasMoreChildren()) {
|
||||
reader.moveDown();
|
||||
String nodeName = reader.getNodeName();
|
||||
String fieldName = mapper.realMember(clazz, nodeName);
|
||||
Field field = reflectionProvider.getFieldOrNull(clazz,
|
||||
fieldName);
|
||||
if (field != null) {
|
||||
Object value = context.convertAnother(refund,
|
||||
field.getType());
|
||||
reflectionProvider.writeField(refund, fieldName, value,
|
||||
field.getDeclaringClass());
|
||||
} else if ((matcher = REFUND_PATTERN.matcher(nodeName)).find()) {
|
||||
String key = matcher.group();
|
||||
Map<String, String> innerMap = null;
|
||||
if ((matcher = COUPON_PATTERN.matcher(nodeName)).find()) {
|
||||
key = matcher.group();
|
||||
if ((innerMap = couponMap.get(key)) == null) {
|
||||
innerMap = new HashMap<String, String>();
|
||||
couponMap.put(key, innerMap);
|
||||
}
|
||||
} else {
|
||||
if ((innerMap = refundMap
|
||||
.get(String.format("%s_", key))) == null) {
|
||||
innerMap = new HashMap<String, String>();
|
||||
refundMap.put(String.format("%s_", key), innerMap);
|
||||
}
|
||||
}
|
||||
innerMap.put(nodeName.replaceFirst(key, ""),
|
||||
reader.getValue());
|
||||
}
|
||||
reader.moveUp();
|
||||
}
|
||||
if (!refundMap.isEmpty()) {
|
||||
StringBuilder detailXml = new StringBuilder();
|
||||
detailXml.append("<list>");
|
||||
String detailCanonicalName = clazz.getCanonicalName()
|
||||
.replaceFirst("RefundRecord", "RefundDetail");
|
||||
for (Iterator<Entry<String, Map<String, String>>> refundIT = refundMap
|
||||
.entrySet().iterator(); refundIT.hasNext();) {
|
||||
detailXml.append("<").append(detailCanonicalName)
|
||||
.append(">");
|
||||
Entry<String, Map<String, String>> refundEntry = refundIT
|
||||
.next();
|
||||
for (Iterator<Entry<String, String>> innerIt = refundEntry
|
||||
.getValue().entrySet().iterator(); innerIt
|
||||
.hasNext();) {
|
||||
Entry<String, String> entry = innerIt.next();
|
||||
detailXml.append("<").append(entry.getKey())
|
||||
.append(">");
|
||||
detailXml.append(entry.getValue());
|
||||
detailXml.append("</").append(entry.getKey())
|
||||
.append(">");
|
||||
}
|
||||
if (!couponMap.isEmpty()) {
|
||||
detailXml.append("<couponList class=\"")
|
||||
.append(ArrayList.class.getCanonicalName())
|
||||
.append("\">");
|
||||
Iterator<Entry<String, Map<String, String>>> couponIT = couponMap
|
||||
.entrySet().iterator();
|
||||
while (couponIT.hasNext()) {
|
||||
Entry<String, Map<String, String>> couponEntry = couponIT
|
||||
.next();
|
||||
if (couponEntry.getKey().startsWith(
|
||||
refundEntry.getKey())) {
|
||||
detailXml
|
||||
.append("<")
|
||||
.append(COUPON_CLASS.getCanonicalName())
|
||||
.append(">");
|
||||
for (Iterator<Entry<String, String>> innerIt = couponEntry
|
||||
.getValue().entrySet().iterator(); innerIt
|
||||
.hasNext();) {
|
||||
Entry<String, String> entry = innerIt
|
||||
.next();
|
||||
detailXml.append("<")
|
||||
.append(entry.getKey()).append(">");
|
||||
detailXml.append(entry.getValue());
|
||||
detailXml.append("</")
|
||||
.append(entry.getKey()).append(">");
|
||||
}
|
||||
detailXml
|
||||
.append("</")
|
||||
.append(COUPON_CLASS.getCanonicalName())
|
||||
.append(">");
|
||||
couponIT.remove();
|
||||
}
|
||||
}
|
||||
detailXml.append("</couponList>");
|
||||
}
|
||||
detailXml.append("</").append(detailCanonicalName)
|
||||
.append(">");
|
||||
}
|
||||
detailXml.append("</list>");
|
||||
reflectionProvider.writeField(refund, "details",
|
||||
xStream.fromXML(detailXml.toString(), List.class),
|
||||
List.class.getDeclaringClass());
|
||||
}
|
||||
return refund;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.foxinmy.weixin4j.mp.payment.coupon;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 代金券信息
|
||||
*
|
||||
* @className CouponBase
|
||||
* @author jy
|
||||
* @date 2015年3月24日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class CouponInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8744999305258786901L;
|
||||
|
||||
// 代金券或立减优惠批次ID
|
||||
@XStreamAlias("coupon_batch_id")
|
||||
@JSONField(name = "coupon_batch_id")
|
||||
private String couponBatchId;
|
||||
// 代金券或立减优惠ID
|
||||
@XStreamAlias("coupon_id")
|
||||
@JSONField(name = "coupon_id")
|
||||
private String couponId;
|
||||
// 单个代金券或立减优惠支付金额
|
||||
@XStreamAlias("coupon_fee")
|
||||
@JSONField(name = "coupon_fee")
|
||||
private Integer couponFee;
|
||||
|
||||
public String getCouponBatchId() {
|
||||
return couponBatchId;
|
||||
}
|
||||
|
||||
public String getCouponId() {
|
||||
return couponId;
|
||||
}
|
||||
|
||||
public Integer getCouponFee() {
|
||||
return couponFee;
|
||||
}
|
||||
|
||||
/**
|
||||
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
|
||||
*
|
||||
* @return 元单位
|
||||
*/
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
public double getFormatCouponFee() {
|
||||
return couponFee / 100d;
|
||||
}
|
||||
|
||||
public void setCouponId(String couponId) {
|
||||
this.couponId = couponId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "couponBatchId=" + couponBatchId + ", couponId=" + couponId
|
||||
+ ", couponFee=" + couponFee;
|
||||
}
|
||||
}
|
||||
@ -110,6 +110,6 @@ public class ApiResult extends XmlResult {
|
||||
public String toString() {
|
||||
return "appId=" + appId + ", mchId=" + mchId + ", subMchId=" + subMchId
|
||||
+ ", nonceStr=" + nonceStr + ", sign=" + sign + ", deviceInfo="
|
||||
+ deviceInfo + ", recall=" + recall + ", " + super.toString();
|
||||
+ deviceInfo + ", recall=" + getFormatRecall() + ", " + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
package com.foxinmy.weixin4j.mp.payment.v3;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.foxinmy.weixin4j.mp.payment.coupon.CouponInfo;
|
||||
import com.foxinmy.weixin4j.mp.type.CurrencyType;
|
||||
import com.foxinmy.weixin4j.mp.type.TradeState;
|
||||
import com.foxinmy.weixin4j.mp.type.TradeType;
|
||||
import com.foxinmy.weixin4j.util.DateUtil;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import com.thoughtworks.xstream.annotations.XStreamOmitField;
|
||||
|
||||
/**
|
||||
* V3订单信息
|
||||
@ -54,6 +55,14 @@ public class Order extends ApiResult {
|
||||
@XStreamAlias("coupon_fee")
|
||||
@JSONField(name = "coupon_fee")
|
||||
private Integer couponFee;
|
||||
// 代金券或立减优惠使用数量
|
||||
@XStreamAlias("coupon_count")
|
||||
@JSONField(name = "coupon_count")
|
||||
private Integer couponCount;
|
||||
// 代金券信息
|
||||
@XStreamOmitField
|
||||
@JSONField(serialize = false)
|
||||
private List<CouponInfo> couponList;
|
||||
@XStreamAlias("cash_fee")
|
||||
@JSONField(name = "cash_fee")
|
||||
private int cashFee;
|
||||
@ -75,6 +84,10 @@ public class Order extends ApiResult {
|
||||
@XStreamAlias("time_end")
|
||||
@JSONField(name = "time_end")
|
||||
private String timeEnd;
|
||||
// 交易状态描述
|
||||
@XStreamAlias("trade_state_desc")
|
||||
@JSONField(name = "trade_state_desc")
|
||||
private String tradeStateDesc;
|
||||
|
||||
public TradeState getTradeState() {
|
||||
return tradeState;
|
||||
@ -88,6 +101,11 @@ public class Order extends ApiResult {
|
||||
return isSubscribe;
|
||||
}
|
||||
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
public boolean getFormatIsSubscribe() {
|
||||
return isSubscribe != null && isSubscribe.equalsIgnoreCase("y");
|
||||
}
|
||||
|
||||
public TradeType getTradeType() {
|
||||
return tradeType;
|
||||
}
|
||||
@ -124,6 +142,15 @@ public class Order extends ApiResult {
|
||||
return couponFee != null ? couponFee / 100d : 0d;
|
||||
}
|
||||
|
||||
public Integer getCouponCount() {
|
||||
return couponCount;
|
||||
}
|
||||
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
public int getFormatCouponCount() {
|
||||
return couponCount != null ? couponCount.intValue() : 0;
|
||||
}
|
||||
|
||||
public int getCashFee() {
|
||||
return cashFee;
|
||||
}
|
||||
@ -151,7 +178,7 @@ public class Order extends ApiResult {
|
||||
}
|
||||
|
||||
public String getAttach() {
|
||||
return StringUtils.isBlank(attach) ? null : attach;
|
||||
return attach;
|
||||
}
|
||||
|
||||
public String getTimeEnd() {
|
||||
@ -163,18 +190,30 @@ public class Order extends ApiResult {
|
||||
return DateUtil.parse2yyyyMMddHHmmss(timeEnd);
|
||||
}
|
||||
|
||||
public String getTradeStateDesc() {
|
||||
return tradeStateDesc;
|
||||
}
|
||||
|
||||
public List<CouponInfo> getCouponList() {
|
||||
return couponList;
|
||||
}
|
||||
|
||||
public void setCouponList(List<CouponInfo> couponList) {
|
||||
this.couponList = couponList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Order [tradeState=" + tradeState + ", openId=" + openId
|
||||
+ ", isSubscribe=" + isSubscribe + ", tradeType=" + tradeType
|
||||
+ ", bankType=" + bankType + ", totalFee=" + totalFee
|
||||
+ ", couponFee=" + couponFee + ", cashFee=" + cashFee
|
||||
+ ", feeType=" + feeType + ", transactionId=" + transactionId
|
||||
+ ", outTradeNo=" + outTradeNo + ", attach=" + attach
|
||||
+ ", timeEnd=" + timeEnd + ", getFormatTotalFee()="
|
||||
+ getFormatTotalFee() + ", getFormatCouponFee()="
|
||||
+ getFormatCouponFee() + ", getFormatCashFee()="
|
||||
+ getFormatCashFee() + ", getFormatTimeEnd()="
|
||||
+ getFormatTimeEnd() + ", " + super.toString() + "]";
|
||||
+ ", isSubscribe=" + getFormatIsSubscribe() + ", tradeType="
|
||||
+ tradeType + ", bankType=" + bankType + ", feeType=" + feeType
|
||||
+ ", transactionId=" + transactionId + ", outTradeNo="
|
||||
+ outTradeNo + ", attach=" + attach + ", timeEnd=" + timeEnd
|
||||
+ ", totalFee=" + getFormatTotalFee() + ", couponFee="
|
||||
+ getFormatCouponFee() + ", couponCount="
|
||||
+ getFormatCouponCount() + ", couponList=" + couponList
|
||||
+ ", cashFee=" + getFormatCashFee() + ", timeEnd="
|
||||
+ getFormatTimeEnd() + ", tradeStateDesc=" + tradeStateDesc
|
||||
+ ", " + super.toString() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,12 +18,20 @@ public class PrePay extends ApiResult {
|
||||
private static final long serialVersionUID = -8430005768959715444L;
|
||||
|
||||
@XStreamAlias("trade_type")
|
||||
private TradeType tradeType;// 交易类型JSAPI、NATIVE、APP 非空
|
||||
/**
|
||||
* 调用接口提交的交易类型,取值如下:JSAPI,NATIVE,APP,
|
||||
*/
|
||||
private TradeType tradeType;
|
||||
@XStreamAlias("prepay_id")
|
||||
private String prepayId;// 微信生成的预支付 ID,用于后续接口调用中使用二维码链接 非空
|
||||
/**
|
||||
* 微信生成的预支付回话标识,用于后续接口调用中使用,该值有效期为2小时
|
||||
*/
|
||||
private String prepayId;
|
||||
@XStreamAlias("code_url")
|
||||
private String codeUrl;// trade_type 为 NATIVE 是有 返回,此参数可直接生成二 维码展示出来进行扫码支付
|
||||
// 可能为空
|
||||
/**
|
||||
* trade_type 为 NATIVE 是有 返回,此参数可直接生成二 维码展示出来进行扫码支付 可能为空
|
||||
*/
|
||||
private String codeUrl;
|
||||
|
||||
public PrePay() {
|
||||
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
package com.foxinmy.weixin4j.mp.payment.v3;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.foxinmy.weixin4j.mp.payment.coupon.CouponInfo;
|
||||
import com.foxinmy.weixin4j.mp.type.CurrencyType;
|
||||
import com.foxinmy.weixin4j.mp.type.RefundChannel;
|
||||
import com.foxinmy.weixin4j.mp.type.RefundStatus;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
@ -32,12 +36,43 @@ public class RefundDetail extends ApiResult {
|
||||
@XStreamAlias("refund_fee")
|
||||
@JSONField(name = "refund_fee")
|
||||
private int refundFee; // 退款总金额,单位为分,可以做部分退款
|
||||
@XStreamAlias("refund_fee_type")
|
||||
@JSONField(name = "refund_fee_type")
|
||||
private CurrencyType refundFeeType; // 退款货币种类
|
||||
@XStreamAlias("total_fee")
|
||||
@JSONField(name = "total_fee")
|
||||
private int totalFee; // 订单总金额
|
||||
@XStreamAlias("fee_type")
|
||||
@JSONField(name = "fee_type")
|
||||
private CurrencyType feeType; // 订单金额货币种类
|
||||
@XStreamAlias("cash_fee")
|
||||
@JSONField(name = "cash_fee")
|
||||
private int cashFee; // 现金支付金额
|
||||
@XStreamAlias("cash_fee_type")
|
||||
@JSONField(name = "cash_fee_type")
|
||||
private CurrencyType cashFeeType; // 现金支付货币种类
|
||||
@XStreamAlias("cash_refund_fee")
|
||||
@JSONField(name = "cash_refund_fee")
|
||||
private Integer cashRefundFee; // 现金退款金额
|
||||
@XStreamAlias("cash_refund_fee_type")
|
||||
@JSONField(name = "cash_refund_fee_type")
|
||||
private CurrencyType cashRefundFeeType; // 现金退款货币类型
|
||||
@XStreamAlias("refund_status")
|
||||
@JSONField(name = "refund_status")
|
||||
private String refundStatus; // 退款状态
|
||||
@XStreamAlias("coupon_refund_fee")
|
||||
@JSONField(name = "coupon_refund_fee")
|
||||
private int couponRefundFee; // 现金券退款金额<=退款金额,退款金额-现金券退款金额为现金
|
||||
private Integer couponRefundFee; // 现金券退款金额<=退款金额,退款金额-现金券退款金额为现金
|
||||
/**
|
||||
* <font
|
||||
* color="red">微信支付文档上写的coupon_count,而实际测试拿到的是coupon_refund_count,做个记号。
|
||||
* </font>
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_count")
|
||||
@JSONField(name = "coupon_refund_count")
|
||||
private Integer couponRefundCount; // 代金券或立减优惠使用数量
|
||||
@JSONField(serialize = false)
|
||||
private List<CouponInfo> couponList; // 代金券信息
|
||||
|
||||
public String getOutRefundNo() {
|
||||
return outRefundNo;
|
||||
@ -63,6 +98,10 @@ public class RefundDetail extends ApiResult {
|
||||
return refundFee;
|
||||
}
|
||||
|
||||
public CurrencyType getFeeType() {
|
||||
return feeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
|
||||
*
|
||||
@ -85,7 +124,7 @@ public class RefundDetail extends ApiResult {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCouponRefundFee() {
|
||||
public Integer getCouponRefundFee() {
|
||||
return couponRefundFee;
|
||||
}
|
||||
|
||||
@ -96,17 +135,92 @@ public class RefundDetail extends ApiResult {
|
||||
*/
|
||||
@JSONField(deserialize = false, serialize = false)
|
||||
public double getFormatCouponRefundFee() {
|
||||
return couponRefundFee / 100d;
|
||||
return couponRefundFee != null ? couponRefundFee.intValue() / 100d : 0d;
|
||||
}
|
||||
|
||||
public CurrencyType getRefundFeeType() {
|
||||
return refundFeeType;
|
||||
}
|
||||
|
||||
public int getTotalFee() {
|
||||
return totalFee;
|
||||
}
|
||||
|
||||
/**
|
||||
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
|
||||
*
|
||||
* @return 元单位
|
||||
*/
|
||||
@JSONField(deserialize = false, serialize = false)
|
||||
public double getFormatTotalFee() {
|
||||
return totalFee / 100d;
|
||||
}
|
||||
|
||||
public int getCashFee() {
|
||||
return cashFee;
|
||||
}
|
||||
|
||||
/**
|
||||
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
|
||||
*
|
||||
* @return 元单位
|
||||
*/
|
||||
@JSONField(deserialize = false, serialize = false)
|
||||
public double getFormatCashFee() {
|
||||
return cashFee / 100d;
|
||||
}
|
||||
|
||||
public CurrencyType getCashFeeType() {
|
||||
return cashFeeType;
|
||||
}
|
||||
|
||||
public Integer getCashRefundFee() {
|
||||
return cashRefundFee;
|
||||
}
|
||||
|
||||
/**
|
||||
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
|
||||
*
|
||||
* @return 元单位
|
||||
*/
|
||||
@JSONField(deserialize = false, serialize = false)
|
||||
public double getFormatCashRefundFee() {
|
||||
return cashRefundFee != null ? cashRefundFee.intValue() / 100d : 0d;
|
||||
}
|
||||
|
||||
public CurrencyType getCashRefundFeeType() {
|
||||
return cashRefundFeeType;
|
||||
}
|
||||
|
||||
public Integer getCouponRefundCount() {
|
||||
return couponRefundCount;
|
||||
}
|
||||
|
||||
@JSONField(deserialize = false, serialize = false)
|
||||
public int getFormatCouponRefundCount() {
|
||||
return couponRefundCount != null ? couponRefundCount.intValue() : 0;
|
||||
}
|
||||
|
||||
public List<CouponInfo> getCouponList() {
|
||||
return couponList;
|
||||
}
|
||||
|
||||
public void setCouponList(List<CouponInfo> couponList) {
|
||||
this.couponList = couponList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RefundDetail [outRefundNo=" + outRefundNo + ", refundId="
|
||||
+ refundId + ", refundChannel=" + refundChannel
|
||||
+ ", refundFee=" + refundFee + ", refundStatus=" + refundStatus
|
||||
+ ", couponRefundFee=" + couponRefundFee
|
||||
+ ", getFormatRefundChannel()=" + getFormatRefundChannel()
|
||||
+ ", getFormatRefundStatus()=" + getFormatRefundStatus()
|
||||
+ ", getFormatCouponRefundFee()=" + getFormatCouponRefundFee();
|
||||
+ ", refundFee=" + getFormatRefundFee() + ", refundFeeType="
|
||||
+ refundFeeType + ", totalFee=" + getFormatTotalFee()
|
||||
+ ", feeType=" + feeType + ", cashFee=" + getFormatCashFee()
|
||||
+ ", cashFeeType=" + cashFeeType + ", cashRefundFee="
|
||||
+ getFormatCashRefundFee() + ", cashRefundFeeType="
|
||||
+ cashRefundFeeType + ", refundStatus=" + refundStatus
|
||||
+ ", couponRefundFee=" + getFormatCouponRefundFee()
|
||||
+ ", couponCount=" + getCouponRefundCount() + ", couponList="
|
||||
+ couponList + ", " + super.toString() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.foxinmy.weixin4j.mp.payment.v3;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.foxinmy.weixin4j.mp.type.CurrencyType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import com.thoughtworks.xstream.annotations.XStreamOmitField;
|
||||
|
||||
@ -26,9 +27,24 @@ public class RefundRecord extends ApiResult {
|
||||
@XStreamAlias("out_trade_no")
|
||||
@JSONField(name = "out_trade_no")
|
||||
private String outTradeNo;// 商户订单号
|
||||
@XStreamAlias("total_fee")
|
||||
@JSONField(name = "total_fee")
|
||||
private int totalFee; // 订单总金额
|
||||
@XStreamAlias("fee_type")
|
||||
@JSONField(name = "fee_type")
|
||||
private CurrencyType feeType; // 订单金额货币种类
|
||||
@XStreamAlias("cash_fee")
|
||||
@JSONField(name = "cash_fee")
|
||||
private int cashFee;
|
||||
private int cashFee; // 现金支付金额
|
||||
@XStreamAlias("cash_fee_type")
|
||||
@JSONField(name = "cash_fee_type")
|
||||
private CurrencyType cashFeeType; // 现金支付金额货币种类
|
||||
@XStreamAlias("refund_fee")
|
||||
@JSONField(name = "refund_fee")
|
||||
private int refundFee; // 退款总金额
|
||||
@XStreamAlias("coupon_refund_fee")
|
||||
@JSONField(name = "coupon_refund_fee")
|
||||
private Integer couponRefundFee; // 代金券或立减优惠退款金额=订单金额-现金退款金额,注意:满立减金额不会退回
|
||||
@XStreamAlias("refund_count")
|
||||
@JSONField(name = "refund_count")
|
||||
private int count;// 退款笔数
|
||||
@ -58,6 +74,42 @@ public class RefundRecord extends ApiResult {
|
||||
return cashFee;
|
||||
}
|
||||
|
||||
public CurrencyType getFeeType() {
|
||||
return feeType;
|
||||
}
|
||||
|
||||
public CurrencyType getCashFeeType() {
|
||||
return cashFeeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
|
||||
*
|
||||
* @return 元单位
|
||||
*/
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
public double getFormatCouponRefundFee() {
|
||||
return couponRefundFee != null ? couponRefundFee.intValue() / 100d : 0d;
|
||||
}
|
||||
|
||||
public Integer getCouponRefundFee() {
|
||||
return couponRefundFee;
|
||||
}
|
||||
|
||||
/**
|
||||
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
|
||||
*
|
||||
* @return 元单位
|
||||
*/
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
public double getFormatTotalFee() {
|
||||
return totalFee / 100d;
|
||||
}
|
||||
|
||||
public int getTotalFee() {
|
||||
return totalFee;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
@ -70,10 +122,28 @@ public class RefundRecord extends ApiResult {
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
public int getRefundFee() {
|
||||
return refundFee;
|
||||
}
|
||||
|
||||
/**
|
||||
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
|
||||
*
|
||||
* @return 元单位
|
||||
*/
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
public double getFormatRefundFee() {
|
||||
return refundFee / 100d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RefundRecord [transactionId=" + transactionId + ", outTradeNo="
|
||||
+ outTradeNo + ", cashFee=" + cashFee + ", count=" + count
|
||||
+ outTradeNo + ", totalFee=" + getFormatTotalFee()
|
||||
+ ", feeType=" + feeType + ", cashFee=" + getFormatCashFee()
|
||||
+ ", cashFeeType=" + cashFeeType + ", refundFee="
|
||||
+ getFormatRefundFee() + ", couponRefundFee="
|
||||
+ getFormatCouponRefundFee() + ", count=" + count
|
||||
+ ", details=" + details + ", " + super.toString() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,16 +31,16 @@ public class PayTest {
|
||||
private final static WeixinMpAccount ACCOUNT3;
|
||||
static {
|
||||
ACCOUNT2 = new WeixinMpAccount(
|
||||
"wxba294f2c6f330361",
|
||||
"8e33f5371a1afea1f7bce88088cb4bba",
|
||||
"gADrKITv3qYWu9JEg1NS0WPaU5yFgTwS9WfPueskfPpt3OZGpnUN1uBom36G2tP701vi2pPRJLZF9dEDFj9pqxidPn10Y91Lj8kK37Svz6S4MfeAHo9svFZmHkIKScGb",
|
||||
"1221928801", "8d1b26231827a965ef54fe6a3a151551");
|
||||
"请填入v2版本的appid",
|
||||
"请填入v2版本的appsecret",
|
||||
"请填入v2版本的paysignkey",
|
||||
"请填入v2版本的partnerId", "请填入v2版本的partnerKey");
|
||||
PAY2 = new WeixinPayProxy(ACCOUNT2, new FileTokenHolder(
|
||||
new WeixinTokenCreator(ACCOUNT2.getId(), ACCOUNT2.getSecret(),
|
||||
AccountType.MP)));
|
||||
ACCOUNT3 = new WeixinMpAccount("wx0d1d598c0c03c999",
|
||||
"2513ac683f1beabdb6b98d9ddd9e5755",
|
||||
"GATFzDwbQdbbci3QEQxX2rUBvwTrsMiZ", "10020674");
|
||||
ACCOUNT3 = new WeixinMpAccount("请填入v3版本的appid",
|
||||
"请填入v3版本的appSecret",
|
||||
"请填入v3版本的paysignkey", "请填入v3版本的mchid");
|
||||
PAY3 = new WeixinPayProxy(ACCOUNT3, new FileTokenHolder(
|
||||
new WeixinTokenCreator(ACCOUNT3.getId(), ACCOUNT3.getSecret(),
|
||||
AccountType.MP)));
|
||||
@ -54,10 +54,10 @@ public class PayTest {
|
||||
@Test
|
||||
public void refundV2() throws WeixinException {
|
||||
File caFile = new File(
|
||||
"/Users/jy/workspace/feican/canyi-weixin-parent/canyi-weixin-service/src/main/resources/1221928801.pfx");
|
||||
"签名文件,如12333.pfx");
|
||||
IdQuery idQuery = new IdQuery("D15020300005", IdType.TRADENO);
|
||||
System.err.println(PAY2.refundV2(caFile, idQuery, "1422925555037", 16d, 16d,
|
||||
"1221928801", "111111", null, null, null));
|
||||
System.err.println(PAY2.refundV2(caFile, idQuery, "1422925555037", 16d,
|
||||
16d, "1221928801", "111111", null, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -91,17 +91,25 @@ public class PayTest {
|
||||
|
||||
@Test
|
||||
public void refundQueryV3() throws WeixinException {
|
||||
System.err.println(PAY3.refundQueryV3(new IdQuery("T00015",
|
||||
IdType.TRADENO)));
|
||||
com.foxinmy.weixin4j.mp.payment.v3.RefundRecord record = PAY3.refundQueryV3(new IdQuery("TT_1427183696238",
|
||||
IdType.TRADENO));
|
||||
System.err.println(record);
|
||||
// 这里的验证签名需要把details循环拼接
|
||||
String sign = record.getSign();
|
||||
record.setSign(null);
|
||||
String valiSign = PayUtil.paysignMd5(record, ACCOUNT3.getPaySignKey());
|
||||
System.err
|
||||
.println(String.format("sign=%s,valiSign=%s", sign, valiSign));
|
||||
Assert.assertEquals(valiSign, sign);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void downbillV3() throws WeixinException {
|
||||
Calendar c = Calendar.getInstance();
|
||||
System.err.println(c.getTime());
|
||||
c.set(Calendar.YEAR, 2014);
|
||||
c.set(Calendar.MONTH, 9);
|
||||
c.set(Calendar.DAY_OF_MONTH, 22);
|
||||
c.set(Calendar.YEAR, 2015);
|
||||
c.set(Calendar.MONTH, 2);
|
||||
c.set(Calendar.DAY_OF_MONTH, 24);
|
||||
System.err.println(c.getTime());
|
||||
File file = PAY3.downloadbill(c.getTime(), null);
|
||||
System.err.println(file);
|
||||
@ -110,10 +118,11 @@ public class PayTest {
|
||||
@Test
|
||||
public void refundV3() throws WeixinException {
|
||||
File caFile = new File(
|
||||
"/Users/jy/workspace/feican/canyi-weixin-parent/canyi-weixin-service/src/main/resources/10020674.p12");
|
||||
IdQuery idQuery = new IdQuery("T00015", IdType.TRADENO);
|
||||
"签名文件如123.p12");
|
||||
IdQuery idQuery = new IdQuery("TT_1427183696238", IdType.TRADENO);
|
||||
com.foxinmy.weixin4j.mp.payment.v3.RefundResult result = PAY3.refundV3(
|
||||
caFile, idQuery, "R0002", 1d, 1d, "10020674");
|
||||
caFile, idQuery, "TT_R" + System.currentTimeMillis(), 0.01d, 0.01d,
|
||||
null, "10020674");
|
||||
System.err.println(result);
|
||||
String sign = result.getSign();
|
||||
result.setSign(null);
|
||||
|
||||
@ -68,3 +68,7 @@ weixin4j-mp-server
|
||||
* 2014-11-23
|
||||
|
||||
+ `WeixinServerBootstrap`重命名为`WeixinMpServerBootstrap`
|
||||
|
||||
* 2015-03-25
|
||||
|
||||
+ 新增客服创建、关闭、转接会话事件
|
||||
@ -5,6 +5,8 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -16,6 +18,7 @@ import com.foxinmy.weixin4j.model.WeixinMpAccount;
|
||||
import com.foxinmy.weixin4j.mp.payment.JsPayNotify;
|
||||
import com.foxinmy.weixin4j.mp.payment.PayPackage;
|
||||
import com.foxinmy.weixin4j.mp.payment.PayUtil;
|
||||
import com.foxinmy.weixin4j.mp.payment.conver.CouponConverter;
|
||||
import com.foxinmy.weixin4j.mp.payment.v2.NativePayNotifyV2;
|
||||
import com.foxinmy.weixin4j.mp.payment.v2.NativePayResponseV2;
|
||||
import com.foxinmy.weixin4j.mp.payment.v2.PayFeedback;
|
||||
@ -149,16 +152,22 @@ public class PayAction {
|
||||
* <return_code>SUCCESS/FAIL</return_code><br>
|
||||
* <return_msg>如非空,为错误 原因签名失败参数格式校验错误</return_msg><br>
|
||||
* </xml>
|
||||
* @throws DocumentException
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7">支付结果通知</a>
|
||||
*/
|
||||
public String jsNotifyV3(InputStream inputStream) {
|
||||
com.foxinmy.weixin4j.mp.payment.v3.Order order = XmlStream.get(
|
||||
inputStream, com.foxinmy.weixin4j.mp.payment.v3.Order.class);
|
||||
public String jsNotifyV3(InputStream inputStream) throws DocumentException {
|
||||
SAXReader sax = new SAXReader();
|
||||
String orderXml = sax.read(inputStream).asXML();
|
||||
com.foxinmy.weixin4j.mp.payment.v3.Order order = CouponConverter
|
||||
.fromXML(orderXml, com.foxinmy.weixin4j.mp.payment.v3.Order.class);
|
||||
log.info("jsapi_notify_order_info:", order);
|
||||
String sign = order.getSign();
|
||||
order.setSign(null);
|
||||
WeixinMpAccount weixinAccount = ConfigUtil.getWeixinMpAccount();
|
||||
String valid_sign = PayUtil.paysignMd5(order,
|
||||
weixinAccount.getPaySignKey());
|
||||
// 如果订单中存在代金券的情况并不适用
|
||||
log.info("微信签名----->sign={},vaild_sign={}", sign, valid_sign);
|
||||
if (!sign.equals(valid_sign)) {
|
||||
return XmlStream.to(new XmlResult(Consts.FAIL, "签名错误"));
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
package com.foxinmy.weixin4j.mp.action.event;
|
||||
|
||||
import com.foxinmy.weixin4j.action.DebugAction;
|
||||
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
|
||||
import com.foxinmy.weixin4j.msg.event.KfCloseEventMessage;
|
||||
import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
|
||||
/**
|
||||
* 客服关闭会话消息
|
||||
*
|
||||
* @className KfCloseAction
|
||||
* @author jy
|
||||
* @date 2015年3月25日
|
||||
* @since JDK 1.7
|
||||
* @see com.foxinmy.weixin4j.msg.event.KfCloseEventMessage
|
||||
*/
|
||||
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.kf_close_session })
|
||||
public class KfCloseAction extends DebugAction<KfCloseEventMessage> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.foxinmy.weixin4j.mp.action.event;
|
||||
|
||||
import com.foxinmy.weixin4j.action.DebugAction;
|
||||
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
|
||||
import com.foxinmy.weixin4j.msg.event.KfCreateEventMessage;
|
||||
import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
|
||||
/**
|
||||
* 客服接入会话消息
|
||||
*
|
||||
* @className KfCreateAction
|
||||
* @author jy
|
||||
* @date 2015年3月25日
|
||||
* @since JDK 1.7
|
||||
* @see com.foxinmy.weixin4j.msg.event.KfCreateEventMessage
|
||||
*/
|
||||
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.kf_create_session })
|
||||
public class KfCreateAction extends DebugAction<KfCreateEventMessage> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.foxinmy.weixin4j.mp.action.event;
|
||||
|
||||
import com.foxinmy.weixin4j.action.DebugAction;
|
||||
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
|
||||
import com.foxinmy.weixin4j.msg.event.KfSwitchEventMessage;
|
||||
import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
|
||||
/**
|
||||
* 客服转接会话消息
|
||||
*
|
||||
* @className KfSwitchAction
|
||||
* @author jy
|
||||
* @date 2015年3月25日
|
||||
* @since JDK 1.7
|
||||
* @see com.foxinmy.weixin4j.msg.event.KfSwitchEventMessage
|
||||
*/
|
||||
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.kf_switch_session })
|
||||
public class KfSwitchAction extends DebugAction<KfSwitchEventMessage> {
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user