新增退款接口

This commit is contained in:
jy.hu
2014-11-06 20:46:35 +08:00
parent f489667109
commit 26d04798c5
34 changed files with 752 additions and 502 deletions
+6 -2
View File
@@ -48,10 +48,14 @@ weixin4j
+ 优化了代码 + 优化了代码
* 2014-11-06
+ **weixin-base**: 删除`WeixinConfig`类只保留`WeixinAccount`
+ **weixin-mp**: 新增`退款接口`
接下来 接下来
------ ------
* 公众号退款接口
* 公众号智能接口 * 公众号智能接口
* 微信消息加密 * 微信消息加密
+4
View File
@@ -18,3 +18,7 @@ weixin4j-base
+ `TokenApi`重命名为`TokenHolder` + `TokenApi`重命名为`TokenHolder`
+ 新增`WeixinConfig`等类 + 新增`WeixinConfig`等类
* 2014-11-06
+ 删除`WeixinConfig`类只保留`WeixinAccount`
@@ -47,7 +47,7 @@ import com.foxinmy.weixin4j.exception.WeixinException;
*/ */
public class HttpRequest { public class HttpRequest {
private final String SUCCESS = "success"; private final String SUCCESS = "success";
private AbstractHttpClient client; protected AbstractHttpClient client;
public HttpRequest() { public HttpRequest() {
this(150, 100, 10000, 10000); this(150, 100, 10000, 10000);
@@ -155,16 +155,16 @@ public class HttpRequest {
HttpResponse httpResponse = client.execute(request); HttpResponse httpResponse = client.execute(request);
StatusLine statusLine = httpResponse.getStatusLine(); StatusLine statusLine = httpResponse.getStatusLine();
HttpEntity httpEntity = httpResponse.getEntity(); HttpEntity httpEntity = httpResponse.getEntity();
int status = statusLine.getStatusCode(); int status = statusLine.getStatusCode();
if (status != HttpStatus.SC_OK) { if (status != HttpStatus.SC_OK) {
throw new WeixinException(status + "", "request fail"); throw new WeixinException(Integer.toString(status),
"request fail");
} }
// 301或者302 // 301或者302
if (status == HttpStatus.SC_MOVED_PERMANENTLY if (status == HttpStatus.SC_MOVED_PERMANENTLY
|| status == HttpStatus.SC_MOVED_TEMPORARILY) { || status == HttpStatus.SC_MOVED_TEMPORARILY) {
throw new WeixinException(status + "", String.format( throw new WeixinException(Integer.toString(status),
"the page was redirected to %s", String.format("the page was redirected to %s",
httpResponse.getFirstHeader("location"))); httpResponse.getFirstHeader("location")));
} }
byte[] data = EntityUtils.toByteArray(httpEntity); byte[] data = EntityUtils.toByteArray(httpEntity);
@@ -186,8 +186,8 @@ public class HttpRequest {
JsonResult jsonResult = response.getAsJsonResult(); JsonResult jsonResult = response.getAsJsonResult();
response.setJsonResult(true); response.setJsonResult(true);
if (jsonResult.getCode() != 0) { if (jsonResult.getCode() != 0) {
throw new WeixinException(jsonResult.getCode() + "", throw new WeixinException(Integer.toString(jsonResult
jsonResult.getDesc()); .getCode()), jsonResult.getDesc());
} }
return response; return response;
} catch (JSONException e) { } catch (JSONException e) {
@@ -205,7 +205,7 @@ public class HttpRequest {
} }
} }
} catch (IOException e) { } catch (IOException e) {
throw new WeixinException(e.getMessage()); throw new WeixinException("-1", e.getMessage());
} finally { } finally {
request.releaseConnection(); request.releaseConnection();
} }
@@ -0,0 +1,48 @@
package com.foxinmy.weixin4j.http;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
/**
* ssl请求
*
* @className SSLHttpRequest
* @author jy
* @date 2014年11月6日
* @since JDK 1.7
* @see
*/
public class SSLHttpRequest extends HttpRequest {
public SSLHttpRequest(String password, File file) throws IOException {
this(password, new FileInputStream(file));
}
public SSLHttpRequest(String password, InputStream inputStream) {
super();
try {
KeyStore trustStore = KeyStore.getInstance("PKCS12");
trustStore.load(inputStream, password.toCharArray());
SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore,
password);
client.getConnectionManager().getSchemeRegistry()
.register(new Scheme("https", 443, socketFactory));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Exception ignore) {
;
}
}
}
}
@@ -24,7 +24,6 @@ public class Token implements Serializable {
private String accessToken; private String accessToken;
@JSONField(name = "expires_in") @JSONField(name = "expires_in")
private int expiresIn; private int expiresIn;
private String openid;
private long time; private long time;
public String getAccessToken() { public String getAccessToken() {
@@ -43,14 +42,6 @@ public class Token implements Serializable {
this.expiresIn = expiresIn; this.expiresIn = expiresIn;
} }
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public long getTime() { public long getTime() {
return time; return time;
} }
@@ -69,6 +60,7 @@ public class Token implements Serializable {
@Override @Override
public String toString() { public String toString() {
return "Token [accessToken=" + accessToken + ", expiresIn=" + expiresIn + ", openid=" + openid + ", time=" + time + "]"; return "Token [accessToken=" + accessToken + ", expiresIn=" + expiresIn
+ ", time=" + time + "]";
} }
} }
@@ -1,5 +1,7 @@
package com.foxinmy.weixin4j.model; package com.foxinmy.weixin4j.model;
import java.io.Serializable;
/** /**
* 微信账户信息 * 微信账户信息
* *
@@ -9,9 +11,16 @@ package com.foxinmy.weixin4j.model;
* @since JDK 1.7 * @since JDK 1.7
* @see * @see
*/ */
public class WeixinAccount extends WeixinConfig { public class WeixinAccount implements Serializable {
private static final long serialVersionUID = 3689999353867189585L; private static final long serialVersionUID = 3689999353867189585L;
private String token;
// 支付场景下为用户的openid 其余情况可能是公众号的原始ID
private String openId;
// 公众号身份的唯一标识
private String appId;
// 公众平台接口 API 的权限获取所需密钥 Key
private String appSecret;
// 公众号支付请求中用于加密的密钥 Key,可验证商户唯一身份,PaySignKey 对应于支付场景中的 appKey 值 // 公众号支付请求中用于加密的密钥 Key,可验证商户唯一身份,PaySignKey 对应于支付场景中的 appKey 值
private String paySignKey; private String paySignKey;
// 财付通商户身份的标识 // 财付通商户身份的标识
@@ -30,6 +39,38 @@ public class WeixinAccount extends WeixinConfig {
// 是否是订阅号 // 是否是订阅号
private boolean isSubscribe; private boolean isSubscribe;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
public String getPaySignKey() { public String getPaySignKey() {
return paySignKey; return paySignKey;
} }
@@ -98,19 +139,51 @@ public class WeixinAccount extends WeixinConfig {
} }
public WeixinAccount(String appId, String appSecret) {
this.appId = appId;
this.appSecret = appSecret;
}
/**
* V3版本字段
*
* @param appId
* @param appSecret
* @param paySignKey
* @param mchId
*/
public WeixinAccount(String appId, String appSecret, String paySignKey, public WeixinAccount(String appId, String appSecret, String paySignKey,
String mchId) { String mchId) {
super(appId, appSecret); this(appId, appSecret);
this.paySignKey = paySignKey; this.paySignKey = paySignKey;
this.mchId = mchId; this.mchId = mchId;
} }
/**
* V2版本字段
*
* @param appId
* @param appSecret
* @param paySignKey
* @param partnerId
* @param partnerKey
*/
public WeixinAccount(String appId, String appSecret, String paySignKey, public WeixinAccount(String appId, String appSecret, String paySignKey,
String partnerId, String partnerKey) { String partnerId, String partnerKey) {
super(appId, appSecret); this(appId, appSecret);
this.paySignKey = paySignKey; this.paySignKey = paySignKey;
this.partnerId = partnerId; this.partnerId = partnerId;
this.partnerKey = partnerKey; this.partnerKey = partnerKey;
} }
@Override
public String toString() {
return "WeixinAccount [token=" + token + ", openId=" + openId
+ ", appId=" + appId + ", appSecret=" + appSecret
+ ", paySignKey=" + paySignKey + ", partnerId=" + partnerId
+ ", partnerKey=" + partnerKey + ", mchId=" + mchId
+ ", deviceInfo=" + deviceInfo + ", isAlive=" + isAlive
+ ", isService=" + isService + ", isSubscribe=" + isSubscribe
+ "]";
}
} }
@@ -1,64 +0,0 @@
package com.foxinmy.weixin4j.model;
import java.io.Serializable;
public class WeixinConfig implements Serializable {
private static final long serialVersionUID = -3454743453282851243L;
private String token;
// 支付场景下为用户的openid 其余情况可能是公众号的原始ID
private String openId;
// 公众号身份的唯一标识
private String appId;
// 除了支付请求需要用到 paySignKey,公众平台接口 API 的权限获取所需密 钥 Key
private String appSecret;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
public WeixinConfig() {
}
public WeixinConfig(String appId, String appSecret) {
this.appId = appId;
this.appSecret = appSecret;
}
@Override
public String toString() {
return "WeixinConfig [token=" + token + ", openId=" + openId
+ ", appId=" + appId + ", appSecret=" + appSecret + "]";
}
}
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.token; package com.foxinmy.weixin4j.token;
import com.foxinmy.weixin4j.http.HttpRequest; import com.foxinmy.weixin4j.http.HttpRequest;
import com.foxinmy.weixin4j.model.WeixinConfig; import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
/** /**
@@ -16,17 +16,17 @@ import com.foxinmy.weixin4j.util.ConfigUtil;
public abstract class AbstractTokenHolder implements TokenHolder { public abstract class AbstractTokenHolder implements TokenHolder {
protected final String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; protected final String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
protected final HttpRequest request = new HttpRequest(); protected final HttpRequest request = new HttpRequest();
private final WeixinConfig weixinConfig; private final WeixinAccount weixinAccount;
public AbstractTokenHolder() { public AbstractTokenHolder() {
this.weixinConfig = ConfigUtil.getWeixinConfig(); this.weixinAccount = ConfigUtil.getWeixinAccount();
} }
public AbstractTokenHolder(String appid, String appsecret) { public AbstractTokenHolder(WeixinAccount weixinAccount) {
this.weixinConfig = new WeixinConfig(appid, appsecret); this.weixinAccount = weixinAccount;
} }
public WeixinConfig getConfig() { public WeixinAccount getAccount() {
return this.weixinConfig; return weixinAccount;
} }
} }
@@ -12,6 +12,7 @@ import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.xml.XStream; import com.foxinmy.weixin4j.xml.XStream;
@@ -32,8 +33,12 @@ public class FileTokenHolder extends AbstractTokenHolder {
super(); super();
} }
public FileTokenHolder(WeixinAccount weixinAccount) {
super(weixinAccount);
}
public FileTokenHolder(String appid, String appsecret) { public FileTokenHolder(String appid, String appsecret) {
super(appid, appsecret); this(new WeixinAccount(appid, appsecret));
} }
/** /**
@@ -50,8 +55,8 @@ public class FileTokenHolder extends AbstractTokenHolder {
*/ */
@Override @Override
public Token getToken() throws WeixinException { public Token getToken() throws WeixinException {
String appid = getConfig().getAppId(); String appid = getAccount().getAppId();
String appsecret = getConfig().getAppSecret(); String appsecret = getAccount().getAppSecret();
if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) { if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"appid or appsecret not be null!"); "appid or appsecret not be null!");
@@ -65,7 +70,6 @@ public class FileTokenHolder extends AbstractTokenHolder {
if (token_file.exists()) { if (token_file.exists()) {
token = XStream.get(new FileInputStream(token_file), token = XStream.get(new FileInputStream(token_file),
Token.class); Token.class);
long expise_time = token.getTime() long expise_time = token.getTime()
+ (token.getExpiresIn() * 1000) - 3; + (token.getExpiresIn() * 1000) - 3;
if (expise_time > now_time) { if (expise_time > now_time) {
@@ -79,7 +83,6 @@ public class FileTokenHolder extends AbstractTokenHolder {
token = response.getAsObject(new TypeReference<Token>() { token = response.getAsObject(new TypeReference<Token>() {
}); });
token.setTime(now_time); token.setTime(now_time);
token.setOpenid(appid);
XStream.to(token, new FileOutputStream(token_file)); XStream.to(token, new FileOutputStream(token_file));
} catch (IOException e) { } catch (IOException e) {
throw new WeixinException("-1", "IO ERROR"); throw new WeixinException("-1", "IO ERROR");
@@ -10,6 +10,7 @@ import redis.clients.jedis.exceptions.JedisException;
import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinAccount;
/** /**
* 基于redis保存的Token获取类 * 基于redis保存的Token获取类
@@ -26,17 +27,7 @@ public class RedisTokenHolder extends AbstractTokenHolder {
private JedisPool jedisPool; private JedisPool jedisPool;
public RedisTokenHolder() { private void createPool(String host, int port) {
super();
}
public RedisTokenHolder(String appid, String appsecret) {
this(appid, appsecret, "localhost", 6379);
}
public RedisTokenHolder(String appid, String appsecret, String host,
int port) {
super(appid, appsecret);
JedisPoolConfig poolConfig = new JedisPoolConfig(); JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(50); poolConfig.setMaxTotal(50);
poolConfig.setMaxIdle(5); poolConfig.setMaxIdle(5);
@@ -46,10 +37,33 @@ public class RedisTokenHolder extends AbstractTokenHolder {
this.jedisPool = new JedisPool(poolConfig, host, port); this.jedisPool = new JedisPool(poolConfig, host, port);
} }
public RedisTokenHolder() {
this("localhost", 6379);
}
public RedisTokenHolder(String host, int port) {
super();
createPool(host, port);
}
public RedisTokenHolder(WeixinAccount weixinAccount) {
this(weixinAccount, "localhost", 6379);
}
public RedisTokenHolder(String appId, String appSecret, String host,
int port) {
this(new WeixinAccount(appId, appSecret), host, port);
}
public RedisTokenHolder(WeixinAccount weixinAccount, String host, int port) {
super(weixinAccount);
createPool(host, port);
}
@Override @Override
public Token getToken() throws WeixinException { public Token getToken() throws WeixinException {
String appid = getConfig().getAppId(); String appid = getAccount().getAppId();
String appsecret = getConfig().getAppSecret(); String appsecret = getAccount().getAppSecret();
if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) { if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"appid or appsecret not be null!"); "appid or appsecret not be null!");
@@ -68,13 +82,12 @@ public class RedisTokenHolder extends AbstractTokenHolder {
}); });
jedis.setex(key, token.getExpiresIn() - 3, jedis.setex(key, token.getExpiresIn() - 3,
token.getAccessToken()); token.getAccessToken());
token.setTime(System.currentTimeMillis());
} else { } else {
token = new Token(); token = new Token();
token.setAccessToken(accessToken); token.setAccessToken(accessToken);
token.setExpiresIn(jedis.ttl(key).intValue()); token.setExpiresIn(jedis.ttl(key).intValue());
} }
token.setTime(System.currentTimeMillis());
token.setOpenid(appid);
} catch (JedisException e) { } catch (JedisException e) {
jedisPool.returnBrokenResource(jedis); jedisPool.returnBrokenResource(jedis);
} finally { } finally {
@@ -2,7 +2,7 @@ package com.foxinmy.weixin4j.token;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinConfig; import com.foxinmy.weixin4j.model.WeixinAccount;
/** /**
* 获取Token接口 * 获取Token接口
@@ -17,7 +17,7 @@ import com.foxinmy.weixin4j.model.WeixinConfig;
* @see com.foxinmy.weixin4j.token.RedisTokenHolder * @see com.foxinmy.weixin4j.token.RedisTokenHolder
*/ */
public interface TokenHolder { public interface TokenHolder {
public WeixinConfig getConfig(); public WeixinAccount getAccount();
public Token getToken() throws WeixinException; public Token getToken() throws WeixinException;
} }
@@ -6,7 +6,6 @@ import java.util.Set;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinConfig;
/** /**
* 商户配置工具类 * 商户配置工具类
@@ -38,9 +37,4 @@ public class ConfigUtil {
String text = getValue("account"); String text = getValue("account");
return JSON.parseObject(text, WeixinAccount.class); return JSON.parseObject(text, WeixinAccount.class);
} }
public static WeixinConfig getWeixinConfig() {
String text = getValue("account");
return JSON.parseObject(text, WeixinConfig.class);
}
} }
@@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.util; package com.foxinmy.weixin4j.util;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
@@ -25,7 +26,16 @@ public class DateUtil {
return new SimpleDateFormat(yyyyMMddHHmmss).format(date); return new SimpleDateFormat(yyyyMMddHHmmss).format(date);
} }
public static String format2fee(double fee) { public static Date parse2yyyyMMddHHmmss(String date) {
try {
return new SimpleDateFormat(yyyyMMddHHmmss).parse(date);
} catch (ParseException e) {
;
}
return null;
}
public static String formaFee2Fen(double fee) {
return new DecimalFormat("#").format(fee * 100); return new DecimalFormat("#").format(fee * 100);
} }
} }
+6 -2
View File
@@ -28,7 +28,7 @@ weixin4j-mp
* **weixin4j-mp-server** * **weixin4j-mp-server**
`netty服务器 & 消息分发` `netty服务器` & `消息分发`
更新LOG 更新LOG
------- -------
@@ -48,4 +48,8 @@ weixin4j-mp
+ `weixin-mp`分离为`weixin-mp-api``weixin-mp-server`两个工程 + `weixin-mp`分离为`weixin-mp-api``weixin-mp-server`两个工程
+ **weixin-mp**: 加入`支付`模块 + **weixin-mp**: 新增`支付`模块
* 2014-11-06
+ **weixin-mp**: 新增`退款接口`
+6 -2
View File
@@ -41,7 +41,7 @@ weixin.properties说明
| media_path | 调用媒体接口时保存媒体文件的物理路径 | | media_path | 调用媒体接口时保存媒体文件的物理路径 |
| bill_path | 调用支付(`V3`)下载对账单接口保存excel文件的物理路径 | | bill_path | 调用支付(`V3`)下载对账单接口保存excel文件的物理路径 |
示例(properties中换行用右斜杆\) 示例(properties中换行用右斜杆\\)
> account={"appId":"appId","appSecret":"appSecret", > account={"appId":"appId","appSecret":"appSecret",
> "token":"开放者的token 非必须","openId":"公众号的openid 非必须", > "token":"开放者的token 非必须","openId":"公众号的openid 非必须",
@@ -84,4 +84,8 @@ weixin.properties说明
+ 分离为`weixin-mp-api``weixin-mp-server`两个工程 + 分离为`weixin-mp-api``weixin-mp-server`两个工程
+ 加入`支付模块` + 新增`支付模块`
* 2014-11-06
+ 新增`退款申请`接口
@@ -2,6 +2,7 @@ package com.foxinmy.weixin4j.mp;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -25,18 +26,18 @@ import com.foxinmy.weixin4j.mp.model.CustomRecord;
import com.foxinmy.weixin4j.mp.model.Following; import com.foxinmy.weixin4j.mp.model.Following;
import com.foxinmy.weixin4j.mp.model.Group; import com.foxinmy.weixin4j.mp.model.Group;
import com.foxinmy.weixin4j.mp.model.MpArticle; import com.foxinmy.weixin4j.mp.model.MpArticle;
import com.foxinmy.weixin4j.mp.model.OauthToken;
import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.QRParameter;
import com.foxinmy.weixin4j.mp.model.User; import com.foxinmy.weixin4j.mp.model.User;
import com.foxinmy.weixin4j.mp.model.OauthToken;
import com.foxinmy.weixin4j.mp.msg.model.Article; import com.foxinmy.weixin4j.mp.msg.model.Article;
import com.foxinmy.weixin4j.mp.msg.model.BaseMsg; import com.foxinmy.weixin4j.mp.msg.model.BaseMsg;
import com.foxinmy.weixin4j.mp.msg.notify.BaseNotify; import com.foxinmy.weixin4j.mp.msg.notify.BaseNotify;
import com.foxinmy.weixin4j.mp.payment.v2.Order; import com.foxinmy.weixin4j.mp.payment.v2.Order;
import com.foxinmy.weixin4j.mp.payment.v3.Refund; import com.foxinmy.weixin4j.mp.payment.v3.Refund;
import com.foxinmy.weixin4j.mp.payment.v3.RefundResult;
import com.foxinmy.weixin4j.mp.response.TemplateMessage; import com.foxinmy.weixin4j.mp.response.TemplateMessage;
import com.foxinmy.weixin4j.mp.type.BillType; import com.foxinmy.weixin4j.mp.type.BillType;
import com.foxinmy.weixin4j.mp.type.IdQuery; import com.foxinmy.weixin4j.mp.type.IdQuery;
import com.foxinmy.weixin4j.mp.type.IdType;
import com.foxinmy.weixin4j.token.FileTokenHolder; import com.foxinmy.weixin4j.token.FileTokenHolder;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.type.MediaType;
@@ -397,7 +398,6 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.api.MassApi * @see com.foxinmy.weixin4j.mp.api.MassApi
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByGroup(JSONObject, String)} * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByGroup(JSONObject, String)}
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByOpenIds(JSONObject, String...) * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByOpenIds(JSONObject, String...)
*/ */
public JsonResult deleteMassNews(String msgid) throws WeixinException { public JsonResult deleteMassNews(String msgid) throws WeixinException {
@@ -720,8 +720,6 @@ public class WeixinProxy {
/** /**
* 发货通知 * 发货通知
* @param weixinAccount
* 商户信息
* *
* @param openId * @param openId
* 用户ID * 用户ID
@@ -736,28 +734,25 @@ public class WeixinProxy {
* @return 调用结果 * @return 调用结果
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
public JsonResult deliverNotify(WeixinAccount weixinAccount, String openId, */
String transid, String orderNo, boolean status, String statusMsg) public JsonResult deliverNotify(String openId, String transid,
String outTradeNo, boolean status, String statusMsg) String outTradeNo, boolean status, String statusMsg)
return payApi.deliverNotify(weixinAccount, openId, transid, orderNo, throws WeixinException {
status, statusMsg); return payApi.deliverNotify(openId, transid, outTradeNo, status,
statusMsg); statusMsg);
} }
/** /**
* 订单查询 * 订单查询
* @param weixinAccount *
* 商户信息
* @param orderNo
* @param outTradeNo * @param outTradeNo
* 订单号 * 订单号
* @return 订单信息 * @return 订单信息
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
public Order orderQueryV2(WeixinAccount weixinAccount, String orderNo) */
public Order orderQueryV2(WeixinAccount weixinAccount, String outTradeNo) public Order orderQueryV2(WeixinAccount weixinAccount, String outTradeNo)
return payApi.orderQueryV2(weixinAccount, new IdQuery(orderNo, throws WeixinException {
IdType.ORDERNO));
return payApi.orderQueryV2(outTradeNo); return payApi.orderQueryV2(outTradeNo);
} }
@@ -779,18 +774,15 @@ public class WeixinProxy {
/** /**
* V3订单查询 * V3订单查询
* @param weixinAccount
* 商户信息
* *
* @param idQuery * @param idQuery
* 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级: * 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级:
* transaction_id> out_trade_no * transaction_id> out_trade_no
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException * @throws WeixinException
public com.foxinmy.weixin4j.mp.payment.v3.Order orderQueryV3( */
WeixinAccount weixinAccount, IdQuery idQuery)
public com.foxinmy.weixin4j.mp.payment.v3.Order orderQueryV3(IdQuery idQuery) public com.foxinmy.weixin4j.mp.payment.v3.Order orderQueryV3(IdQuery idQuery)
return payApi.orderQueryV3(weixinAccount, idQuery); throws WeixinException {
return payApi.orderQueryV3(idQuery); return payApi.orderQueryV3(idQuery);
} }
@@ -800,8 +792,6 @@ public class WeixinProxy {
* REVOKED;<br> * REVOKED;<br>
* 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;<br> * 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;<br>
* 3.对账单中涉及金额的字段单位为“元”。<br> * 3.对账单中涉及金额的字段单位为“元”。<br>
* @param weixinAccount
* 商户配置
* *
* @param billDate * @param billDate
* 下载对账单的日期 * 下载对账单的日期
@@ -812,16 +802,60 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException * @throws WeixinException
* @throws IOException * @throws IOException
public File downloadbill(WeixinAccount weixinAccount, Date billDate, */
BillType billType) throws WeixinException, IOException { public File downloadbill(Date billDate, BillType billType)
return payApi.downloadbill(weixinAccount, billDate, billType); throws WeixinException, IOException {
return payApi.downloadbill(billDate, billType);
}
/**
* 申请退款(请求需要双向证书)<br/>
* <p style="color:red">
* 交易时间超过 1 年的订单无法提交退款; <br/>
* 支持部分退款,部分退需要设置相同的订单号和不同的 out_refund_no。一笔退款失 败后重新提交,要采用原来的
* out_refund_no。总退款金额不能超过用户实际支付金额。<br/>
* </p>
*
* @param ca
* 证书文件
* @param idQuery
* ) 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级:
* transaction_id> out_trade_no
* @param outRefundNo
* 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔
* @param totalFee
* 订单总金额,单位为元
* @param refundFee
* 退款总金额,单位为元,可以做部分退款
* @param opUserId
* 操作员帐号, 默认为商户号
* @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException
* @throws IOException
* @return 退款结果
*/
public RefundResult refund(InputStream ca, IdQuery idQuery,
String outRefundNo, double totalFee, double refundFee,
String opUserId) throws WeixinException, IOException {
return payApi.refund(idQuery, outRefundNo, totalFee, refundFee,
opUserId);
}
/**
* 使用properties中配置的ca文件
*
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#refund(InputStream, IdQuery, String, double, double, String)}
*/
public RefundResult refund(IdQuery idQuery, String outRefundNo,
double totalFee, double refundFee, String opUserId)
throws WeixinException, IOException {
return payApi.refund(idQuery, outRefundNo, totalFee, refundFee,
opUserId); opUserId);
} }
/** /**
* 退款查询<br/> * 退款查询<br/>
* 退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款 3 个工作日后重新查询退款状态 * 退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款 3 个工作日后重新查询退款状态
* @param weixinAccount
* *
* @param idQuery * @param idQuery
* 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id * 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id
@@ -830,9 +864,8 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
* @return 退款记录 * @return 退款记录
* @throws WeixinException * @throws WeixinException
public Refund refundQuery(WeixinAccount weixinAccount, IdQuery idQuery) */
throws WeixinException { public Refund refundQuery(IdQuery idQuery) throws WeixinException {
return payApi.refundQuery(weixinAccount, idQuery);
return payApi.refundQuery(idQuery); return payApi.refundQuery(idQuery);
} }
@@ -840,33 +873,26 @@ public class WeixinProxy {
* 关闭订单<br/> * 关闭订单<br/>
* 当订单支付失败,调用关单接口后用新订单号重新发起支付,如果关单失败,返回已完 * 当订单支付失败,调用关单接口后用新订单号重新发起支付,如果关单失败,返回已完
* 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。 * 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。
* @param weixinAccount *
* 商户信息
* @param order
* @param outTradeNo * @param outTradeNo
* 商户系统内部的订单号 * 商户系统内部的订单号
* @return 执行结果 * @return 执行结果
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException * @throws WeixinException
public XmlResult closeOrder(WeixinAccount weixinAccount, String orderNo) */
throws WeixinException { public XmlResult closeOrder(String outTradeNo) throws WeixinException {
return payApi.orderQueryV3(weixinAccount, new IdQuery(orderNo,
IdType.ORDERNO));
return payApi.closeOrder(outTradeNo); return payApi.closeOrder(outTradeNo);
} }
/** /**
* native支付URL转短链接 * native支付URL转短链接
* @param weixinAccount
* 商户信息
* *
* @param url * @param url
* 具有native标识的支付URL * 具有native标识的支付URL
* @return 转换后的短链接 * @return 转换后的短链接
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException * @throws WeixinException
public String getPayShorturl(WeixinAccount weixinAccount, String url) */
throws WeixinException { public String getPayShorturl(String url) throws WeixinException {
return payApi.getShorturl(weixinAccount, url);
return payApi.getShorturl(url); return payApi.getShorturl(url);
} }
@@ -2,8 +2,10 @@ package com.foxinmy.weixin4j.mp.api;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader; import java.io.StringReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
@@ -16,6 +18,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@@ -25,6 +28,7 @@ import com.alibaba.fastjson.parser.Feature;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.http.SSLHttpRequest;
import com.foxinmy.weixin4j.http.XmlResult; import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.WeixinAccount;
@@ -32,8 +36,10 @@ import com.foxinmy.weixin4j.mp.payment.PayUtil;
import com.foxinmy.weixin4j.mp.payment.v2.Order; import com.foxinmy.weixin4j.mp.payment.v2.Order;
import com.foxinmy.weixin4j.mp.payment.v3.Refund; import com.foxinmy.weixin4j.mp.payment.v3.Refund;
import com.foxinmy.weixin4j.mp.payment.v3.RefundConverter; import com.foxinmy.weixin4j.mp.payment.v3.RefundConverter;
import com.foxinmy.weixin4j.mp.payment.v3.RefundResult;
import com.foxinmy.weixin4j.mp.type.BillType; import com.foxinmy.weixin4j.mp.type.BillType;
import com.foxinmy.weixin4j.mp.type.IdQuery; import com.foxinmy.weixin4j.mp.type.IdQuery;
import com.foxinmy.weixin4j.mp.type.IdType;
import com.foxinmy.weixin4j.mp.util.ExcelUtil; import com.foxinmy.weixin4j.mp.util.ExcelUtil;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
@@ -60,24 +66,23 @@ public class PayApi extends BaseApi {
/** /**
* 发货通知 * 发货通知
* *
* @param weixinAccount
* 商户信息
* @param openId * @param openId
* 用户ID * 用户ID
* @param transid * @param transid
* 交易单号 * 交易单号
* @param orderNo * @param outTradeNo
* 订单号 * 订单号
* @param status * @param status
* 成功|失败 * 成功|失败
* @param statusMsg * @param statusMsg
* status为失败时携带的信息 * status为失败时携带的信息
* @return * @return 发货处理结果
* @throws WeixinException * @throws WeixinException
*/ */
public JsonResult deliverNotify(WeixinAccount weixinAccount, String openId, public JsonResult deliverNotify(String openId, String transid,
String transid, String orderNo, boolean status, String statusMsg) String outTradeNo, boolean status, String statusMsg)
throws WeixinException { throws WeixinException {
WeixinAccount weixinAccount = tokenHolder.getAccount();
String delivernotify_uri = getRequestUri("delivernotify_uri"); String delivernotify_uri = getRequestUri("delivernotify_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
@@ -87,7 +92,7 @@ public class PayApi extends BaseApi {
// 用户购买的openId // 用户购买的openId
param.put("openid", openId); param.put("openid", openId);
param.put("transid", transid); param.put("transid", transid);
param.put("out_trade_no", orderNo); param.put("out_trade_no", outTradeNo);
param.put("deliver_timestamp", System.currentTimeMillis() / 1000 + ""); param.put("deliver_timestamp", System.currentTimeMillis() / 1000 + "");
param.put("deliver_status", status ? "1" : "0"); param.put("deliver_status", status ? "1" : "0");
param.put("deliver_msg", statusMsg); param.put("deliver_msg", statusMsg);
@@ -105,20 +110,17 @@ public class PayApi extends BaseApi {
/** /**
* 订单查询 * 订单查询
* *
* @param weixinAccount
* 商户信息
* @param orderNo * @param orderNo
* 订单号 * 订单号
* @return * @return
* @throws WeixinException * @throws WeixinException
*/ */
public Order orderQueryV2(WeixinAccount weixinAccount, IdQuery idQuery) public Order orderQueryV2(String orderNo) throws WeixinException {
throws WeixinException { WeixinAccount weixinAccount = tokenHolder.getAccount();
String orderquery_uri = getRequestUri("orderquery_uri"); String orderquery_uri = getRequestUri("orderquery_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(idQuery.getType().getName()).append(idQuery.getId()); sb.append("out_trade_no=").append(orderNo);
sb.append("&partner=").append(weixinAccount.getPartnerId()); sb.append("&partner=").append(weixinAccount.getPartnerId());
String part = sb.toString(); String part = sb.toString();
sb.append("&key=").append(weixinAccount.getPartnerKey()); sb.append("&key=").append(weixinAccount.getPartnerKey());
@@ -149,6 +151,10 @@ public class PayApi extends BaseApi {
String order_info = response.getAsJson().getString("order_info"); String order_info = response.getAsJson().getString("order_info");
Order order = JSON.parseObject(order_info, Order.class, Order order = JSON.parseObject(order_info, Order.class,
Feature.IgnoreNotMatch); Feature.IgnoreNotMatch);
if (order.getRetCode() != 0) {
throw new WeixinException(Integer.toString(order.getRetCode()),
order.getRetMsg());
}
order.setMapData(JSON.parseObject(order_info, order.setMapData(JSON.parseObject(order_info,
new TypeReference<Map<String, String>>() { new TypeReference<Map<String, String>>() {
})); }));
@@ -177,21 +183,15 @@ public class PayApi extends BaseApi {
/** /**
* V3订单查询 * V3订单查询
* *
* @param weixinAccount
* 商户信息
* @param idQuery * @param idQuery
* 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级: * 商户系统内部的订单号, transaction_id、out_trade_no 二 选一,如果同时存在优先级:
* transaction_id> out_trade_no * transaction_id> out_trade_no
* @throws WeixinException * @throws WeixinException
*/ */
public com.foxinmy.weixin4j.mp.payment.v3.Order orderQueryV3( public com.foxinmy.weixin4j.mp.payment.v3.Order orderQueryV3(IdQuery idQuery)
WeixinAccount weixinAccount, IdQuery idQuery)
throws WeixinException { throws WeixinException {
Map<String, String> map = new HashMap<String, String>(); WeixinAccount weixinAccount = tokenHolder.getAccount();
map.put("appid", weixinAccount.getAppId()); Map<String, String> map = baseMap2V3(idQuery);
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
map.put(idQuery.getType().getName(), idQuery.getId());
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey()); String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign); map.put("sign", sign);
String param = map2xml(map); String param = map2xml(map);
@@ -202,6 +202,67 @@ public class PayApi extends BaseApi {
}); });
} }
/**
* 申请退款(请求需要双向证书)<br/>
* <p style="color:red">
* 交易时间超过 1 年的订单无法提交退款; <br/>
* 支持部分退款,部分退需要设置相同的订单号和不同的 out_refund_no。一笔退款失 败后重新提交,要采用原来的
* out_refund_no。总退款金额不能超过用户实际支付金额。<br/>
* </p>
*
* @param ca
* 证书文件
* @param idQuery
* ) 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级:
* transaction_id> out_trade_no
* @param outRefundNo
* 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔
* @param totalFee
* 订单总金额,单位为元
* @param refundFee
* 退款总金额,单位为元,可以做部分退款
* @param opUserId
* 操作员帐号, 默认为商户号
* @throws WeixinException
* @throws IOException
* @return 退款结果
*/
public RefundResult refund(InputStream ca, IdQuery idQuery,
String outRefundNo, double totalFee, double refundFee,
String opUserId) throws WeixinException, IOException {
WeixinAccount weixinAccount = tokenHolder.getAccount();
Map<String, String> map = baseMap2V3(idQuery);
map.put("out_refund_no", outRefundNo);
map.put("total_fee", DateUtil.formaFee2Fen(totalFee));
map.put("refund_fee", DateUtil.formaFee2Fen(refundFee));
if (StringUtils.isBlank(opUserId)) {
opUserId = weixinAccount.getMchId();
}
map.put("op_user_id", opUserId);
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign);
String param = map2xml(map);
String refund_uri = getRequestUri("refund_uri");
SSLHttpRequest request = new SSLHttpRequest(weixinAccount.getMchId(),
ca);
Response response = request.post(refund_uri, param);
return response.getAsObject(new TypeReference<RefundResult>() {
});
}
/**
* 使用properties中配置的ca文件
*
* @see {@link com.foxinmy.weixin4j.mp.api.PayApi#refund(InputStream, IdQuery, String, double, double, String)}
*/
public RefundResult refund(IdQuery idQuery, String outRefundNo,
double totalFee, double refundFee, String opUserId)
throws WeixinException, IOException {
File caFile = new File(ConfigUtil.getValue("ca_file"));
return refund(new FileInputStream(caFile), idQuery, outRefundNo,
totalFee, refundFee, opUserId);
}
/** /**
* native支付URL转短链接 * native支付URL转短链接
* *
@@ -212,13 +273,10 @@ public class PayApi extends BaseApi {
* @return 转换后的短链接 * @return 转换后的短链接
* @throws WeixinException * @throws WeixinException
*/ */
public String getShorturl(WeixinAccount weixinAccount, String url) public String getShorturl(String url) throws WeixinException {
throws WeixinException { WeixinAccount weixinAccount = tokenHolder.getAccount();
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = baseMap2V3(null);
map.put("appid", weixinAccount.getAppId());
map.put("mch_id", weixinAccount.getMchId());
map.put("long_url", url); map.put("long_url", url);
map.put("nonce_str", RandomUtil.generateString(16));
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey()); String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign); map.put("sign", sign);
try { try {
@@ -238,20 +296,15 @@ public class PayApi extends BaseApi {
* 当订单支付失败,调用关单接口后用新订单号重新发起支付,如果关单失败,返回已完 * 当订单支付失败,调用关单接口后用新订单号重新发起支付,如果关单失败,返回已完
* 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。 * 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。
* *
* @param weixinAccount * @param outTradeNo
* 商户信息
* @param idQuery
* 商户系统内部的订单号 * 商户系统内部的订单号
* @return * @return
* @throws WeixinException * @throws WeixinException
*/ */
public XmlResult closeOrder(WeixinAccount weixinAccount, IdQuery idQuery) public XmlResult closeOrder(String outTradeNo) throws WeixinException {
throws WeixinException { WeixinAccount weixinAccount = tokenHolder.getAccount();
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = baseMap2V3(new IdQuery(outTradeNo,
map.put("appid", weixinAccount.getAppId()); IdType.TRADENO));
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
map.put(idQuery.getType().getName(), idQuery.getId());
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey()); String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign); map.put("sign", sign);
String param = map2xml(map); String param = map2xml(map);
@@ -267,8 +320,6 @@ public class PayApi extends BaseApi {
* 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;<br> * 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;<br>
* 3.对账单中涉及金额的字段单位为“元”。<br> * 3.对账单中涉及金额的字段单位为“元”。<br>
* *
* @param weixinAccount
* 商户配置
* @param billDate * @param billDate
* 下载对账单的日期 * 下载对账单的日期
* @param billType * @param billType
@@ -278,9 +329,9 @@ public class PayApi extends BaseApi {
* @throws WeixinException * @throws WeixinException
* @throws IOException * @throws IOException
*/ */
public File downloadbill(WeixinAccount weixinAccount, Date billDate, public File downloadbill(Date billDate, BillType billType)
BillType billType) throws WeixinException, IOException { throws WeixinException, IOException {
WeixinAccount weixinAccount = tokenHolder.getAccount();
if (billDate == null) { if (billDate == null) {
Calendar now = Calendar.getInstance(); Calendar now = Calendar.getInstance();
now.add(Calendar.DAY_OF_MONTH, -10); now.add(Calendar.DAY_OF_MONTH, -10);
@@ -297,11 +348,7 @@ public class PayApi extends BaseApi {
if (file.exists()) { if (file.exists()) {
return file; return file;
} }
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = baseMap2V3(null);
map.put("appid", weixinAccount.getAppId());
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
map.put("device_info", weixinAccount.getDeviceInfo());
map.put("bill_date", _billDate); map.put("bill_date", _billDate);
map.put("bill_type", billType.name()); map.put("bill_type", billType.name());
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey()); String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
@@ -334,7 +381,6 @@ public class PayApi extends BaseApi {
* 退款查询<br/> * 退款查询<br/>
* 退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款 3 个工作日后重新查询退款状态 * 退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款 3 个工作日后重新查询退款状态
* *
* @param weixinAccount 商户信息
* @param idQuery * @param idQuery
* 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id * 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id
* 四个参数必填一个,优先级为: * 四个参数必填一个,优先级为:
@@ -342,14 +388,9 @@ public class PayApi extends BaseApi {
* @return 退款记录 * @return 退款记录
* @throws WeixinException * @throws WeixinException
*/ */
public Refund refundQuery(WeixinAccount weixinAccount, IdQuery idQuery) public Refund refundQuery(IdQuery idQuery) throws WeixinException {
throws WeixinException { WeixinAccount weixinAccount = tokenHolder.getAccount();
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = baseMap2V3(idQuery);
map.put("appid", weixinAccount.getAppId());
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
map.put("device_info", weixinAccount.getDeviceInfo());
map.put(idQuery.getType().getName(), idQuery.getId());
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey()); String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign); map.put("sign", sign);
String param = map2xml(map); String param = map2xml(map);
@@ -357,4 +398,24 @@ public class PayApi extends BaseApi {
Response response = request.post(refundquery_uri, param); Response response = request.post(refundquery_uri, param);
return new RefundConverter().fromXML(response.getAsString()); return new RefundConverter().fromXML(response.getAsString());
} }
/**
* V3接口请求基本数据
*
* @return
*/
private Map<String, String> baseMap2V3(IdQuery idQuery) {
WeixinAccount weixinAccount = tokenHolder.getAccount();
Map<String, String> map = new HashMap<String, String>();
map.put("appid", weixinAccount.getAppId());
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
if (StringUtils.isNotBlank(weixinAccount.getDeviceInfo())) {
map.put("device_info", weixinAccount.getDeviceInfo());
}
if (idQuery != null) {
map.put(idQuery.getType().getName(), idQuery.getId());
}
return map;
}
} }
@@ -10,7 +10,7 @@ import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinConfig; import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.mp.model.Following; import com.foxinmy.weixin4j.mp.model.Following;
import com.foxinmy.weixin4j.mp.model.OauthToken; import com.foxinmy.weixin4j.mp.model.OauthToken;
import com.foxinmy.weixin4j.mp.model.User; import com.foxinmy.weixin4j.mp.model.User;
@@ -45,10 +45,10 @@ public class UserApi extends BaseApi {
* @see com.foxinmy.weixin4j.mp.model.OauthToken * @see com.foxinmy.weixin4j.mp.model.OauthToken
*/ */
public OauthToken getOauthToken(String code) throws WeixinException { public OauthToken getOauthToken(String code) throws WeixinException {
WeixinAccount weixinAccount = tokenHolder.getAccount();
String user_token_uri = getRequestUri("sns_user_token_uri"); String user_token_uri = getRequestUri("sns_user_token_uri");
WeixinConfig weixinConfig = tokenHolder.getConfig();
Response response = request.get(String.format(user_token_uri, Response response = request.get(String.format(user_token_uri,
weixinConfig.getAppId(), weixinConfig.getAppSecret(), code)); weixinAccount.getAppId(), weixinAccount.getAppSecret(), code));
return response.getAsObject(new TypeReference<OauthToken>() { return response.getAsObject(new TypeReference<OauthToken>() {
}); });
@@ -17,11 +17,21 @@ public class OauthToken extends Token {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private String openid;
@JSONField(name = "refresh_token") @JSONField(name = "refresh_token")
private String refreshToken; private String refreshToken;
private String scope; private String scope;
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getRefreshToken() { public String getRefreshToken() {
return refreshToken; return refreshToken;
} }
@@ -40,6 +50,9 @@ public class OauthToken extends Token {
@Override @Override
public String toString() { public String toString() {
return "UserToken [refreshToken=" + refreshToken + ", scope=" + scope + ", getAccessToken()=" + getAccessToken() + ", getExpiresIn()=" + getExpiresIn() + ", getOpenid()=" + getOpenid() + ", getTime()=" + getTime() + "]"; return "OauthToken [openid=" + openid + ", refreshToken="
+ refreshToken + ", scope=" + scope + ", getAccessToken()="
+ getAccessToken() + ", getExpiresIn()=" + getExpiresIn()
+ ", getTime()=" + getTime() + "]";
} }
} }
@@ -20,6 +20,8 @@ public class ApiResult extends XmlResult {
private String appId;// 微信分配的公众账号 ID商户号 非空 private String appId;// 微信分配的公众账号 ID商户号 非空
@XStreamAlias("mch_id") @XStreamAlias("mch_id")
private String mchId;// 微信支付分配的商户号 非空 private String mchId;// 微信支付分配的商户号 非空
@XStreamAlias("sub_mch_id")
private String subMchId; // 未知 可能为空
@XStreamAlias("nonce_str") @XStreamAlias("nonce_str")
private String nonceStr;// 随机字符串 非空 private String nonceStr;// 随机字符串 非空
private String sign;// 签名 非空 private String sign;// 签名 非空
@@ -50,6 +52,14 @@ public class ApiResult extends XmlResult {
this.mchId = mchId; this.mchId = mchId;
} }
public String getSubMchId() {
return subMchId;
}
public void setSubMchId(String subMchId) {
this.subMchId = subMchId;
}
public String getNonceStr() { public String getNonceStr() {
return nonceStr; return nonceStr;
} }
@@ -76,8 +86,11 @@ public class ApiResult extends XmlResult {
@Override @Override
public String toString() { public String toString() {
return "ApiResult [appId=" + appId + ", mchId=" + mchId + ", nonceStr=" return "ApiResult [appId=" + appId + ", mchId=" + mchId + ", subMchId="
+ nonceStr + ", sign=" + sign + ", deviceInfo=" + deviceInfo + subMchId + ", nonceStr=" + nonceStr + ", sign=" + sign
+ "]"; + ", deviceInfo=" + deviceInfo + ", getReturnCode()="
+ getReturnCode() + ", getReturnMsg()=" + getReturnMsg()
+ ", getResultCode()=" + getResultCode() + ", getErrCode()="
+ getErrCode() + ", getErrCodeDes()=" + getErrCodeDes() + "]";
} }
} }
@@ -52,7 +52,7 @@ public class PayPackage implements Serializable {
} }
public void setTotal_fee(double total_fee) { public void setTotal_fee(double total_fee) {
this.total_fee = DateUtil.format2fee(total_fee); this.total_fee = DateUtil.formaFee2Fen(total_fee);
} }
public String getSpbill_create_ip() { public String getSpbill_create_ip() {
@@ -78,7 +78,6 @@ public class PayPackage implements Serializable {
public void setTime_start(Date time_start) { public void setTime_start(Date time_start) {
this.time_start = time_start != null ? DateUtil this.time_start = time_start != null ? DateUtil
.fortmat2yyyyMMddHHmmss(time_start) : null; .fortmat2yyyyMMddHHmmss(time_start) : null;
;
} }
public String getTime_expire() { public String getTime_expire() {
@@ -88,7 +87,6 @@ public class PayPackage implements Serializable {
public void setTime_expire(Date time_expire) { public void setTime_expire(Date time_expire) {
this.time_expire = time_expire != null ? DateUtil this.time_expire = time_expire != null ? DateUtil
.fortmat2yyyyMMddHHmmss(time_expire) : null; .fortmat2yyyyMMddHHmmss(time_expire) : null;
;
} }
public String getGoods_tag() { public String getGoods_tag() {
@@ -116,7 +114,7 @@ public class PayPackage implements Serializable {
this.body = body; this.body = body;
this.attach = attach; this.attach = attach;
this.out_trade_no = out_trade_no; this.out_trade_no = out_trade_no;
this.total_fee = DateUtil.format2fee(total_fee); this.total_fee = DateUtil.formaFee2Fen(total_fee);
this.spbill_create_ip = spbill_create_ip; this.spbill_create_ip = spbill_create_ip;
this.time_start = time_start != null ? DateUtil this.time_start = time_start != null ? DateUtil
.fortmat2yyyyMMddHHmmss(time_start) : null; .fortmat2yyyyMMddHHmmss(time_start) : null;
@@ -1,8 +1,11 @@
package com.foxinmy.weixin4j.mp.payment.v2; package com.foxinmy.weixin4j.mp.payment.v2;
import java.util.Date;
import java.util.Map; import java.util.Map;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.util.DateUtil;
/** /**
* 订单信息 * 订单信息
@@ -18,84 +21,104 @@ public class Order extends JsonResult {
private static final long serialVersionUID = 4543552984506609920L; private static final long serialVersionUID = 4543552984506609920L;
// 是查询结果状态码,0 表明成功,其他表明错误; // 是查询结果状态码,0 表明成功,其他表明错误;
private String ret_code; @JSONField(name = "ret_code")
private int retCode;
// 是查询结果出错信息; // 是查询结果出错信息;
private String ret_msg; @JSONField(name = "ret_msg")
private String retMsg;
// 是返回信息中的编码方式; // 是返回信息中的编码方式;
private String input_charset; @JSONField(name = "input_charset")
private String inputCharset;
// 是订单状态,0 为成功,其他为失败; // 是订单状态,0 为成功,其他为失败;
private String trade_state; @JSONField(name = "trade_state")
private int tradeState;
// 是交易模式,1 为即时到帐,其他保留; // 是交易模式,1 为即时到帐,其他保留;
private String trade_mode; @JSONField(name = "trade_mode")
private int tradeMode;
// 是财付通商户号,即前文的 partnerid; // 是财付通商户号,即前文的 partnerid;
private String partner; private String partner;
// 是银行类型; // 是银行类型;
private String bank_type; @JSONField(name = "bank_type")
private String bankType;
// 是银行订单号; // 是银行订单号;
private String bank_billno; @JSONField(name = "bank_billno")
private String bankBillno;
// 是总金额,单位为分; // 是总金额,单位为分;
private String total_fee; @JSONField(name = "total_fee")
private int totalFee;
// 是币种,1 为人民币; // 是币种,1 为人民币;
private String fee_type; @JSONField(name = "fee_type")
private String feeType;
// 是财付通订单号; // 是财付通订单号;
private String transaction_id; @JSONField(name = "transaction_id")
private String transactionId;
// 是第三方订单号; // 是第三方订单号;
private String out_trade_no; @JSONField(name = "out_trade_no")
private String outTradeNo;
// 表明是否分账,false 为无分账,true 为有分账; // 表明是否分账,false 为无分账,true 为有分账;
private boolean is_split; @JSONField(name = "is_split")
private boolean isSplit;
// 表明是否退款,false 为无退款,ture 为退款; // 表明是否退款,false 为无退款,ture 为退款;
private boolean is_refund; @JSONField(name = "is_refund")
private boolean isRefund;
// attach 是商户数据包,即生成订单package 时商户填入的 attach; // attach 是商户数据包,即生成订单package 时商户填入的 attach;
private String attach; private String attach;
// 支付完成时间; // 支付完成时间;
private String time_end; @JSONField(name = "time_end")
private String timeEnd;
// 物流费用,单位为分; // 物流费用,单位为分;
private String transport_fee; @JSONField(name = "transport_fee")
private int transportFee;
// 物品费用,单位为分; // 物品费用,单位为分;
private String product_fee; @JSONField(name = "product_fee")
private int productFee;
// 折扣价格,单位为分; // 折扣价格,单位为分;
private String discount; private int discount;
// 换算成人民币之后的总金额,单位为分,一般看 total_fee 即可。 // 换算成人民币之后的总金额,单位为分,一般看 total_fee 即可。
private String rmb_total_fee; @JSONField(name = "rmb_total_fee")
private int rmbTotalFee;
public String getRet_code() { @JSONField(serialize = false)
return ret_code; private Map<String, String> mapData;
public int getRetCode() {
return retCode;
} }
public void setRet_code(String ret_code) { public void setRetCode(int retCode) {
this.ret_code = ret_code; this.retCode = retCode;
} }
public String getRet_msg() { public String getRetMsg() {
return ret_msg; return retMsg;
} }
public void setRet_msg(String ret_msg) { public void setRetMsg(String retMsg) {
this.ret_msg = ret_msg; this.retMsg = retMsg;
} }
public String getInput_charset() { public String getInputCharset() {
return input_charset; return inputCharset;
} }
public void setInput_charset(String input_charset) { public void setInputCharset(String inputCharset) {
this.input_charset = input_charset; this.inputCharset = inputCharset;
} }
public String getTrade_state() { public int getTradeState() {
return trade_state; return tradeState;
} }
public void setTrade_state(String trade_state) { public void setTradeState(int tradeState) {
this.trade_state = trade_state; this.tradeState = tradeState;
} }
public String getTrade_mode() { public int getTradeMode() {
return trade_mode; return tradeMode;
} }
public void setTrade_mode(String trade_mode) { public void setTradeMode(int tradeMode) {
this.trade_mode = trade_mode; this.tradeMode = tradeMode;
} }
public String getPartner() { public String getPartner() {
@@ -106,68 +129,73 @@ public class Order extends JsonResult {
this.partner = partner; this.partner = partner;
} }
public String getBank_type() { public String getBankType() {
return bank_type; return bankType;
} }
public void setBank_type(String bank_type) { public void setBankType(String bankType) {
this.bank_type = bank_type; this.bankType = bankType;
} }
public String getBank_billno() { public String getBankBillno() {
return bank_billno; return bankBillno;
} }
public void setBank_billno(String bank_billno) { public void setBankBillno(String bankBillno) {
this.bank_billno = bank_billno; this.bankBillno = bankBillno;
} }
public String getTotal_fee() { /**
return total_fee; * <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
public double getTotalFee() {
return totalFee / 100d;
} }
public void setTotal_fee(String total_fee) { public void setTotalFee(int totalFee) {
this.total_fee = total_fee; this.totalFee = totalFee;
} }
public String getFee_type() { public String getFeeType() {
return fee_type; return feeType;
} }
public void setFee_type(String fee_type) { public void setFeeType(String feeType) {
this.fee_type = fee_type; this.feeType = feeType;
} }
public String getTransaction_id() { public String getTransactionId() {
return transaction_id; return transactionId;
} }
public void setTransaction_id(String transaction_id) { public void setTransactionId(String transactionId) {
this.transaction_id = transaction_id; this.transactionId = transactionId;
} }
public String getOut_trade_no() { public String getOutTradeNo() {
return out_trade_no; return outTradeNo;
} }
public void setOut_trade_no(String out_trade_no) { public void setOutTradeNo(String outTradeNo) {
this.out_trade_no = out_trade_no; this.outTradeNo = outTradeNo;
} }
public boolean isIs_split() { public boolean isSplit() {
return is_split; return isSplit;
} }
public void setIs_split(boolean is_split) { public void setSplit(boolean isSplit) {
this.is_split = is_split; this.isSplit = isSplit;
} }
public boolean isIs_refund() { public boolean isRefund() {
return is_refund; return isRefund;
} }
public void setIs_refund(boolean is_refund) { public void setRefund(boolean isRefund) {
this.is_refund = is_refund; this.isRefund = isRefund;
} }
public String getAttach() { public String getAttach() {
@@ -178,48 +206,66 @@ public class Order extends JsonResult {
this.attach = attach; this.attach = attach;
} }
public String getTime_end() { public Date getTimeEnd() {
return time_end; return DateUtil.parse2yyyyMMddHHmmss(timeEnd);
} }
public void setTime_end(String time_end) { public void setTimeEnd(String timeEnd) {
this.time_end = time_end; this.timeEnd = timeEnd;
} }
public String getTransport_fee() { /**
return transport_fee; * <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
public double getTransportFee() {
return transportFee / 100d;
} }
public void setTransport_fee(String transport_fee) { public void setTransportFee(int transportFee) {
this.transport_fee = transport_fee; this.transportFee = transportFee;
} }
public String getProduct_fee() { /**
return product_fee; * <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
public double getProductFee() {
return productFee / 100d;
} }
public void setProduct_fee(String product_fee) { public void setProductFee(int productFee) {
this.product_fee = product_fee; this.productFee = productFee;
} }
public String getDiscount() { /**
return discount; * <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
public double getDiscount() {
return discount / 100d;
} }
public void setDiscount(String discount) { public void setDiscount(int discount) {
this.discount = discount; this.discount = discount;
} }
public String getRmb_total_fee() { /**
return rmb_total_fee; * <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
public double getRmbTotalFee() {
return rmbTotalFee / 100d;
} }
public void setRmb_total_fee(String rmb_total_fee) { public void setRmbTotalFee(int rmbTotalFee) {
this.rmb_total_fee = rmb_total_fee; this.rmbTotalFee = rmbTotalFee;
} }
private Map<String, String> mapData;
public Map<String, String> getMapData() { public Map<String, String> getMapData() {
return mapData; return mapData;
} }
@@ -230,16 +276,16 @@ public class Order extends JsonResult {
@Override @Override
public String toString() { public String toString() {
return "Order [ret_code=" + ret_code + ", ret_msg=" + ret_msg return "Order [retCode=" + retCode + ", retMsg=" + retMsg
+ ", input_charset=" + input_charset + ", trade_state=" + ", inputCharset=" + inputCharset + ", tradeState="
+ trade_state + ", trade_mode=" + trade_mode + ", partner=" + tradeState + ", tradeMode=" + tradeMode + ", partner="
+ partner + ", bank_type=" + bank_type + ", bank_billno=" + partner + ", bankType=" + bankType + ", bankBillno="
+ bank_billno + ", total_fee=" + total_fee + ", fee_type=" + bankBillno + ", totalFee=" + totalFee + ", feeType="
+ fee_type + ", transaction_id=" + transaction_id + feeType + ", transactionId=" + transactionId
+ ", out_trade_no=" + out_trade_no + ", is_split=" + is_split + ", outTradeNo=" + outTradeNo + ", isSplit=" + isSplit
+ ", is_refund=" + is_refund + ", attach=" + attach + ", isRefund=" + isRefund + ", attach=" + attach
+ ", time_end=" + time_end + ", transport_fee=" + transport_fee + ", timeEnd=" + timeEnd + ", transportFee=" + transportFee
+ ", product_fee=" + product_fee + ", discount=" + discount + ", productFee=" + productFee + ", discount=" + discount
+ ", rmb_total_fee=" + rmb_total_fee + "]"; + ", rmbTotalFee=" + rmbTotalFee + ", mapData=" + mapData + "]";
} }
} }
@@ -38,66 +38,34 @@ public class PayFeedback extends PayBaseInfo {
return feedbackId; return feedbackId;
} }
public void setFeedbackId(String feedbackId) {
this.feedbackId = feedbackId;
}
public String getOpenId() { public String getOpenId() {
return openId; return openId;
} }
public void setOpenId(String openId) {
this.openId = openId;
}
public String getTransId() { public String getTransId() {
return transId; return transId;
} }
public void setTransId(String transId) {
this.transId = transId;
}
public String getReason() { public String getReason() {
return reason; return reason;
} }
public void setReason(String reason) {
this.reason = reason;
}
public String getSolution() { public String getSolution() {
return solution; return solution;
} }
public void setSolution(String solution) {
this.solution = solution;
}
public String getExtInfo() { public String getExtInfo() {
return extInfo; return extInfo;
} }
public void setExtInfo(String extInfo) {
this.extInfo = extInfo;
}
public String getPicInfo() { public String getPicInfo() {
return picInfo; return picInfo;
} }
public void setPicInfo(String picInfo) {
this.picInfo = picInfo;
}
public String getStatus() { public String getStatus() {
return status; return status;
} }
public void setStatus(String status) {
this.status = status;
}
@Override @Override
public String toString() { public String toString() {
return "PayFeedback [feedbackId=" + feedbackId + ", openId=" + openId return "PayFeedback [feedbackId=" + feedbackId + ", openId=" + openId
@@ -72,7 +72,7 @@ public class PayPackageV2 extends PayPackage {
} }
public void setTransport_fee(double transport_fee) { public void setTransport_fee(double transport_fee) {
this.transport_fee = DateUtil.format2fee(transport_fee); this.transport_fee = DateUtil.formaFee2Fen(transport_fee);
} }
public String getProduct_fee() { public String getProduct_fee() {
@@ -80,7 +80,7 @@ public class PayPackageV2 extends PayPackage {
} }
public void setProduct_fee(double product_fee) { public void setProduct_fee(double product_fee) {
this.product_fee = DateUtil.format2fee(product_fee); this.product_fee = DateUtil.formaFee2Fen(product_fee);
} }
public String getInput_charset() { public String getInput_charset() {
@@ -125,8 +125,8 @@ public class PayPackageV2 extends PayPackage {
this.fee_type = "1"; this.fee_type = "1";
this.input_charset = "UTF-8"; this.input_charset = "UTF-8";
this.transport_fee = transport_fee > 0d ? DateUtil this.transport_fee = transport_fee > 0d ? DateUtil
.format2fee(transport_fee) : null; .formaFee2Fen(transport_fee) : null;
this.product_fee = product_fee > 0 ? DateUtil.format2fee(product_fee) this.product_fee = product_fee > 0 ? DateUtil.formaFee2Fen(product_fee)
: null; : null;
} }
@@ -21,26 +21,14 @@ public class PayWarn extends PayBaseInfo {
return errortype; return errortype;
} }
public void setErrortype(String errortype) {
this.errortype = errortype;
}
public String getDescription() { public String getDescription() {
return description; return description;
} }
public void setDescription(String description) {
this.description = description;
}
public String getAlarmcontent() { public String getAlarmcontent() {
return alarmcontent; return alarmcontent;
} }
public void setAlarmcontent(String alarmcontent) {
this.alarmcontent = alarmcontent;
}
@Override @Override
public String toString() { public String toString() {
return "PayWarn [errortype=" + errortype + ", description=" return "PayWarn [errortype=" + errortype + ", description="
@@ -1,9 +1,12 @@
package com.foxinmy.weixin4j.mp.payment.v3; package com.foxinmy.weixin4j.mp.payment.v3;
import java.util.Date;
import com.foxinmy.weixin4j.mp.payment.ApiResult; import com.foxinmy.weixin4j.mp.payment.ApiResult;
import com.foxinmy.weixin4j.mp.type.CurrencyType; import com.foxinmy.weixin4j.mp.type.CurrencyType;
import com.foxinmy.weixin4j.mp.type.TradeState; import com.foxinmy.weixin4j.mp.type.TradeState;
import com.foxinmy.weixin4j.mp.type.TradeType; import com.foxinmy.weixin4j.mp.type.TradeType;
import com.foxinmy.weixin4j.util.DateUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
/** /**
@@ -51,7 +54,6 @@ public class Order extends ApiResult {
@XStreamAlias("out_rade_no") @XStreamAlias("out_rade_no")
private String outTradeNo; private String outTradeNo;
// 商家数据包 // 商家数据包
@XStreamAlias("attach")
private String attach; private String attach;
// 支付完成时间,格式为 yyyyMMddhhmmss // 支付完成时间,格式为 yyyyMMddhhmmss
@XStreamAlias("time_end") @XStreamAlias("time_end")
@@ -61,96 +63,58 @@ public class Order extends ApiResult {
return tradeState; return tradeState;
} }
public void setTradeState(TradeState tradeState) {
this.tradeState = tradeState;
}
public String getOpenId() { public String getOpenId() {
return openId; return openId;
} }
public void setOpenId(String openId) {
this.openId = openId;
}
public String getIsSubscribe() { public String getIsSubscribe() {
return isSubscribe; return isSubscribe;
} }
public void setIsSubscribe(String isSubscribe) {
this.isSubscribe = isSubscribe;
}
public TradeType getTradeType() { public TradeType getTradeType() {
return tradeType; return tradeType;
} }
public void setTradeType(TradeType tradeType) {
this.tradeType = tradeType;
}
public String getBankType() { public String getBankType() {
return bankType; return bankType;
} }
public void setBankType(String bankType) { /**
this.bankType = bankType; * <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
public double getTotalFee() {
return totalFee / 100d;
} }
public int getTotalFee() { /**
return totalFee; * <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
} *
* @return 元单位
public void setTotalFee(int totalFee) { */
this.totalFee = totalFee; public double getCouponFee() {
} return couponFee / 100d;
public int getCouponFee() {
return couponFee;
}
public void setCouponFee(int couponFee) {
this.couponFee = couponFee;
} }
public CurrencyType getFeeType() { public CurrencyType getFeeType() {
return feeType; return feeType;
} }
public void setFeeType(CurrencyType feeType) {
this.feeType = feeType;
}
public String getTransactionId() { public String getTransactionId() {
return transactionId; return transactionId;
} }
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public String getOutTradeNo() { public String getOutTradeNo() {
return outTradeNo; return outTradeNo;
} }
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public String getAttach() { public String getAttach() {
return attach; return attach;
} }
public void setAttach(String attach) { public Date getTimeEnd() {
this.attach = attach; return DateUtil.parse2yyyyMMddHHmmss(timeEnd);
}
public String getTimeEnd() {
return timeEnd;
}
public void setTimeEnd(String timeEnd) {
this.timeEnd = timeEnd;
} }
@Override @Override
@@ -33,34 +33,18 @@ public class Refund extends ApiResult {
return transactionId; return transactionId;
} }
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public String getOrderNo() { public String getOrderNo() {
return orderNo; return orderNo;
} }
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public String getSubMchId() { public String getSubMchId() {
return subMchId; return subMchId;
} }
public void setSubMchId(String subMchId) {
this.subMchId = subMchId;
}
public int getCount() { public int getCount() {
return count; return count;
} }
public void setCount(int count) {
this.count = count;
}
public List<RefundDetail> getDetails() { public List<RefundDetail> getDetails() {
return details; return details;
} }
@@ -71,15 +55,14 @@ public class Refund extends ApiResult {
@Override @Override
public String toString() { public String toString() {
return "Refund [transactionId=" + transactionId + ", subMchId=" return "Refund [transactionId=" + transactionId + ", orderNo="
+ subMchId + ", orderNo=" + orderNo + ", count=" + count + orderNo + ", subMchId=" + subMchId + ", count=" + count
+ ", details=" + details + ", getAppId()=" + getAppId() + ", details=" + details + ", getAppId()=" + getAppId()
+ ", getMchId()=" + getMchId() + ", getNonceStr()=" + ", getMchId()=" + getMchId() + ", getNonceStr()="
+ getNonceStr() + ", getSign()=" + getSign() + getNonceStr() + ", getSign()=" + getSign()
+ ", getDeviceInfo()=" + getDeviceInfo() + ", toString()=" + ", getDeviceInfo()=" + getDeviceInfo() + ", getReturnCode()="
+ super.toString() + ", getReturnCode()=" + getReturnCode() + getReturnCode() + ", getReturnMsg()=" + getReturnMsg()
+ ", getReturnMsg()=" + getReturnMsg() + ", getResultCode()=" + ", getResultCode()=" + getResultCode() + ", getErrCode()="
+ getResultCode() + ", getErrCode()=" + getErrCode() + getErrCode() + ", getErrCodeDes()=" + getErrCodeDes() + "]";
+ ", getErrCodeDes()=" + getErrCodeDes() + "]";
} }
} }
@@ -2,6 +2,9 @@ package com.foxinmy.weixin4j.mp.payment.v3;
import java.io.Serializable; import java.io.Serializable;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.mp.type.RefundChannel;
import com.foxinmy.weixin4j.mp.type.RefundStatus; import com.foxinmy.weixin4j.mp.type.RefundStatus;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
@@ -35,50 +38,37 @@ public class RefundDetail implements Serializable {
return outRefundNo; return outRefundNo;
} }
public void setOutRefundNo(String outRefundNo) {
this.outRefundNo = outRefundNo;
}
public String getRefundId() { public String getRefundId() {
return refundId; return refundId;
} }
public void setRefundId(String refundId) {
this.refundId = refundId;
}
public String getRefundChannel() { public String getRefundChannel() {
return refundChannel; return StringUtils.isBlank(refundChannel) ? RefundChannel.BALANCE
.name() : refundChannel;
} }
public void setRefundChannel(String refundChannel) { /**
this.refundChannel = refundChannel; * <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
public double getRefundFee() {
return refundFee / 100d;
} }
public int getRefundFee() { /**
return refundFee; * <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
} *
* @return 元单位
public void setRefundFee(int refundFee) { */
this.refundFee = refundFee; public double getCouponRefundFee() {
} return couponRefundFee / 100d;
public int getCouponRefundFee() {
return couponRefundFee;
}
public void setCouponRefundFee(int couponRefundFee) {
this.couponRefundFee = couponRefundFee;
} }
public RefundStatus getRefundStatus() { public RefundStatus getRefundStatus() {
return refundStatus; return refundStatus;
} }
public void setRefundStatus(RefundStatus refundStatus) {
this.refundStatus = refundStatus;
}
@Override @Override
public String toString() { public String toString() {
return "RefundDetail [outRefundNo=" + outRefundNo + ", refundId=" return "RefundDetail [outRefundNo=" + outRefundNo + ", refundId="
@@ -0,0 +1,98 @@
package com.foxinmy.weixin4j.mp.payment.v3;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.mp.payment.ApiResult;
import com.foxinmy.weixin4j.mp.type.RefundChannel;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 退款申请结果
*
* @className RefundResult
* @author jy
* @date 2014年11月6日
* @since JDK 1.7
* @see
*/
@XStreamAlias("xml")
public class RefundResult extends ApiResult {
private static final long serialVersionUID = -3687863914168618620L;
// 微信订单号
@XStreamAlias("transaction_id")
private String transactionId;
// 商户系统内部的订单号
@XStreamAlias("out_trade_no")
private String outTradeNo;
// 商户退款单号
@XStreamAlias("out_refund_no")
private String outRefundNo;
// 微信退款单号
@XStreamAlias("refund_id")
private String refundId;
// 退款渠道 ORIGINAL—原路退款,默认 BALANCE—退回到余额
@XStreamAlias("refund_channel")
private String refundChannel;
// 退款总金额,单位为元,可以做部分退款
@XStreamAlias("refund_fee")
private int refundFee;
// 现金券退款金额<=退款金 额,退款金额-现金券退款金 额为现金
@XStreamAlias("coupon_refund_fee")
private int couponRefundFee;
public String getTransactionId() {
return transactionId;
}
public String getOutTradeNo() {
return outTradeNo;
}
public String getOutRefundNo() {
return outRefundNo;
}
public String getRefundId() {
return refundId;
}
public String getRefundChannel() {
return StringUtils.isBlank(refundChannel) ? RefundChannel.BALANCE
.name() : refundChannel;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
public double getRefundFee() {
return refundFee / 100d;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
public double getCouponRefundFee() {
return couponRefundFee / 100d;
}
@Override
public String toString() {
return "RefundResult [transactionId=" + transactionId + ", outTradeNo="
+ outTradeNo + ", outRefundNo=" + outRefundNo + ", refundId="
+ refundId + ", refundChannel=" + refundChannel
+ ", refundFee=" + refundFee + ", couponRefundFee="
+ couponRefundFee + ", getAppId()=" + getAppId()
+ ", getMchId()=" + getMchId() + ", getNonceStr()="
+ getNonceStr() + ", getSign()=" + getSign()
+ ", getDeviceInfo()=" + getDeviceInfo() + ", getReturnCode()="
+ getReturnCode() + ", getReturnMsg()=" + getReturnMsg()
+ ", getResultCode()=" + getResultCode() + ", getErrCode()="
+ getErrCode() + ", getErrCodeDes()=" + getErrCodeDes() + "]";
}
}
@@ -12,7 +12,7 @@ package com.foxinmy.weixin4j.mp.type;
public enum IdType { public enum IdType {
REFUNDID("refund_id"), // 微信退款单号 REFUNDID("refund_id"), // 微信退款单号
TRANSACTIONID("transaction_id"), // 微信订单号 TRANSACTIONID("transaction_id"), // 微信订单号
ORDERNO("out_trade_no"), // 商户订单号 TRADENO("out_trade_no"), // 商户订单号
REFUNDNO("out_refund_no"); // 商户退款号 REFUNDNO("out_refund_no"); // 商户退款号
private String name; private String name;
@@ -0,0 +1,15 @@
package com.foxinmy.weixin4j.mp.type;
/**
* 退款渠道
*
* @className RefundChannel
* @author jy
* @date 2014年11月6日
* @since JDK 1.7
* @see
*/
public enum RefundChannel {
ORIGINAL, // 原路退款
BALANCE;// 退回到余额
}
@@ -36,11 +36,11 @@ public class MessagePush {
int status = statusLine.getStatusCode(); int status = statusLine.getStatusCode();
if (status != HttpStatus.SC_OK) { if (status != HttpStatus.SC_OK) {
throw new WeixinException(status + "", "request fail"); throw new WeixinException(Integer.toString(status), "request fail");
} }
if (status == HttpStatus.SC_MOVED_PERMANENTLY if (status == HttpStatus.SC_MOVED_PERMANENTLY
|| status == HttpStatus.SC_MOVED_TEMPORARILY) { || status == HttpStatus.SC_MOVED_TEMPORARILY) {
throw new WeixinException(status + "", "uri moved"); throw new WeixinException(Integer.toString(status), "uri moved");
} }
return EntityUtils.toString(httpResponse.getEntity(), return EntityUtils.toString(httpResponse.getEntity(),
StandardCharsets.UTF_8); StandardCharsets.UTF_8);
+1 -1
View File
@@ -23,7 +23,7 @@ weixin4j-mp-server
| media_path | 调用媒体接口时保存媒体文件的物理路径 | | media_path | 调用媒体接口时保存媒体文件的物理路径 |
| bill_path | 调用支付(`V3`)下载对账单接口保存excel文件的物理路径 | | bill_path | 调用支付(`V3`)下载对账单接口保存excel文件的物理路径 |
示例(properties中换行用右斜杆\) 示例(properties中换行用右斜杆\\)
> account={"appId":"appId","appSecret":"appSecret", > account={"appId":"appId","appSecret":"appSecret",
> "token":"开放者的token 非必须","openId":"公众号的openid 非必须", > "token":"开放者的token 非必须","openId":"公众号的openid 非必须",
@@ -13,3 +13,5 @@ qr_path=/tmp/weixin/qr
media_path=/tmp/weixin/media media_path=/tmp/weixin/media
# \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84 # \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84
bill_path=/tmp/weixin/bill bill_path=/tmp/weixin/bill
# ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84
ca_file=/tmp/weixin/xxxxx.p12