You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					
					
						
							1243 lines
						
					
					
						
							50 KiB
						
					
					
				
			
		
		
	
	
							1243 lines
						
					
					
						
							50 KiB
						
					
					
				| package com.ynxbd.wx.wxfactory;
 | |
| 
 | |
| import com.alibaba.fastjson.JSONObject;
 | |
| import com.ynxbd.common.bean.enums.MerchantEnum;
 | |
| import com.ynxbd.common.bean.pay.Bill;
 | |
| import com.ynxbd.common.bean.pay.Order;
 | |
| import com.ynxbd.common.helper.cache.TextCache;
 | |
| import com.ynxbd.common.helper.common.*;
 | |
| import com.ynxbd.common.result.ResultEnum;
 | |
| import com.ynxbd.common.result.ServiceException;
 | |
| import com.ynxbd.wx.config.WeChatConfig;
 | |
| import com.ynxbd.wx.wxfactory.bean.WxPayNotify;
 | |
| import com.ynxbd.wx.wxfactory.bean.refund.WxRefundItem;
 | |
| import com.ynxbd.wx.wxfactory.bean.refund.WxRefundQueryRoot;
 | |
| import com.ynxbd.wx.wxfactory.utils.WxSignHelper;
 | |
| import lombok.extern.slf4j.Slf4j;
 | |
| import org.apache.commons.lang3.ObjectUtils;
 | |
| import org.apache.commons.lang3.StringUtils;
 | |
| import weixin.popular.api.PayMchAPI;
 | |
| import weixin.popular.bean.paymch.*;
 | |
| import weixin.popular.client.LocalHttpClient;
 | |
| 
 | |
| import javax.servlet.http.HttpServletRequest;
 | |
| import java.math.BigDecimal;
 | |
| import java.util.*;
 | |
| import java.util.stream.Collectors;
 | |
| 
 | |
| import static weixin.popular.api.PayMchAPI.payRefundquery;
 | |
| 
 | |
| /**
 | |
|  * @Author wsq
 | |
|  * @Date 2020/8/17 15:26
 | |
|  * @Copyright @ 2020 云南新八达科技有限公司 All rights reserved.
 | |
|  */
 | |
| @Slf4j
 | |
