package com.subscription.restful.service; import java.math.BigDecimal; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate; import com.alibaba.fastjson.JSON; import com.cku.core.RESTResponse; import com.cku.core.ResultDto; import com.cku.core.ZAErrorCode; import com.cku.core.ZAException; import com.cku.oa.finance.dao.PaymentOrderDao; import com.cku.oa.finance.entity.PaymentOrder; import com.cku.oa.finance.entity.PaymentPayLog; import com.cku.oa.finance.service.PaymentOrderService; import com.cku.oa.finance.service.PaymentPayLogService; import com.cku.restful.v1.finance.service.RestOrderService; import com.github.wxpay.sdk.WXPay; import com.github.wxpay.sdk.WXPayConstants.SignType; import com.github.wxpay.sdk.WXPayUtil; import com.subscription.restful.utils.MyWXPayConfig; import com.thinkgem.jeesite.common.config.Global; import net.sf.json.JSONObject; @Service @Transactional(readOnly = true) public class WXpayServiceImpl { private static final Logger logger = LoggerFactory.getLogger(WXpayServiceImpl.class); @Autowired private RestTemplate restTemplate; @Autowired private MyWXPayConfig wxPayConfig; @Autowired private PaymentOrderDao paymentOrderDao; @Autowired private PaymentOrderService paymentOrderService; @Autowired private PaymentPayLogService paymentPayLogService; @Autowired private RestOrderService restOrderService; /** * 第一步、根据前端传入的URL生产签名数据,拉起支付使用 * * @param url * @return * @throws Exception */ public JSONObject getTicket(String url) throws Exception { String URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + wxPayConfig.getAppID() + "&secret=" + wxPayConfig.getKey(); logger.debug("@@@@@@URL" + URL); String t = restTemplate.getForEntity(URL, String.class).getBody(); logger.debug("@@@@@@t" + t); HashMap tmap = JSON.parseObject(t, HashMap.class); String URL2 = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + tmap.get("access_token") + "&type=jsapi"; logger.debug("@@@@@@URL2" + URL2); String body = restTemplate.getForEntity(URL2, String.class).getBody(); logger.debug("@@@@@@body" + body); HashMap map = JSON.parseObject(body, HashMap.class); if (StringUtils.isBlank(map.get("ticket"))) { throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "获取票据失败!"); } String noncestr = WXPayUtil.generateNonceStr(); String timestamp = String.valueOf(System.currentTimeMillis()).toString().substring(0, 10); StringBuilder sb = new StringBuilder("jsapi_ticket="); sb.append(map.get("ticket")); sb.append("&noncestr="); sb.append(noncestr); sb.append("×tamp="); sb.append(timestamp); sb.append("&url="); sb.append(url); JSONObject jsonObject = new JSONObject(); jsonObject.put("appId", wxPayConfig.getAppID()); jsonObject.put("noncestr", noncestr); jsonObject.put("timestamp", timestamp); jsonObject.put("signature", DigestUtils.sha1Hex(sb.toString())); return jsonObject; } /** * 第二步 新建微信付款单 * * @param orderId * @param userIp * @param openId * @return * @throws Exception */ @Transactional(readOnly = false) public RESTResponse createPayOrder(String orderId, String userIp, String openId) throws Exception { // 1、查询订单 获取金额 PaymentOrder order = paymentOrderDao.get(orderId); if (order == null) { throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "订单ID错误!"); } if ("1".equals(order.getDelFlag())) { throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "该订单已删除,请勿支付"); } if ("2".equals(order.getPaymentState())) { throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "订单已经支付!"); } // 2、记录支付记录,并修改订单支付状态 paymentPayLogService.savePayLog(order.getId(), "24"); // 3、调用微信接口下支付单 Map map = getPrepayId(order.getId(), new BigDecimal(order.getTotalPrice()), userIp, openId); return new RESTResponse(JSONObject.fromObject(map)); } public Map getPrepayId(String outTradeNo, BigDecimal totalAmount, String userIp, String openId) throws Exception { if (StringUtils.isBlank(openId)) { throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "openId 为空!"); } if (StringUtils.isBlank(userIp)) { throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "userIp 为空!"); } Map reqData = new HashMap<>(); reqData.put("body", "CKU业务订单支付"); reqData.put("out_trade_no", outTradeNo); // 方便测试 if (Global.isProductMode()) { reqData.put("total_fee", String.valueOf( totalAmount.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).intValue())); } else { reqData.put("total_fee", "1"); } reqData.put("spbill_create_ip", userIp); reqData.put("notify_url", wxPayConfig.getPayNotifyUrl()); reqData.put("trade_type", "JSAPI"); reqData.put("openid", openId); Map weixinResponse = new WXPay(wxPayConfig).unifiedOrder(reqData); if (!weixinResponse.get("return_code").equals("SUCCESS") || !weixinResponse.get("result_code").equals("SUCCESS")) { logger.error("获取prepay_id失败" + weixinResponse); throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "获取prepay_id失败"); } // 最后参与签名的参数有appId, timeStamp, nonceStr, package, signType Map parameterMap2 = new HashMap<>(); parameterMap2.put("appId", wxPayConfig.getAppID()); parameterMap2.put("timeStamp", String.valueOf(System.currentTimeMillis()).toString().substring(0, 10)); parameterMap2.put("nonceStr", WXPayUtil.generateNonceStr()); parameterMap2.put("package", "prepay_id=" + weixinResponse.get("prepay_id")); parameterMap2.put("signType", SignType.MD5.toString()); parameterMap2.put("sign", WXPayUtil.generateSignature(parameterMap2, wxPayConfig.getKey(), SignType.MD5)); parameterMap2.put("timestamp", parameterMap2.get("timeStamp")); return parameterMap2; } /** * 第三步 查询付款结果 * * @param orderId * @return * @throws Exception */ @Transactional(readOnly = false) public RESTResponse check(String orderId) throws Exception { JSONObject j = new JSONObject(); // 查询库中是否已经记录付款成功 List logs = paymentPayLogService.findByOrderId(orderId); if (logs == null || logs.size() == 0) { // 已成功直接返回 return new RESTResponse(10001, "无支付记录"); } PaymentOrder order = paymentOrderService.get(orderId); if ("2".equals(order.getPaymentState())) { // 已成功直接返回 j.put("result", "SUCCESS"); return new RESTResponse(j); } // 未成功向微支接口确认 Map reqData = new HashMap<>(); reqData.put("out_trade_no", orderId); Map weixinResponse = new WXPay(wxPayConfig).orderQuery(reqData); if ("SUCCESS".equals(weixinResponse.get("return_code")) && "SUCCESS".equals(weixinResponse.get("result_code")) && "SUCCESS".equals(weixinResponse.get("trade_state"))) { // 保存回调的支付日志 paymentPayLogService.updatePayInfo(orderId, weixinResponse.get("transaction_id"), weixinResponse.toString()); order.setPaymentWay("24");// 24代表微信支付 order.setTransactionId(weixinResponse.get("transaction_id")); // 会员端支付后处理逻辑 restOrderService.afterPay(order); // 修改支付日志支付状态 paymentPayLogService.updatePayState(orderId, "2", null); j.put("result", "SUCCESS"); return new RESTResponse(j); } j.put("result", "FAIL"); return new RESTResponse(j); } public ResultDto getOpenId(String code) throws Exception { String URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + wxPayConfig.getAppID() + "&secret=" + wxPayConfig.getKey() + "&code=" + code + "&grant_type=authorization_code"; logger.debug("OAuth2@@@@@@URL:" + URL); String t = restTemplate.getForEntity(URL, String.class).getBody(); logger.debug("OAuth2@@@@@@t:" + t); HashMap map = JSON.parseObject(t, HashMap.class); if (StringUtils.isBlank(map.get("openid"))) { logger.error("OAuth2@@@@@@t:" + t); throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "获取openid失败!"); } return ResultDto.success(map.get("openid")); } }