package com.pj.api.wx.service; import cn.hutool.core.net.URLDecoder; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.XmlUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.pj.api.wx.WxUtils; import com.pj.api.wx.bo.*; import com.pj.api.wx.vo.PrePayVO; import com.pj.current.config.MyConfig; import com.pj.current.config.WxConfig; import com.pj.project.tb_business.TbBusiness; import com.pj.project.tb_business.TbBusinessService; import com.pj.project.tb_business_car.TbBusinessCar; import com.pj.project.tb_business_car.TbBusinessCarService; import com.pj.project.tb_business_item.TbBusinessItem; import com.pj.project.tb_business_item.TbBusinessItemService; import com.pj.project.tb_costomer.TbCostomer; import com.pj.project.tb_costomer.TbCostomerService; import com.pj.project.tb_pay_record.TbPayRecord; import com.pj.project.tb_pay_record.TbPayRecordService; import com.pj.utils.cache.RedisUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.nio.charset.Charset; import java.util.*; import java.util.stream.Collectors; @Service @Transactional @Slf4j public class WxService { @Resource @Lazy private TbBusinessService tbBusinessService; @Resource WxConfig wxConfig; @Resource MyConfig myConfig; @Resource WxUtils wxUtils; @Resource TbPayRecordService tbPayRecordService; @Resource TbCostomerService tbCostomerService; @Resource TbBusinessCarService tbBusinessCarService; @Resource @Lazy TbBusinessItemService tbBusinessItemService; /** * 统一下单接口 */ public Map prePay(HttpServletRequest request) throws Exception { String tradeType = request.getParameter("tradeType"); String money = request.getParameter("money"); String openid = request.getParameter("openid"); String businessId = request.getParameter("b"); String c = request.getParameter("c"); String a = request.getParameter("a"); Attach atchMap = new Attach(); atchMap.setC(c).setB(businessId).setA(a); String out_trade_no = RandomUtil.randomString(32); Map params = new HashMap<>(); params.put("appid", wxConfig.getAppId()); params.put("mch_id", wxConfig.getMachId()); params.put("openid", openid); params.put("nonce_str", RandomUtil.randomString(32)); params.put("body", "支付中心-业务订单支付"); params.put("out_trade_no", out_trade_no); params.put("attach", JSONUtil.toJsonStr(atchMap)); String total_free = NumberUtil.mul(money, 100 + "").intValue() + ""; // String total_free = "1"; log.info("pay free:{}", total_free); params.put("total_fee", total_free); // params.put("total_fee", "1"); params.put("spbill_create_ip", getIpAddress(request)); params.put("notify_url", myConfig.getDomain() + "/wx/notify"); params.put("trade_type", tradeType); params.put("scene_info", SceneInfoBO.getSceneInfo(myConfig.getDomain(), wxConfig.getTitle())); String sign = wxUtils.sign(params, wxConfig.getKey()); log.info("wx pay sign result:{}", sign); params.put("sign", sign); String prePayUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"; String xmlParam = XmlUtil.mapToXmlStr(params); log.info("wx pay xml params:{}", xmlParam); String result = HttpUtil.createPost(prePayUrl).header("Content-Type", "text/xml").body(xmlParam) .execute().body(); Map resultMap = XmlUtil.xmlToMap(result); log.info("request pre pay url result:{}", resultMap); PrePayVO vo = new PrePayVO(); if ("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))) { log.info("生成预支付订单成功,mweb_url:{}", resultMap.get("mweb_url")); Object webUrl = resultMap.get("mweb_url"); Object prePayId = resultMap.get("prepay_id"); String preId = prePayId == null ? "" : prePayId.toString(); vo.setPayUrl(webUrl == null ? "" : webUrl.toString()) .setPrePayId(preId) .setTradeType(tradeType); return getPayParams(openid, preId); } throw new Exception("支付信息有误"); } public Map getPayParams(String openid, String prePayId) { Map signMap = new HashMap<>(10); signMap.put("appId", wxConfig.getAppId()); signMap.put("timeStamp", System.currentTimeMillis() / 1000 + ""); signMap.put("nonceStr", RandomUtil.randomString(32)); signMap.put("signType", "MD5"); signMap.put("package", "prepay_id=" + prePayId); String sign = wxUtils.sign(signMap, wxConfig.getKey()); signMap.put("paySign", sign); signMap.put("openId", openid); return signMap; } public static String getIpAddress(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } if (ip.contains(",")) { return ip.split(",")[0]; } else { return ip; } } @Async public void WxNotify(NotifyBO notifyBO) throws Exception { String total_fee = notifyBO.getTotalFee(); BigDecimal money = new BigDecimal(total_fee).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP); log.info("wx pay notify;{}", JSONUtil.toJsonStr(notifyBO)); String tradeNo = notifyBO.getOutTradeNo(); tradeNo = StrUtil.subBefore(tradeNo, "_", true); String attachStr = notifyBO.getAttach(); String transactionId = notifyBO.getTransactionId(); Date now = new Date(); if (StrUtil.isNotEmpty(attachStr)) { Attach attach = JSONUtil.toBean(attachStr, Attach.class); List cars = JSONUtil.toList(attach.getC(), PriceBO.class); for (PriceBO bo1 : cars) { TbBusinessCar car = tbBusinessCarService.getById(bo1.getId()); BigDecimal price = bo1.getP(); car.setPay(1).setMoney(car.getMoney().add(price)); tbBusinessCarService.updateById(car); TbBusiness business = tbBusinessService.getById(car.getBusinessId()); business.setPayMoney(business.getPayMoney().add(price)); business.setPayStatus(business.getPayMoney().add(price).equals(business.getTotalMoney()) ? 3 : 4); tbBusinessService.updateById(business); } String businessId = attach.getB(); if (StrUtil.isNotEmpty(businessId)) { List items = tbBusinessItemService.findByBusinessId(businessId); items.forEach(tbBusinessItem -> tbBusinessItem.setPayStatus(1).setPayTime(now)); double sum = items.stream().collect(Collectors.summarizingDouble(item -> item.getItemPrice().doubleValue())).getSum(); BigDecimal itemPrice=new BigDecimal(sum); tbBusinessItemService.updateBatchById(items); TbBusiness tbBusiness = tbBusinessService.getById(businessId); tbBusiness.setPayStatus(tbBusiness.getPayMoney().add(itemPrice).equals(tbBusiness.getTotalMoney()) ? 3 : 4); tbBusiness.setPayTime(now).setPayType(3).setConfirmInput(1).setConfirmInputTime(now) .setPayMoney(tbBusiness.getPayMoney().add(itemPrice)) .setPayNo(transactionId); tbBusinessService.updateById(tbBusiness); TbPayRecord payRecord = new TbPayRecord(); TbCostomer tbCostomer = tbCostomerService.getById(tbBusiness.getCustomerId()); payRecord.setCreateTime(now) .setOutTradeNo(tradeNo) .setTransactionId(transactionId) .setPayMoney(money) .setCustomerId(tbCostomer.getId()).setCustomerName(tbCostomer.getName()); tbPayRecordService.save(payRecord); } } } public String getRedirectUrl(String path, String state) { String redirectUrl = myConfig.getWebDomain() + path; String encoderUrl = URLDecoder.decode(redirectUrl, Charset.forName("utf-8")); String url = wxConfig.getAuthLoginUrl().replace("REDIRECT_URI", encoderUrl); if (StrUtil.isNotEmpty(state)) { url = url.replace("STATE", state); } log.info("get redirect url:{}", url); return url; } public String getOpenidByCode(String code, String openid) { String openidUrl = wxConfig.getOpenidUrl().replace("CODE", code); String resp = HttpUtil.get(openidUrl); JSONObject result = JSONUtil.parseObj(resp); log.info("get openid result:{}", resp); String newOpenid = result.getStr("openid"); if (StrUtil.isNotEmpty(newOpenid)) { return newOpenid; } return openid; } public SortedMap getWxConfig(String url) { Long nowTime = System.currentTimeMillis() / 1000; String jsTicket = RedisUtil.get(wxConfig.getJsApiTicketKey()); SortedMap params = new TreeMap<>(); params.put("noncestr", RandomUtil.randomString(32)); params.put("jsapi_ticket", jsTicket); params.put("timestamp", nowTime); params.put("url", url); String sign = SecureUtil.sha1(params.toString().substring(1, params.toString().lastIndexOf("}")).replaceAll(", ", "&")); params.put("sign", sign); params.put("appId", wxConfig.getAppId()); return params; } }