| public class WxPayHelper {
 | |
|     // 证书名称
 | |
|     public static final String API_CLIENT_CERT_NAME = "apiclient_cert.p12";
 | |
|     public static final String ALL = "ALL";   // 查询全部订单
 | |
| 
 | |
|     // 交易成功返回内容
 | |
|     public static final String REVOKED = "REVOKED";   // 订单已撤销
 | |
|     public static final String PAY_ERROR = "PAYERROR"; // 支付失败
 | |
|     public static final String USER_PAYING = "USERPAYING"; // 用户支付中
 | |
|     public static final String REFUND = "REFUND"; // 发生过退款
 | |
| 
 | |
|     // 失败
 | |
|     public static final String FAIL = "FAIL";
 | |
| 
 | |
|     // 成功
 | |
|     public static final String SUCCESS = "SUCCESS";
 | |
|     public static final String OK = "OK";
 | |
|     // 排重
 | |
|     public static final RepeatKeyHelper KEYS = new RepeatKeyHelper(60);
 | |
| 
 | |
|     static {
 | |
|         try {
 | |
|             String mchId = WeChatConfig.MCH_ID;
 | |
|             if (!ObjectUtils.isEmpty(mchId)) {
 | |
|                 String clazzPath = Objects.requireNonNull(WxPayHelper.class.getClassLoader().getResource("")).getPath();
 | |
|                 if (clazzPath == null) {
 | |
|                     log.info("【微信】未找到证书");
 | |
|                 }
 | |
|                 LocalHttpClient.initMchKeyStore(mchId, clazzPath + API_CLIENT_CERT_NAME);
 | |
|             }
 | |
|         } catch (Exception e) {
 | |
|             ErrorHelper.println(e);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 微信支付调用及通知
 | |
|      *
 | |
|      * @param request 请求
 | |
|      * @return 微信支付信息
 | |
|      */
 | |
|     public static WxPayNotify payNotify(HttpServletRequest request) throws ServiceException {
 | |
|         try {
 | |
|             // 转换数据对象
 | |
|             Map<String, Object> paramsMap = WxSignHelper.getReqXmlParamsMap(request);
 | |
|             log.info("【微信回调】map={}", paramsMap);
 | |
|             if (paramsMap == null) {
 | |
|                 throw new ServiceException("【微信】回调通知下单信息返回错误");
 | |
|             }
 | |
| 
 | |
|             // 签名验证
 | |
|             if (!WxSignHelper.validateSign(paramsMap, WeChatConfig.MCH_KEY)) { // 验证未通过,通知支付失败
 | |
|                 throw new ServiceException("【微信】回调通知签名验证未通过!");
 | |
|             }
 | |
| 
 | |
|             String json = JsonHelper.toJsonString(paramsMap);
 | |
|             if ("".equals(json)) {
 | |
|                 throw new ServiceException("【微信】回调通知下单信息为空");
 | |
|             }
 | |
| 
 | |
|             WxPayNotify notifyInfo = JsonHelper.parseObject(json, WxPayNotify.class);
 | |
|             log.info("【微信回调】notifyInfo={}", notifyInfo);
 | |
|             if (notifyInfo == null) {
 | |
|                 throw new ServiceException("【微信】回调通知下单信息转换失败");
 | |
|             }
 | |
| 
 | |
|             String openid = notifyInfo.getOpenid();
 | |
|             String outTradeNo = notifyInfo.getOutTradeNo();
 | |
|             String bankTransNo = notifyInfo.getTransactionId();
 | |
|             BigDecimal totalFee = notifyInfo.getTotalFee();// 金额
 | |
|             String timeEnd = notifyInfo.getTimeEnd();
 | |
| 
 | |
|             if (openid == null || outTradeNo == null || bankTransNo == null || totalFee == null || timeEnd == null) {
 | |
|                 throw new ServiceException(String.format("【微信】下单信息返回错误 outTradeNo={%s}", outTradeNo));
 | |
|             }
 | |
| 
 | |
|             // 已处理 去重
 | |
|             if (KEYS.isContainsKey(bankTransNo)) {
 | |
|                 throw new ServiceException(ResultEnum.PAY_NOTIFY_REPEAT, String.format("【微信】[重复请求]下单信息去重 outTradeNo={%s}", outTradeNo));
 | |
|             }
 | |
| 
 | |
|             String info = WxSignHelper.getMapInfo(paramsMap);
 | |
| 
 | |
|             Map<String, String> dateMap = WxSignHelper.getDateMap(timeEnd);
 | |
|             notifyInfo.setPayDate(dateMap.get(WxSignHelper.DATE_KEY));
 | |
|             notifyInfo.setPayTime(dateMap.get(WxSignHelper.TIME_KEY));
 | |
| 
 | |
|             notifyInfo.setPayInfo(info);
 | |
|             notifyInfo.setTotalFee(totalFee.movePointLeft(2));
 | |
|             return notifyInfo;
 | |
|         } catch (Exception e) {
 | |
|             if (e instanceof ServiceException) {
 | |
|                 throw e;
 | |
|             }
 | |
|             ErrorHelper.println(e);
 | |
|             throw new ServiceException(String.format("【微信】支付通知异常:[%s]", e.getMessage()));
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * 商户创建订单
 | |
|      *
 | |
|      * @param merchantEnum 枚举
 | |
|      * @param title        商品标题
 | |
|      * @param totalFee     订单金额
 | |
|      * @param outTradeNo   订单号
 | |
|      * @param notifyType   回调类型
 | |
|      * @param ip           ip地址
 | |
|      * @param openid       openid
 | |
|      * @param patientId    患者id
 | |
|      * @return 成功返回 json, 否则返回null
 | |
|      */
 | |
|     public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String notifyType, String ip, String openid, String patientId) {
 | |
|         try {
 | |
|             if (ObjectUtils.isEmpty(openid) || ObjectUtils.isEmpty(outTradeNo)
 | |
|                     || merchantEnum == null || totalFee == null || notifyType == null) {
 | |
|                 log.info("【微信】下单参数缺失");
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             // 金额转换
 | |
|             String cents;
 | |
|             try {
 | |
|                 cents = new BigDecimal(totalFee).movePointRight(2).toString(); // 单位分
 | |
|             } catch (Exception e) {
 | |
|                 ErrorHelper.println(e);
 | |
|                 log.info("【微信】统一下单金额转换异常");
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             String appId = WeChatConfig.APP_ID;
 | |
|             String mchId = WeChatConfig.MCH_ID;
 | |
|             String mchKey = WeChatConfig.MCH_KEY;
 | |
|             String nonce = UUID.randomUUID().toString().replace("-", "");
 | |
| 
 | |
|             Unifiedorder unifiedorder = new Unifiedorder();
 | |
|             unifiedorder.setAppid(appId);
 | |
|             unifiedorder.setMch_id(mchId);
 | |
|             unifiedorder.setNonce_str(nonce);
 | |
|             unifiedorder.setOpenid(openid);
 | |
|             unifiedorder.setOut_trade_no(outTradeNo);
 | |
|             unifiedorder.setBody(title);
 | |
| 
 | |
|             unifiedorder.setTotal_fee(cents); // 金额分
 | |
|             unifiedorder.setSpbill_create_ip(ip);
 | |
|             unifiedorder.setNotify_url(WeChatConfig.getBaseUrl() + merchantEnum.NOTIFY_URL);
 | |
|             unifiedorder.setTrade_type("JSAPI");
 | |
|             // 额外参数
 | |
|             unifiedorder.setAttach(notifyType);
 | |
| 
 | |
|             log.info(appId + ","
 | |
|                     + mchId + ","
 | |
|                     + nonce + ","
 | |
|                     + title + ","
 | |
|                     + outTradeNo + ","
 | |
|                     + totalFee + ","
 | |
|                     + ip + ","
 | |
|                     + merchantEnum.NOTIFY_URL);
 | |
| 
 | |
|             // 微信统一下单
 | |
|             UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder, mchKey);
 | |
|             log.info("【微信】统一下单返回:{}", JsonHelper.toJsonString(unifiedorderResult));
 | |
|             if (unifiedorderResult == null) {
 | |
|                 log.info("【微信】统一下单失败");
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             String result_code = unifiedorderResult.getResult_code();
 | |
|             // 下单是否成功
 | |
|             Boolean sign_status = unifiedorderResult.getSign_status();
 | |
|             if (!SUCCESS.equals(result_code) || sign_status == null || !sign_status) {
 | |
|                 log.info("【微信】统一下单返回异常信息:sign_status={}, err_code=[ {} ], err_code_des=[ {} ]", sign_status, unifiedorderResult.getErr_code(), unifiedorderResult.getErr_code_des());
 | |
|                 return null;
 | |
|             }
 | |
|             String json = weixin.popular.util.PayUtil.generateMchPayJsRequestJson(unifiedorderResult.getPrepay_id(), appId, mchKey);
 | |
|             if (json != null) {
 | |
|                 return JsonHelper.parseObject(json);
 | |
|             }
 | |
|         } catch (Exception e) {
 | |
|             log.error("【微信】统一下单异常信息:" + e.getMessage());
 | |
|             ErrorHelper.println(e);
 | |
|         }
 | |
|         return null;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * 微信退款
 | |
|      *
 | |
|      * @param outTradeNo  订单号
 | |
|      * @param outRefundNo 退款订单号(HIS订单号)
 | |
|      * @param refundMoney 本次退款金额
 | |
|      * @param totalFee    订单总金额
 | |
|      * @param desc        退款描述
 | |
|      * @return 退款信息
 | |
|      */
 | |
|     public static Order refund(String outTradeNo, String outRefundNo, BigDecimal refundMoney, BigDecimal totalFee, String desc) {
 | |
|         Order order = new Order();
 | |
|         try {
 | |
|             int feeCents;
 | |
|             int totalFeeCents;
 | |
| 
 | |
|             feeCents = refundMoney.movePointRight(2).intValue(); // 单位分
 | |
|             totalFeeCents = totalFee.movePointRight(2).intValue();
 | |
| 
 | |
|             if (feeCents == 0 || totalFeeCents == 0) {
 | |
|                 order.setErrorMsg(ResultEnum.REFUND_MONEY_IS_ZERO.message);
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             log.info("【微信】退款开始 outTradeNo={}, refundMoney={}, totalFee={}", outTradeNo, feeCents, totalFeeCents);
 | |
| 
 | |
|             SecapiPayRefund refund = new SecapiPayRefund();
 | |
|             refund.setAppid(WeChatConfig.APP_ID);
 | |
|             refund.setMch_id(WeChatConfig.MCH_ID);
 | |
|             refund.setNonce_str(UUID.randomUUID().toString().replace("-", ""));
 | |
|             refund.setSign_type("MD5");
 | |
|             refund.setOut_trade_no(outTradeNo);
 | |
|             refund.setOut_refund_no(outRefundNo);
 | |
|             refund.setRefund_fee(feeCents);
 | |
|             refund.setTotal_fee(totalFeeCents);
 | |
|             refund.setRefund_fee_type("CNY");
 | |
|             refund.setRefund_account("REFUND_SOURCE_UNSETTLED_FUNDS");
 | |
|             if (desc.length() > 80) {
 | |
|                 desc = desc.substring(0, 80);
 | |
|             }
 | |
| 
 | |
|             desc = TextCache.textFilter(desc);
 | |
|             refund.setRefund_desc(desc);
 | |
| 
 | |
|             SecapiPayRefundResult refundResult;
 | |
|             try {
 | |
|                 refundResult = PayMchAPI.secapiPayRefund(refund, WeChatConfig.MCH_KEY);
 | |
|                 if (refundResult == null) {
 | |
|                     throw new Exception(ResultEnum.INTERFACE_WX_INVOKE_ERROR.message);
 | |
|                 }
 | |
|             } catch (Exception e) {
 | |
|                 log.error("【微信】退款接口调用异常 outTradeNo={}", outTradeNo);
 | |
|                 order.setErrorMsg(ResultEnum.INTERFACE_WX_INVOKE_ERROR.message);
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             String code = refundResult.getReturn_code();
 | |
|             String message = refundResult.getReturn_msg();
 | |
|             String resultCode = refundResult.getResult_code();
 | |
|             if (!SUCCESS.equals(resultCode)) {
 | |
|                 String errCode = refundResult.getErr_code();
 | |
|                 String errCodeDesc = refundResult.getErr_code_des();
 | |
| 
 | |
|                 log.info("【微信】退款失败 code={}, message={}, resultCode={}, errCode={}, errCodeDesc={}", code, message, resultCode, errCode, errCodeDesc);
 | |
| 
 | |
|                 order.setErrorMsg(errCodeDesc);
 | |
|                 order.setRefundResult(errCodeDesc); // 退款失败信息记录
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             log.info("【微信】退款返回 code={}, message={}, resultCode={}", code, message, resultCode);
 | |
|             order.setRefundResult(message); // 退款信息记录
 | |
|             if (!OK.equals(message)) { // 退款失败
 | |
|                 order.setErrorMsg(ResultEnum.INTERFACE_WX_INVOKE_ERROR.message);
 | |
|                 return order;
 | |
|             }
 | |
|             order.setSuccess(true);
 | |
|             return order;
 | |
|         } catch (Exception e) {
 | |
|             ErrorHelper.println(e);
 | |
|             order.setErrorMsg(ResultEnum.INTERFACE_WX_INVOKE_ERROR.message);
 | |
|             String refundResult = order.getRefundResult();
 | |
|             order.setRefundResult(ObjectUtils.isEmpty(refundResult) ? order.getErrorMsg() : refundResult);
 | |
|             return order;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * 微信扫码盒子支付
 | |
|      *
 | |
|      * @param title      商品标题
 | |
|      * @param outTradeNo 商户订单号
 | |
|      * @param totalFee   总金额
 | |
|      * @param authCode   微信条码
 | |
|      * @param ip         ip地址
 | |
|      * @return 执行返回
 | |
|      */
 | |
|     public static Order payMicro(String title, String outTradeNo, BigDecimal totalFee, String authCode, String ip) {
 | |
|         Order order = new Order();
 | |
| 
 | |
|         if (StringUtils.isEmpty(outTradeNo) || StringUtils.isEmpty(authCode) || ip == null || totalFee == null) {
 | |
|             order.setErrorMsg("【微信】[盒子支付] 参数缺失");
 | |
|             return order;
 | |
|         }
 | |
| 
 | |
|         int totalFeeCents;
 | |
|         try {
 | |
|             totalFeeCents = totalFee.movePointRight(2).intValue();
 | |
| 
 | |
|             String appId = WeChatConfig.APP_ID;
 | |
|             String mchId = WeChatConfig.MCH_ID;
 | |
|             String mchKey = WeChatConfig.MCH_KEY;
 | |
|             String nonce = UUID.randomUUID().toString().replace("-", "");
 | |
| 
 | |
|             Micropay micropay = new Micropay();
 | |
|             micropay.setAppid(appId);
 | |
|             micropay.setMch_id(mchId);
 | |
|             micropay.setNonce_str(nonce); // 随机字符串
 | |
|             micropay.setOut_trade_no(outTradeNo); // 商户订单号
 | |
|             micropay.setBody(title);
 | |
|             micropay.setAuth_code(authCode);
 | |
|             micropay.setTotal_fee(totalFeeCents); // 金额分
 | |
|             micropay.setSpbill_create_ip(ip);
 | |
| 
 | |
|             //  micropay.setDetail("描述"); // 商品描述
 | |
| 
 | |
|             MicropayResult micropayResult = PayMchAPI.payMicropay(micropay, mchKey);
 | |
|             if (micropayResult == null) {
 | |
|                 order.setErrorMsg("【微信】盒子扫码支付请求失败");
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             log.info("【微信】[盒子支付]支付反馈 {}", JsonHelper.toJsonString(micropayResult));
 | |
| 
 | |
|             String openid = micropayResult.getOpenid();
 | |
|             String bankTransNo = micropayResult.getTransaction_id(); // 银行流水号
 | |
|             String resultCode = micropayResult.getResult_code();
 | |
|             String errMsg = micropayResult.getErr_code_des();
 | |
|             String errCode = micropayResult.getErr_code();
 | |
| 
 | |
|             order.setOpenid(openid);
 | |
|             order.setBankTransNo(bankTransNo);
 | |
| 
 | |
|             // 调用失败
 | |
|             if (FAIL.equals(micropayResult.getReturn_code())) { // 失败
 | |
|                 log.info("【微信】[盒子支付]失败 outTradeNo={}, bankTransNo={}, returnCode={}, returnMsg={}", outTradeNo, bankTransNo, micropayResult.getReturn_code(), micropayResult.getReturn_msg());
 | |
|                 order.setErrorCode(micropayResult.getReturn_code());
 | |
|                 order.setErrorMsg(micropayResult.getReturn_msg());
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             Order wxOrder;
 | |
|             if (FAIL.equals(resultCode)) { // 失败
 | |
|                 if (USER_PAYING.equals(errCode)) { // 密码支付
 | |
|                     log.info("【微信】[盒子支付]密码支付 outTradeNo={}, msg={}", outTradeNo, errMsg);
 | |
|                     for (int i = 1; i <= 5; i++) {
 | |
|                         try {
 | |
|                             Thread.sleep(5000 + ((i - 1) * 1500)); // 总共35s
 | |
|                             wxOrder = queryOrder(outTradeNo);
 | |
|                             if (wxOrder.isSuccess()) {
 | |
|                                 return wxOrder;
 | |
|                             }
 | |
| 
 | |
|                             // 支付失败
 | |
|                             if (PAY_ERROR.equals(wxOrder.getTradeState())) {
 | |
|                                 if (i == 1 || i == 2) {
 | |
|                                     Thread.sleep(i == 2 ? 3000 : 9000); // 等够15s
 | |
|                                 }
 | |
| 
 | |
|                                 // 撤销订单
 | |
|                                 Order cancelOrder = cancelOrder(wxOrder.getOutTradeNo(), wxOrder.getBankTransNo());
 | |
|                                 // 撤销成功
 | |
|                                 if (cancelOrder.isSuccess()) {
 | |
|                                     wxOrder.setTradeState(REVOKED);
 | |
|                                     wxOrder.setErrorMsg("订单已撤销");
 | |
|                                 }
 | |
|                                 return wxOrder;
 | |
|                             }
 | |
| 
 | |
|                             // 其他失败原因
 | |
|                             if (!USER_PAYING.equals(wxOrder.getTradeState())) {
 | |
|                                 return wxOrder;
 | |
|                             }
 | |
|                         } catch (Exception e) {
 | |
|                             e.printStackTrace();
 | |
|                         }
 | |
|                     }
 | |
|                 } else {
 | |
|                     order.setErrorCode(errCode);
 | |
|                     order.setErrorMsg(errMsg);
 | |
|                     log.info("【微信】[盒子支付]失败 outTradeNo={}, bankTransNo={}, errCode={}, errMsg={}", outTradeNo, bankTransNo, errCode, errMsg);
 | |
|                     return order;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // 免密支付
 | |
|             Thread.sleep(2000); // 2s
 | |
|             wxOrder = queryOrder(outTradeNo);
 | |
|             // 长时间未支付
 | |
|             if (USER_PAYING.equals(wxOrder.getTradeState()) || PAY_ERROR.equals(wxOrder.getTradeState())) {
 | |
|                 // 撤销订单
 | |
|                 Order cancelOrder = cancelOrder(wxOrder.getOutTradeNo(), wxOrder.getBankTransNo());
 | |
|                 // 撤销成功
 | |
|                 if (cancelOrder.isSuccess()) {
 | |
|                     wxOrder.setTradeState(REVOKED);
 | |
|                     wxOrder.setErrorMsg("订单已撤销");
 | |
|                 }
 | |
|             }
 | |
|             return wxOrder;
 | |
|         } catch (Exception e) {
 | |
|             log.info("【微信】[盒子支付]异常 {}", e.getMessage());
 | |
|             order.setErrorMsg("网络异常或当前不支持微信支付");
 | |
|             ErrorHelper.println(e);
 | |
|         }
 | |
|         return order;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 撤销订单
 | |
|      *
 | |
|      * @param outTradeNo  商户订单号
 | |
|      * @param bankTransNo 银行流水号
 | |
|      * @return 撤销
 | |
|      */
 | |
|     public static Order cancelOrder(String outTradeNo, String bankTransNo) {
 | |
|         log.info("【微信】撤销订单 outTradeNo={}, bankTransNo={}", outTradeNo, bankTransNo);
 | |
|         Order order = new Order();
 | |
|         try {
 | |
|             MchReverse mchReverse = new MchReverse();
 | |
|             String appId = WeChatConfig.APP_ID;
 | |
|             String mchId = WeChatConfig.MCH_ID;
 | |
|             String mchKey = WeChatConfig.MCH_KEY;
 | |
| 
 | |
|             mchReverse.setAppid(appId);
 | |
|             mchReverse.setMch_id(mchId);
 | |
|             mchReverse.setOut_trade_no(outTradeNo);
 | |
|             if (!ObjectUtils.isEmpty(bankTransNo)) {
 | |
|                 mchReverse.setTransaction_id(bankTransNo);
 | |
|             }
 | |
|             mchReverse.setNonce_str(CodeHelper.get32UUID());
 | |
|             mchReverse.setSign_type("MD5");
 | |
| 
 | |
|             MchReverseResult wxResult = PayMchAPI.secapiPayReverse(mchReverse, mchKey);
 | |
|             if (wxResult == null) {
 | |
|                 order.setErrorMsg("【微信】撤销订单失败");
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             // 调用错误
 | |
|             if (FAIL.equals(wxResult.getReturn_code())) {
 | |
|                 order.setErrorCode(wxResult.getReturn_code());
 | |
|                 order.setErrorMsg(wxResult.getReturn_msg());
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             // 业务错误
 | |
|             if (FAIL.equals(wxResult.getResult_code())) {
 | |
|                 order.setErrorCode(wxResult.getErr_code());
 | |
|                 order.setErrorMsg(wxResult.getErr_code_des());
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             // 交易成功
 | |
|             if (SUCCESS.equals(wxResult.getResult_code())) {
 | |
|                 order.setSuccess(true); // 订单支付成功(判断条件)
 | |
|             }
 | |
|         } catch (Exception e) {
 | |
|             ErrorHelper.println(e);
 | |
|             order.setErrorMsg("异常信息:" + e.getMessage());
 | |
|         }
 | |
|         return order;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * 查询退费订单集(含退费时间)
 | |
|      *
 | |
|      * @param outTradeNo 订单号
 | |
|      * @return 订单信息
 | |
|      */
 | |
|     public static List<Bill> queryRefundInfoList(String outTradeNo) throws ServiceException {
 | |
|         Refundquery refund = new Refundquery();
 | |
| 
 | |
|         refund.setAppid(WeChatConfig.APP_ID);
 | |
|         refund.setMch_id(WeChatConfig.MCH_ID);
 | |
|         refund.setOut_trade_no(outTradeNo);
 | |
|         refund.setNonce_str(CodeHelper.get32UUID());
 | |
| 
 | |
|         WxRefundQueryRoot wxResult = WxFactory.Base.Refund().refundQuery(refund, WeChatConfig.MCH_KEY);
 | |
|         if (wxResult == null) {
 | |
|             throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR);
 | |
|         }
 | |
| 
 | |
|         if (!SUCCESS.equals(wxResult.getReturn_code())) {
 | |
|             log.info("[微信]查询退款失败{}", wxResult.getReturn_msg());
 | |
|             throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR);
 | |
|         }
 | |
| 
 | |
|         List<Bill> billList = new ArrayList<>();
 | |
|         if (FAIL.equals(wxResult.getResult_code()) && "REFUNDNOTEXIST".equals(wxResult.getErr_code())) {
 | |
|             return billList;
 | |
|         }
 | |
| 
 | |
|         if (!SUCCESS.equals(wxResult.getResult_code())) {
 | |
|             throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR);
 | |
|         }
 | |
| 
 | |
| 
 | |
|         List<WxRefundItem> refundOrderList = wxResult.getItems();
 | |
|         if (refundOrderList == null || refundOrderList.size() == 0) {
 | |
|             return billList;
 | |
|         }
 | |
| 
 | |
|         BigDecimal totalFee = new BigDecimal(wxResult.getTotal_fee()).movePointLeft(2);
 | |
| 
 | |
|         Bill bill;
 | |
|         String refundStatus;
 | |
|         for (WxRefundItem item : refundOrderList) {
 | |
|             refundStatus = item.getRefund_status();
 | |
|             if (SUCCESS.equals(refundStatus)) {
 | |
|                 bill = new Bill();
 | |
|                 bill.setTotalFee(totalFee);
 | |
|                 bill.setMoney(new BigDecimal(item.getRefund_fee()).movePointLeft(2));
 | |
|                 bill.setRefundId(item.getRefund_id());
 | |
|                 bill.setOutRefundNo(item.getOut_refund_no());
 | |
|                 bill.setRefundChannel(item.getRefund_channel());
 | |
|                 bill.setRefundRecvAccout(item.getRefund_recv_accout());
 | |
|                 bill.setRefundTime(item.getRefund_success_time());
 | |
| 
 | |
|                 billList.add(bill);
 | |
|             }
 | |
|         }
 | |
|         return billList;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * 查询订单
 | |
|      *
 | |
|      * @param outTradeNo 订单号
 | |
|      * @return 订单信息
 | |
|      */
 | |
|     public static List<Bill> queryRefundList(String outTradeNo) throws ServiceException {
 | |
|         Refundquery refund = new Refundquery();
 | |
| 
 | |
|         refund.setAppid(WeChatConfig.APP_ID);
 | |
|         refund.setMch_id(WeChatConfig.MCH_ID);
 | |
|         refund.setOut_trade_no(outTradeNo);
 | |
|         refund.setNonce_str(CodeHelper.get32UUID());
 | |
| 
 | |
|         RefundqueryResult wxResult = payRefundquery(refund, WeChatConfig.MCH_KEY);
 | |
|         if (wxResult == null) {
 | |
|             throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR);
 | |
|         }
 | |
| 
 | |
|         if (!SUCCESS.equals(wxResult.getReturn_code())) {
 | |
|             log.info("[微信]查询退款失败{}", wxResult.getReturn_msg());
 | |
|             throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR);
 | |
|         }
 | |
| 
 | |
|         List<Bill> billList = new ArrayList<>();
 | |
|         if (FAIL.equals(wxResult.getResult_code()) && "REFUNDNOTEXIST".equals(wxResult.getErr_code())) {
 | |
|             return billList;
 | |
|         }
 | |
| 
 | |
|         if (!SUCCESS.equals(wxResult.getResult_code())) {
 | |
|             throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR);
 | |
|         }
 | |
| 
 | |
|         List<RefundqueryResultItem> refundOrderList = wxResult.getRefundqueryResultItems();
 | |
|         if (refundOrderList == null || refundOrderList.size() == 0) {
 | |
|             return billList;
 | |
|         }
 | |
|         BigDecimal totalFee = new BigDecimal(wxResult.getTotal_fee()).movePointLeft(2);
 | |
| 
 | |
|         Bill bill;
 | |
|         String refundStatus;
 | |
|         for (RefundqueryResultItem item : refundOrderList) {
 | |
|             refundStatus = item.getRefund_status();
 | |
|             if (SUCCESS.equals(refundStatus)) {
 | |
|                 bill = new Bill();
 | |
|                 bill.setTotalFee(totalFee);
 | |
|                 bill.setMoney(new BigDecimal(item.getRefund_fee()).movePointLeft(2));
 | |
|                 bill.setRefundId(item.getRefund_id());
 | |
|                 bill.setOutRefundNo(item.getOut_refund_no());
 | |
|                 bill.setRefundChannel(item.getRefund_channel());
 | |
|                 bill.setRefundRecvAccout(item.getRefund_recv_accout());
 | |
| 
 | |
|                 billList.add(bill);
 | |
|             }
 | |
|         }
 | |
|         return billList;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * 查询退费订单
 | |
|      *
 | |
|      * @param outTradeNo 订单号
 | |
|      * @return 订单信息
 | |
|      */
 | |
|     public static Bill queryRefund(String outTradeNo, String outRefundNo) throws ServiceException {
 | |
|         if (ObjectUtils.isEmpty(outTradeNo) || ObjectUtils.isEmpty(outRefundNo)) {
 | |
|             throw new ServiceException(ResultEnum.PARAM_IS_DEFECT);
 | |
|         }
 | |
|         List<Bill> billList = queryRefundList(outTradeNo);
 | |
|         if (billList.size() == 0) {
 | |
|             return null;
 | |
|         }
 | |
|         for (Bill bill : billList) {
 | |
|             if (outRefundNo.equals(bill.getOutRefundNo())) {
 | |
|                 return bill;
 | |
|             }
 | |
|         }
 | |
|         return null;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 查询订单
 | |
|      *
 | |
|      * @param outTradeNo 订单号
 | |
|      * @return 订单信息
 | |
|      */
 | |
|     public static Order queryOrder(String outTradeNo) {
 | |
|         Order order = new Order();
 | |
|         order.setOutTradeNo(outTradeNo);
 | |
|         try {
 | |
|             MchOrderquery mchOrderquery = new MchOrderquery();
 | |
|             String appId = WeChatConfig.APP_ID;
 | |
|             String mchId = WeChatConfig.MCH_ID;
 | |
|             String mchKey = WeChatConfig.MCH_KEY;
 | |
| 
 | |
|             mchOrderquery.setAppid(appId);
 | |
|             mchOrderquery.setMch_id(mchId);
 | |
|             mchOrderquery.setOut_trade_no(outTradeNo);
 | |
|             mchOrderquery.setNonce_str(CodeHelper.get32UUID());
 | |
| 
 | |
|             MchOrderInfoResult wxResult = PayMchAPI.payOrderquery(mchOrderquery, mchKey);
 | |
|             if (wxResult == null) {
 | |
|                 order.setErrorMsg("【微信】查询订单失败");
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             // 调用错误
 | |
|             if (FAIL.equals(wxResult.getReturn_code())) {
 | |
|                 order.setErrorCode(wxResult.getReturn_code());
 | |
|                 order.setErrorMsg(wxResult.getReturn_msg());
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             // 业务错误
 | |
|             if (FAIL.equals(wxResult.getResult_code())) {
 | |
|                 order.setErrorCode(wxResult.getErr_code());
 | |
|                 order.setErrorMsg(wxResult.getErr_code_des());
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             String tradeState = wxResult.getTrade_state();
 | |
|             order.setTradeState(tradeState);
 | |
| 
 | |
|             if (SUCCESS.equals(tradeState)) {
 | |
|                 order.setSuccess(true); // 订单支付成功(判断条件)
 | |
| 
 | |
|             } else if (REFUND.equals(tradeState)) {
 | |
|                 order.setErrorMsg(wxResult.getTrade_state_desc());
 | |
|                 order.setRefund(true); // 订单发生过退款
 | |
|             } else {
 | |
|                 // 交易错误
 | |
|                 order.setErrorCode(tradeState);
 | |
|                 order.setErrorMsg(wxResult.getTrade_state_desc());
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             // 交易成功
 | |
|             order.setOpenid(wxResult.getOpenid());
 | |
|             order.setBankTransNo(wxResult.getTransaction_id());
 | |
|             Integer totalFee = wxResult.getTotal_fee();
 | |
|             if (totalFee != null) {
 | |
|                 order.setTotalFee(new BigDecimal(totalFee).movePointLeft(2));
 | |
|             }
 | |
|         } catch (Exception e) {
 | |
|             ErrorHelper.println(e);
 | |
|             order.setErrorMsg("异常信息:" + e.getMessage());
 | |
|         }
 | |
|         return order;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * 查询订单
 | |
|      *
 | |
|      * @param transId 支付单号
 | |
|      * @return 订单信息
 | |
|      */
 | |
|     public static Order queryOrderByTransId(String transId) {
 | |
|         Order order = new Order();
 | |
|         order.setBankTransNo(transId);
 | |
|         try {
 | |
|             MchOrderquery mchOrderquery = new MchOrderquery();
 | |
| 
 | |
|             mchOrderquery.setAppid(WeChatConfig.APP_ID);
 | |
|             mchOrderquery.setMch_id(WeChatConfig.MCH_ID);
 | |
|             mchOrderquery.setTransaction_id(transId);
 | |
|             mchOrderquery.setNonce_str(CodeHelper.get32UUID());
 | |
| 
 | |
|             MchOrderInfoResult wxResult = PayMchAPI.payOrderquery(mchOrderquery, WeChatConfig.MCH_KEY);
 | |
|             if (wxResult == null) {
 | |
|                 order.setErrorMsg("【微信】查询订单失败");
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             // 调用错误
 | |
|             if (FAIL.equals(wxResult.getReturn_code())) {
 | |
|                 order.setErrorCode(wxResult.getReturn_code());
 | |
|                 order.setErrorMsg(wxResult.getReturn_msg());
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             // 业务错误
 | |
|             if (FAIL.equals(wxResult.getResult_code())) {
 | |
|                 order.setErrorCode(wxResult.getErr_code());
 | |
|                 order.setErrorMsg(wxResult.getErr_code_des());
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             String tradeState = wxResult.getTrade_state();
 | |
|             order.setTradeState(tradeState);
 | |
| 
 | |
|             if (SUCCESS.equals(tradeState)) {
 | |
|                 order.setSuccess(true); // 订单支付成功(判断条件)
 | |
| 
 | |
|             } else if (REFUND.equals(tradeState)) {
 | |
|                 order.setErrorMsg(wxResult.getTrade_state_desc());
 | |
|                 order.setRefund(true); // 订单发生过退款
 | |
|             } else {
 | |
|                 // 交易错误
 | |
|                 order.setErrorCode(tradeState);
 | |
|                 order.setErrorMsg(wxResult.getTrade_state_desc());
 | |
|                 return order;
 | |
|             }
 | |
| 
 | |
|             // 交易成功
 | |
|             order.setOpenid(wxResult.getOpenid());
 | |
|             order.setBankTransNo(wxResult.getTransaction_id());
 | |
|             Integer totalFee = wxResult.getTotal_fee();
 | |
|             if (totalFee != null) {
 | |
|                 order.setTotalFee(new BigDecimal(totalFee).movePointLeft(2));
 | |
|             }
 | |
|         } catch (Exception e) {
 | |
|             ErrorHelper.println(e);
 | |
|             order.setErrorMsg("异常信息:" + e.getMessage());
 | |
|         }
 | |
|         return order;
 | |
|     }
 | |
| 
 | |
| 
 | |
| //
 | |
| //    /**
 | |
| //     * 通知成功
 | |
| //     *
 | |
| //     * @param response 响应流
 | |
| //     */
 | |
| //    public static void notifySuccess(HttpServletResponse response) {
 | |
| //        notifyEnd(response, "SUCCESS", "");
 | |
| //    }
 | |
| //
 | |
| //    public static void notifyEnd(HttpServletResponse response, String returnCode, String returnMsg) {
 | |
| //        try (PrintWriter writer = response.getWriter()) {
 | |
| //            String xml = "<xml><return_code><![CDATA[" + returnCode + "]]></return_code><return_msg><![CDATA[" + returnMsg + "]]></return_msg></xml>"
 | |
| //            writer.write(xml);
 | |
| //            writer.flush();
 | |
| //        } catch (Exception e) {
 | |
| //            e.printStackTrace();
 | |
| //            ErrorHelper.println(e);
 | |
| //        }
 | |
| //    }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * 查询商户账单
 | |
|      *
 | |
|      * @return 订单信息
 | |
|      */
 | |
|     public static List<Bill> queryBill(String billType, String billDate, boolean isCompose) throws ServiceException {
 | |
|         List<Bill> billList = new ArrayList<>();
 | |
|         String data = downWxBillData(billType, billDate);
 | |
|         String[] dataArr = data.split("\\n");
 | |
|         if (dataArr.length == 0) {
 | |
|             return billList;
 | |
|         }
 | |
| 
 | |
|         int index;
 | |
|         Bill billItem;
 | |
|         String money;
 | |
|         String outRefundNo;
 | |
|         String[] titleArr = dataArr[0].split(",");
 | |
|         if (titleArr.length == 0) {
 | |
|             return billList;
 | |
|         }
 | |
| 
 | |
|         String[] item;
 | |
|         String tradeState;
 | |
|         for (int i = 1; i < (dataArr.length - 2); i++) {
 | |
|             item = dataArr[i].split(","); //27
 | |
|             billItem = new Bill();
 | |
|             billItem.setTradeTime(dataHandle(item[0]));
 | |
|             billItem.setOutTradeNo(dataHandle(item[6]));
 | |
|             billItem.setBankTransNo(dataHandle(item[5]));
 | |
| //            billItem.setOpenid(dataHandle(item[7]));
 | |
| //            billItem.setPayType(dataHandle(item[8]));
 | |
|             tradeState = dataHandle(item[9]);
 | |
|             billItem.setTradeState(tradeState);
 | |
|             if (WxPayHelper.REFUND.equals(tradeState)) { // 退款
 | |
|                 index = findIndex(titleArr, "退款金额");
 | |
|                 if (index != -1) {
 | |
|                     money = dataHandle(item[index]);
 | |
|                     if (money != null) {
 | |
|                         billItem.setMoney(new BigDecimal(money).negate());
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 index = findIndex(titleArr, "商户退款单号");
 | |
|                 if (index != -1) {
 | |
|                     outRefundNo = dataHandle(item[index]);
 | |
|                     if (outRefundNo != null) {
 | |
|                         billItem.setOutRefundNo(outRefundNo);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
| //                    index = findIndex(titleArr, "退款类型");
 | |
| //                    if (index != -1) {
 | |
| //                        order.setRefundType(dataHandle(item[index]));
 | |
| //                    }
 | |
| //
 | |
| //                    index = findIndex(titleArr, "退款状态");
 | |
| //                    if (index != -1) {
 | |
| //                        order.setRefundResult(dataHandle(item[index]));
 | |
| //                    }
 | |
| 
 | |
|             } else if (WxPayHelper.SUCCESS.equals(tradeState)) { // 成功
 | |
|                 index = findIndex(titleArr, "应结订单金额");
 | |
|                 if (index != -1) {
 | |
|                     money = dataHandle(item[index]);
 | |
|                     if (money != null) {
 | |
|                         billItem.setMoney(new BigDecimal(money));
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             billList.add(billItem);
 | |
|         }
 | |
| 
 | |
|         if (ALL.equals(billType) && isCompose) {
 | |
|             List<Bill> refundList = billList.stream().filter(o -> REFUND.equals(o.getTradeState())).collect(Collectors.toList());
 | |
|             List<Bill> successList = billList.stream().filter(o -> SUCCESS.equals(o.getTradeState())).collect(Collectors.toList());
 | |
| 
 | |
|             String outTradeNo;
 | |
|             for (Bill refundItem : refundList) {
 | |
|                 outTradeNo = refundItem.getOutTradeNo();
 | |
|                 for (Bill successItem : successList) {
 | |
|                     if (outTradeNo.equals(successItem.getOutTradeNo())) {
 | |
|                         if (successItem.getHisBills() == null) {
 | |
|                             successItem.setRefundBills(new ArrayList<>());
 | |
|                         }
 | |
|                         refundItem.setBankTransNo(null);
 | |
|                         refundItem.setOutTradeNo(null);
 | |
|                         successItem.getRefundBills().add(refundItem);
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return successList;
 | |
|         }
 | |
|         return billList;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     public synchronized static String downWxBillData(String billType, String date) throws ServiceException {
 | |
|         if (!DateHelper.isValidDate(date, DateHelper.DateEnum.yyyy_MM_dd)) {
 | |
|             throw new ServiceException(ResultEnum.PARAM_DATE_ERROR);
 | |
|         }
 | |
|         Date dateTime = DateHelper.strToDate(date, DateHelper.DateEnum.yyyy_MM_dd);
 | |
|         if (dateTime == null) {
 | |
|             throw new ServiceException(ResultEnum.PARAM_DATE_ERROR);
 | |
|         }
 | |
|         date = DateHelper.dateToStr(dateTime, DateHelper.DateEnum.yyyyMMdd);
 | |
|         if (date == null) {
 | |
|             throw new ServiceException(ResultEnum.PARAM_DATE_ERROR);
 | |
|         }
 | |
| 
 | |
|         if (!ALL.equals(billType) && !REFUND.equals(billType) && !SUCCESS.equals(billType)) {
 | |
|             throw new ServiceException(ResultEnum.PARAM_IS_INVALID);
 | |
|         }
 | |
| 
 | |
|         MchDownloadbill mchDownloadbill = new MchDownloadbill();
 | |
|         mchDownloadbill.setAppid(WeChatConfig.APP_ID);
 | |
|         mchDownloadbill.setMch_id(WeChatConfig.MCH_ID);
 | |
|         mchDownloadbill.setNonce_str(CodeHelper.get32UUID());
 | |
|         mchDownloadbill.setBill_date(date);
 | |
|         mchDownloadbill.setBill_type(billType);
 | |
|         DownloadbillResult downloadbillResult = PayMchAPI.payDownloadbill(mchDownloadbill, WeChatConfig.MCH_KEY);
 | |
| 
 | |
|         if (downloadbillResult == null) {
 | |
|             throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR);
 | |
|         }
 | |
|         String code = downloadbillResult.getReturn_code();
 | |
|         String msg = downloadbillResult.getReturn_msg();
 | |
|         if (FAIL.equals(code)) {
 | |
|             if ("invalid bill_date".equals(msg)) {
 | |
|                 throw new ServiceException("日期无效,或超过账单的可查询日期范围[invalid bill_date]");
 | |
|             }
 | |
|             log.info("[微信]下载对账单错误[{}][{}]", code, msg);
 | |
|             throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR.message + "[" + msg + "]");
 | |
|         }
 | |
|         String data = downloadbillResult.getData();
 | |
|         if (ObjectUtils.isEmpty(data)) {
 | |
|             throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR);
 | |
|         }
 | |
|         return data;
 | |
|     }
 | |
| 
 | |
| //
 | |
| //    /**
 | |
| //     * 查询商户账单
 | |
| //     *
 | |
| //     * @return 订单信息
 | |
| //     */
 | |
| //    public static List<Bill> queryBill(String billType, String date) throws ServiceException {
 | |
| //        List<Bill> billList = new ArrayList<>();
 | |
| //        if (!DateHelper.isValidDate(date, DateHelper.DateEnum.yyyy_MM_dd)) {
 | |
| //            throw new ServiceException(ResultEnum.PARAM_DATE_ERROR);
 | |
| //        }
 | |
| //
 | |
| //        Date dateTime = DateHelper.strToDate(date, DateHelper.DateEnum.yyyy_MM_dd);
 | |
| //        if (dateTime == null) {
 | |
| //            throw new ServiceException(ResultEnum.PARAM_DATE_ERROR);
 | |
| //        }
 | |
| //        date = DateHelper.dateToStr(dateTime, DateHelper.DateEnum.yyyyMMdd);
 | |
| //        if (date == null) {
 | |
| //            throw new ServiceException(ResultEnum.PARAM_DATE_ERROR);
 | |
| //        }
 | |
| //
 | |
| //        if (!ALL.equals(billType) && !REFUND.equals(billType) && !SUCCESS.equals(billType)) {
 | |
| //            throw new ServiceException(ResultEnum.PARAM_IS_INVALID);
 | |
| //        }
 | |
| //
 | |
| //        MchDownloadbill mchDownloadbill = new MchDownloadbill();
 | |
| //        String appId = WeChatConfig.getAppId();
 | |
| //        String mchId = WeChatConfig.getMchId();
 | |
| //        String mchKey = WeChatConfig.getMchKey();
 | |
| //
 | |
| //        mchDownloadbill.setAppid(appId);
 | |
| //        mchDownloadbill.setMch_id(mchId);
 | |
| //        mchDownloadbill.setNonce_str(CodeHelper.get32UUID());
 | |
| //        mchDownloadbill.setBill_date(date);
 | |
| //        mchDownloadbill.setBill_type(billType);
 | |
| //        DownloadbillResult downloadbillResult = PayMchAPI.payDownloadbill(mchDownloadbill, mchKey);
 | |
| //
 | |
| //        if (downloadbillResult == null) {
 | |
| //            throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR);
 | |
| //        }
 | |
| //
 | |
| //        String data = downloadbillResult.getData();
 | |
| //        if (data == null) {
 | |
| //            throw new ServiceException(ResultEnum.INTERFACE_WX_INVOKE_ERROR);
 | |
| //        }
 | |
| //        String[] dataArr = data.split("\\n");
 | |
| //        if (dataArr.length == 0) {
 | |
| //            return billList;
 | |
| //        }
 | |
| //
 | |
| //        int index;
 | |
| //        Bill billItem;
 | |
| //        String money;
 | |
| //        String[] titleArr = dataArr[0].split(",");
 | |
| //        if (titleArr.length == 0) {
 | |
| //            return billList;
 | |
| //        }
 | |
| //
 | |
| //        System.out.println(JSONArray.toJSONString(titleArr));
 | |
| //        for (int i = 1; i < (dataArr.length - 2); i++) {
 | |
| //            String[] item = dataArr[i].split(","); //27
 | |
| //            System.out.println(JSONArray.toJSONString(item));
 | |
| //            billItem = new Bill();
 | |
| //            billItem.setTradeTime(dataHandle(item[0]));
 | |
| //            billItem.setOutTradeNo(dataHandle(item[6]));
 | |
| //            billItem.setBankTransNo(dataHandle(item[5]));
 | |
| ////            billItem.setOpenid(dataHandle(item[7]));
 | |
| ////            billItem.setPayType(dataHandle(item[8]));
 | |
| //            String tradeState = dataHandle(item[9]);
 | |
| //            billItem.setTradeState(tradeState);
 | |
| //            if (WxPayHelper.REFUND.equals(tradeState)) { // 退款
 | |
| //                index = findIndex(titleArr, "退款金额");
 | |
| //                if (index != -1) {
 | |
| //                    money = dataHandle(item[index]);
 | |
| //                    if (money != null) {
 | |
| //                        billItem.setMoney(new BigDecimal(money).negate());
 | |
| //                    }
 | |
| //                }
 | |
| //
 | |
| ////                    index = findIndex(titleArr, "退款类型");
 | |
| ////                    if (index != -1) {
 | |
| ////                        order.setRefundType(dataHandle(item[index]));
 | |
| ////                    }
 | |
| ////
 | |
| ////                    index = findIndex(titleArr, "退款状态");
 | |
| ////                    if (index != -1) {
 | |
| ////                        order.setRefundResult(dataHandle(item[index]));
 | |
| ////                    }
 | |
| //
 | |
| //            } else if (WxPayHelper.SUCCESS.equals(tradeState)) { // 成功
 | |
| //                index = findIndex(titleArr, "应结订单金额");
 | |
| //                if (index != -1) {
 | |
| //                    money = dataHandle(item[index]);
 | |
| //                    if (money != null) {
 | |
| //                        billItem.setMoney(new BigDecimal(money));
 | |
| //                    }
 | |
| //                }
 | |
| //            }
 | |
| //            billList.add(billItem);
 | |
| //        }
 | |
| //        return billList;
 | |
| //    }
 | |
| 
 | |
| //    /**
 | |
| //     * 微信支付调用及通知
 | |
| //     *
 | |
| //     * @param request  请求
 | |
| //     * @param response 响应
 | |
| //     * @return 微信支付信息
 | |
| //     */
 | |
| //    public static PayResult oldPayNotify(HttpServletRequest request, HttpServletResponse response) {
 | |
| //        PayResult orderInfo = null;
 | |
| //        InputStream in = null;
 | |
| //        OutputStream out = null;
 | |
| //        try {
 | |
| //            in = request.getInputStream();
 | |
| //            out = response.getOutputStream();
 | |
| //
 | |
| //            // 获取请求数据
 | |
| //            String wxXmlData = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
 | |
| //
 | |
| //            // 转换数据对象
 | |
| //            MchPayNotify wxPayNotify = XMLConverUtil.convertToObject(MchPayNotify.class, wxXmlData);
 | |
| //            String openid = wxPayNotify.getOpenid();
 | |
| //            String outTradeNo = wxPayNotify.getOut_trade_no();
 | |
| //            String bankTransNo = wxPayNotify.getTransaction_id();
 | |
| //            Integer totalFee = wxPayNotify.getTotal_fee(); // 金额
 | |
| //            String timeEnd = wxPayNotify.getTime_end();
 | |
| //            String attach = wxPayNotify.getAttach();
 | |
| //
 | |
| //            if (openid == null || outTradeNo == null || timeEnd == null || bankTransNo == null) {
 | |
| //                log.info("【微信】下单信息返回错误 outTradeNo={}", outTradeNo);
 | |
| //                payNotifyError(out);
 | |
| //                return null;
 | |
| //            }
 | |
| //
 | |
| //            // 已处理 去重
 | |
| //            if (KEYS.isContainsKey(bankTransNo)) {
 | |
| //                log.info("【微信】[重复请求]下单信息去重 outTradeNo={}", outTradeNo);
 | |
| //                payNotifySuccess(out);
 | |
| //                return null;
 | |
| //            }
 | |
| //
 | |
| //            // 将XML转为MAP,确保所有字段都参与签名验证
 | |
| //            Map<String, String> wxMapData = XMLConverUtil.convertToMap(wxXmlData);
 | |
| //            StringBuilder wxPayInfo = new StringBuilder();
 | |
| //            for (String key : wxMapData.keySet()) {
 | |
| //                wxPayInfo.append(key).append("=").append(wxMapData.get(key)).append(";"); // 拼接微信返回的信息
 | |
| //            }
 | |
| //
 | |
| //            // @since 2.8.5
 | |
| //            wxPayNotify.buildDynamicField(wxMapData);
 | |
| //            // 签名验证
 | |
| //            if (!SignatureUtil.validateSign(wxMapData, WeChatConfig.MCH_KEY)) { // 验证未通过,通知支付失败
 | |
| //                log.info("【微信】签名验证未通过,通知支付失败!");
 | |
| //                payNotifyError(out);
 | |
| //                return null;
 | |
| //            }
 | |
| //
 | |
| //            // 验证通过
 | |
| //            payNotifySuccess(out);
 | |
| //
 | |
| //            // 保存支付结果
 | |
| //            orderInfo = new PayResult();
 | |
| //            orderInfo.setOpenid(openid);
 | |
| //            orderInfo.setOutTradeNo(outTradeNo);
 | |
| //            orderInfo.setTimeEnd(timeEnd);
 | |
| //            orderInfo.setTotalFee(new BigDecimal(totalFee).movePointLeft(2));
 | |
| //            orderInfo.setTransId(bankTransNo);
 | |
| //            orderInfo.setInfo(wxPayInfo.toString());
 | |
| //            orderInfo.setAttach(attach);
 | |
| //
 | |
| //        } catch (Exception e) {
 | |
| //            log.info("【微信】支付通知异常:" + e.getMessage());
 | |
| //            payNotifySuccess(out);
 | |
| //            ErrorHelper.println(e);
 | |
| //        } finally {
 | |
| //            try {
 | |
| //                if (in != null) in.close();
 | |
| //
 | |
| //                if (out != null) {
 | |
| //                    if (orderInfo == null) {
 | |
| //                        payNotifySuccess(out);
 | |
| //                    }
 | |
| //                    out.flush();
 | |
| //                    out.close();
 | |
| //                }
 | |
| //            } catch (Exception e) {
 | |
| //                ErrorHelper.println(e);
 | |
| //            }
 | |
| //        }
 | |
| //        return orderInfo;
 | |
| //    }
 | |
| 
 | |
|     /**
 | |
|      * 商户创建订单
 | |
|      *
 | |
|      * @param merchantEnum 枚举
 | |
|      * @param title        商品标题
 | |
|      * @param totalFee     订单金额
 | |
|      * @param outTradeNo   订单号
 | |
|      * @param notifyType   回调类型
 | |
|      * @param ip           ip地址
 | |
|      * @return 成功返回 json, 否则返回null
 | |
|      */
 | |
|     public static String createNativeOrder(MerchantEnum merchantEnum, String title, BigDecimal totalFee, String outTradeNo, String notifyType, String ip) {
 | |
|         try {
 | |
|             if (ObjectUtils.isEmpty(outTradeNo) || merchantEnum == null || totalFee == null || notifyType == null) {
 | |
|                 log.info("【微信】下单参数缺失");
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             // 金额转换
 | |
|             String cents;
 | |
|             try {
 | |
|                 cents = totalFee.movePointRight(2).toString(); // 单位分
 | |
|             } catch (Exception e) {
 | |
|                 ErrorHelper.println(e);
 | |
|                 log.info("【微信】统一下单金额转换异常");
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             String appId = WeChatConfig.APP_ID;
 | |
|             String mchId = WeChatConfig.MCH_ID;
 | |
|             String mchKey = WeChatConfig.MCH_KEY;
 | |
|             String nonce = UUID.randomUUID().toString().replace("-", "");
 | |
| 
 | |
|             Unifiedorder unifiedorder = new Unifiedorder();
 | |
|             unifiedorder.setAppid(appId);
 | |
|             unifiedorder.setMch_id(mchId);
 | |
|             unifiedorder.setNonce_str(nonce);
 | |
|             unifiedorder.setOut_trade_no(outTradeNo);
 | |
|             unifiedorder.setBody(title);
 | |
| 
 | |
|             unifiedorder.setTotal_fee(cents); // 金额分
 | |
|             unifiedorder.setSpbill_create_ip(ip);
 | |
|             unifiedorder.setNotify_url(WeChatConfig.getBaseUrl() + merchantEnum.QR_NOTIFY_URL);
 | |
|             unifiedorder.setTrade_type("NATIVE");
 | |
|             // 额外参数
 | |
|             unifiedorder.setAttach(notifyType);
 | |
| 
 | |
|             log.info(appId + ","
 | |
|                     + mchId + ","
 | |
|                     + nonce + ","
 | |
|                     + title + ","
 | |
|                     + outTradeNo + ","
 | |
|                     + totalFee + ","
 | |
|                     + ip + ","
 | |
|                     + merchantEnum.NOTIFY_URL);
 | |
| 
 | |
|             // 微信统一下单
 | |
|             UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder, mchKey);
 | |
|             log.info("【微信】统一下单返回:{}", JsonHelper.toJsonString(unifiedorderResult));
 | |
|             if (unifiedorderResult == null) {
 | |
|                 log.info("【微信】统一下单失败");
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             String result_code = unifiedorderResult.getResult_code();
 | |
|             // 下单是否成功
 | |
|             Boolean sign_status = unifiedorderResult.getSign_status();
 | |
|             if (!SUCCESS.equals(result_code) || sign_status == null || !sign_status) {
 | |
|                 log.info("【微信】统一下单返回异常信息:sign_status={}, err_code=[ {} ], err_code_des=[ {} ]", sign_status, unifiedorderResult.getErr_code(), unifiedorderResult.getErr_code_des());
 | |
|                 return null;
 | |
|             }
 | |
|             String codeUrl = unifiedorderResult.getCode_url();
 | |
|             log.info("codeUrl={}", codeUrl);
 | |
|             if (codeUrl != null) {
 | |
|                 return codeUrl;
 | |
|             }
 | |
|         } catch (Exception e) {
 | |
|             log.error("【微信】统一下单异常信息:" + e.getMessage());
 | |
|             ErrorHelper.println(e);
 | |
|         }
 | |
|         return null;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     public static String dataHandle(String data) {
 | |
|         if (ObjectUtils.isEmpty(data)) {
 | |
|             return null;
 | |
|         }
 | |
|         return data.substring(1);
 | |
|     }
 | |
| 
 | |
|     public static int findIndex(String[] titleArr, String title) {
 | |
|         if (titleArr == null || titleArr.length == 0) {
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         for (int i = 0; i < titleArr.length; i++) {
 | |
|             if (title.equals(titleArr[i])) {
 | |
|                 return i;
 | |
|             }
 | |
|         }
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
| 
 | |
| }
 | |
| 
 |