View Javadoc
1   package com.foxinmy.weixin4j.pay.api;
2   
3   import com.alibaba.fastjson.JSON;
4   import com.alibaba.fastjson.JSONObject;
5   import com.alibaba.fastjson.TypeReference;
6   import com.foxinmy.weixin4j.exception.WeixinException;
7   import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
8   import com.foxinmy.weixin4j.pay.model.WeixinPayAccount;
9   import com.foxinmy.weixin4j.model.paging.Pageable;
10  import com.foxinmy.weixin4j.pay.payment.mch.*;
11  import com.foxinmy.weixin4j.pay.type.CurrencyType;
12  import com.foxinmy.weixin4j.util.DateUtil;
13  import com.foxinmy.weixin4j.util.RandomUtil;
14  import com.foxinmy.weixin4j.util.StringUtil;
15  import com.foxinmy.weixin4j.xml.XmlStream;
16  
17  import java.math.BigDecimal;
18  import java.util.ArrayList;
19  import java.util.Date;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.concurrent.*;
23  
24  /**
25   * 现金API
26   *
27   * @className CashApi
28   * @author jinyu(foxinmy@gmail.com)
29   * @date 2015年3月28日
30   * @since JDK 1.6
31   * @see <a href=
32   *      "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_1">
33   *      现金红包</a>
34   * @see <a href=
35   *      "https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1">
36   *      企业付款</a>
37   */
38  public class CashApi extends MchApi {
39  
40  	public CashApi(WeixinPayAccount weixinAccount) {
41  		super(weixinAccount);
42  	}
43  
44  	/**
45  	 * 发放红包 企业向微信用户个人发现金红包
46  	 *
47  	 * @param redpacket
48  	 *            红包信息
49  	 * @return 发放结果
50  	 * @see Redpacket
51  	 * @see RedpacketSendResult
52  	 * @see <a href=
53  	 *      "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5">
54  	 *      发放现金红包接口</a>
55  	 * @see <a href=
56  	 *      "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=16_5">
57  	 *      发放裂变红包接口</a>
58  	 * @throws WeixinException
59  	 */
60  	public RedpacketSendResult sendRedpack(Redpacket redpacket)
61  			throws WeixinException {
62  		String appId = redpacket.getAppId();
63  		super.declareMerchant(redpacket);
64  		final JSONObject obj = (JSONObject) JSON.toJSON(redpacket);
65  		if (StringUtil.isNotBlank(appId)) {
66  			obj.put("appid", appId);
67  		}
68  		obj.put("wxappid", obj.remove("appid"));
69  		final String redpack_uri = redpacket.getTotalNum() > 1 ? getRequestUri("groupredpack_send_uri")
70  				: getRequestUri("redpack_send_uri");
71  		obj.put("sign", weixinSignature.sign(obj));
72  		String param = XmlStream.map2xml(obj);
73  		WeixinResponse response = getWeixinSSLExecutor().post(redpack_uri,
74  				param);
75  		String text = response.getAsString()
76  				.replaceFirst("<wxappid>", "<appid>")
77  				.replaceFirst("</wxappid>", "</appid>");
78  		return XmlStream.fromXML(text, RedpacketSendResult.class);
79  	}
80  
81  	/**
82  	 * 批量发放红包 企业向微信用户个人发现金红包
83  	 *
84  	 *            多个红包信息
85  	 * @return 发放结果
86  	 * @see #sendRedpacks(Redpacket...)
87  	 * @throws WeixinException
88  	 */
89  	public List<Future<RedpacketSendResult>> sendRedpacks(
90  			Redpacket... redpackets) {
91  		ExecutorService sendExecutor = Executors.newFixedThreadPool(Math.max(1,
92  				redpackets.length / 10)); // 十分之一?
93  		CompletionService<RedpacketSendResult> completion = new ExecutorCompletionService<RedpacketSendResult>(
94  				sendExecutor);
95  		List<Future<RedpacketSendResult>> callSendList = new ArrayList<Future<RedpacketSendResult>>(
96  				redpackets.length);
97  		for (final Redpacket redpacket : redpackets) {
98  			Future<RedpacketSendResult> futureSend = completion
99  					.submit(new Callable<RedpacketSendResult>() {
100 						@Override
101 						public RedpacketSendResult call() throws Exception {
102 							return sendRedpack(redpacket);
103 						}
104 					});
105 			callSendList.add(futureSend);
106 		}
107 		// 关闭启动线程,不再接受新的任务
108 		sendExecutor.shutdown();
109 		return callSendList;
110 	}
111 
112 	/**
113 	 * 查询红包记录
114 	 *
115 	 * @param outTradeNo
116 	 *            商户发放红包的商户订单号
117 	 * @return 红包记录
118 	 * @see RedpacketRecord
119 	 * @see <a href=
120 	 *      "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_7&index=6">
121 	 *      查询现金红包接口</a>
122 	 * @see <a href=
123 	 *      "https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=16_6">
124 	 *      查询裂变红包接口</a>
125 	 * @throws WeixinException
126 	 */
127 	public RedpacketRecord queryRedpack(String outTradeNo)
128 			throws WeixinException {
129 		Map<String, String> para = createBaseRequestMap(null);
130 		para.put("bill_type", "MCHT");
131 		para.put("mch_billno", outTradeNo);
132 		para.put("sign", weixinSignature.sign(para));
133 		String param = XmlStream.map2xml(para);
134 		WeixinResponse response = getWeixinSSLExecutor().post(
135 				getRequestUri("redpack_query_uri"), param);
136 		return response.getAsObject(new TypeReference<RedpacketRecord>() {
137 		});
138 	}
139 
140 	/**
141 	 * 企业付款为企业提供付款至用户零钱的能力
142 	 *
143 	 * @param payment 付款信息
144 	 * @return 付款结果
145 	 * @see CorpPayment
146 	 * @see CorpPaymentResult
147 	 * @see <a href="https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2">企业付款</a>
148 	 * @see <a href="https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1">场景介绍(使用条件、付款资金、付款规则等)</a>
149 	 * @throws WeixinException
150 	 */
151 	public CorpPaymentResult sendCorpPayment(CorpPayment payment)
152 			throws WeixinException {
153 		super.declareMerchant(payment);
154 		JSONObject obj = (JSONObject) JSON.toJSON(payment);
155 		obj.put("mchid", obj.remove("mch_id"));
156 		obj.put("mch_appid", obj.remove("appid"));
157 		obj.put("sign", weixinSignature.sign(obj));
158 		String param = XmlStream.map2xml(obj);
159 		WeixinResponse response = getWeixinSSLExecutor().post(
160 				getRequestUri("corppayment_send_uri"), param);
161 		String text = response.getAsString()
162 				.replaceFirst("<mch_appid>", "<appid>")
163 				.replaceFirst("</mch_appid>", "</appid>")
164 				.replaceFirst("<mchid>", "<mch_id>")
165 				.replaceFirst("</mchid>", "</mch_id>");
166 		return XmlStream.fromXML(text, CorpPaymentResult.class);
167 	}
168 
169 	/**
170 	 * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果
171 	 *
172 	 * @param outTradeNo
173 	 *            商户调用企业付款API时使用的商户订单号
174 	 * @return 付款记录
175 	 * @see CorpPaymentRecord
176 	 * @see <a href=
177 	 *      "https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3">
178 	 *      企业付款查询接口</a>
179 	 * @throws WeixinException
180 	 */
181 	public CorpPaymentRecord queryCorpPayment(String outTradeNo)
182 			throws WeixinException {
183 		JSONObject obj = new JSONObject();
184 		obj.put("nonce_str", RandomUtil.generateString(16));
185 		obj.put("mch_id", weixinAccount.getMchId());
186 		obj.put("appid", weixinAccount.getId());
187 		obj.put("partner_trade_no", outTradeNo);
188 		obj.put("sign", weixinSignature.sign(obj));
189 		String param = XmlStream.map2xml(obj);
190 		WeixinResponse response = getWeixinSSLExecutor().post(
191 				getRequestUri("corppayment_query_uri"), param);
192 		return response.getAsObject(new TypeReference<CorpPaymentRecord>() {
193 		});
194 	}
195 
196 	/**
197 	 * 查询结算资金
198 	 *
199 	 * @param status
200 	 *            是否结算
201 	 * @param pageable
202 	 *            分页数据
203 	 * @param start
204 	 *            开始日期 查询未结算记录时,该字段可不传
205 	 * @param end
206 	 *            结束日期 查询未结算记录时,该字段可不传
207 	 * @return 结算金额记录
208 	 * @throws WeixinException
209 	 * @see SettlementRecord
210 	 * @see <a href=
211 	 *      "https://pay.weixin.qq.com/wiki/doc/api/external/micropay.php?chapter=9_14&index=7">
212 	 *      查询结算资金接口</a>
213 	 */
214 	public SettlementRecord querySettlement(boolean status, Pageable pageable,
215 			Date start, Date end) throws WeixinException {
216 		JSONObject obj = new JSONObject();
217 		obj.put("nonce_str", RandomUtil.generateString(16));
218 		obj.put("mch_id", weixinAccount.getMchId());
219 		obj.put("appid", weixinAccount.getId());
220 		obj.put("usetag", status ? 1 : 2);
221 		obj.put("offset", pageable.getOffset());
222 		obj.put("limit", pageable.getPageSize());
223 		if (start != null) {
224 			obj.put("date_start", DateUtil.fortmat2yyyyMMdd(start));
225 		}
226 		if (end != null) {
227 			obj.put("date_end", DateUtil.fortmat2yyyyMMdd(end));
228 		}
229 		obj.put("sign", weixinSignature.sign(obj));
230 		String param = XmlStream.map2xml(obj);
231 		WeixinResponse response = weixinExecutor.post(
232 				getRequestUri("settlement_query_uri"), param);
233 		return response.getAsObject(new TypeReference<SettlementRecord>() {
234 		});
235 	}
236 
237 	/**
238 	 * 查询汇率
239 	 *
240 	 * @param currencyType
241 	 *            外币币种
242 	 * @param date
243 	 *            日期 不填则默认当天
244 	 * @return 汇率 例如美元兑换人民币的比例为6.5
245 	 * @throws WeixinException
246 	 * @see <a href=
247 	 *      "https://pay.weixin.qq.com/wiki/doc/api/external/micropay.php?chapter=9_15&index=8">
248 	 *      查询汇率接口</a>
249 	 */
250 	public double queryExchageRate(CurrencyType currencyType, Date date)
251 			throws WeixinException {
252 		if (date == null) {
253 			date = new Date();
254 		}
255 		JSONObject obj = new JSONObject();
256 		obj.put("mch_id", weixinAccount.getMchId());
257 		obj.put("appid", weixinAccount.getId());
258 		obj.put("sub_mch_id", weixinAccount.getSubMchId());
259 		obj.put("fee_type", currencyType.name());
260 		obj.put("date", DateUtil.fortmat2yyyyMMdd(date));
261 		obj.put("sign", weixinSignature.sign(obj));
262 		String param = XmlStream.map2xml(obj);
263 		WeixinResponse response = weixinExecutor.post(
264 				getRequestUri("exchagerate_query_uri"), param);
265 		BigDecimal rate = new BigDecimal(XmlStream.xml2map(
266 				response.getAsString()).get("rate"));
267 		return rate.divide(new BigDecimal(100000000d)).doubleValue();
268 	}
269 }