123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- package com.pj.api.wx.service;
- import cn.hutool.cache.CacheUtil;
- import cn.hutool.cache.impl.TimedCache;
- import cn.hutool.core.codec.Base64;
- import cn.hutool.core.date.DateUtil;
- 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.alibaba.fastjson.JSON;
- 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.PartConfig;
- import com.pj.current.config.WxConfig;
- import com.pj.project.tb_account.TbAccountService;
- 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_charge_record.TbChargeRecord;
- import com.pj.project.tb_costomer.TbCostomer;
- import com.pj.project.tb_costomer.TbCostomerService;
- import com.pj.project.tb_fee_details.TbFeeDetailsService;
- import com.pj.project.tb_fee_statistics.TbFeeStatisticsService;
- import com.pj.project.tb_goods.TbGoods;
- import com.pj.project.tb_goods.TbGoodsService;
- import com.pj.project.tb_item.TbItem;
- import com.pj.project.tb_order.TbOrder;
- import com.pj.project.tb_order.TbOrderService;
- import com.pj.project.tb_pay_record.TbPayRecord;
- import com.pj.project.tb_pay_record.TbPayRecordService;
- import com.pj.project.wx_send_msg.WxSendMsg;
- import com.pj.project.wx_send_msg.WxSendMsgService;
- import com.pj.project4sp.global.BusinessException;
- 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.*;
- @Service
- @Transactional
- @Slf4j
- public class WxService {
- @Resource
- @Lazy
- private TbBusinessService tbBusinessService;
- @Resource
- WxConfig wxConfig;
- @Resource
- MyConfig myConfig;
- @Resource
- PartConfig partConfig;
- @Resource
- WxUtils wxUtils;
- @Resource
- TbBusinessCarService tbBusinessCarService;
- @Resource
- @Lazy
- TbBusinessItemService tbBusinessItemService;
- @Resource
- TbFeeStatisticsService tbFeeStatisticsService;
- @Resource
- private TbAccountService tbAccountService;
- @Resource
- TbFeeDetailsService tbFeeDetailsService;
- @Resource
- private TbOrderService tbOrderService;
- @Resource
- private TbGoodsService tbGoodsService;
- @Resource
- private WxSendMsgService wxSendMsgService;
- /**
- * 统一下单接口
- */
- public Map<String, String> prePay(HttpServletRequest request) throws Exception {
- String tradeType = request.getParameter("tradeType");
- String money = request.getParameter("money");
- if (Double.valueOf(money) <= 0) {
- throw new BusinessException("金额不正确");
- }
- String openid = request.getParameter("openid");
- String desc = request.getParameter("desc");
- // String openid = "oDWvn5w-hVkzUuKeY7OBXBV_l1rU";
- 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<String, String> 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", handlerDesc(desc));
- params.put("out_trade_no", out_trade_no);
- // params.put("attach", JSONUtil.toJsonStr(atchMap));
- String total_free = partConfig.isTestEnv() ? "1" : NumberUtil.mul(money, 100 + "").intValue() + "";
- 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<String, Object> 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);
- Map<String, String> payParams = getPayParams(openid, preId);
- payParams.put("outTradeNo", out_trade_no);
- TbOrder tbOrder = new TbOrder();
- tbOrder.setAttach(JSONUtil.toJsonStr(atchMap))
- .setOpenid(openid)
- .setOrderTime(new Date())
- .setOutTradeNo(out_trade_no).setPrice(money);
- return payParams;
- }
- throw new Exception("支付信息有误");
- }
- public Map<String, String> getPayParams(String openid, String prePayId) {
- Map<String, String> 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 Map<String, String> getPayP(String timeStamp, String nonceStr, String openid, String pack) {
- Map<String, String> signMap = new HashMap<>(10);
- signMap.put("appId", wxConfig.getAppId());
- signMap.put("timeStamp", timeStamp);
- signMap.put("nonceStr", nonceStr);
- signMap.put("signType", "MD5");
- signMap.put("package", pack);
- 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;
- }
- }
- public void WxNotify(NotifyBO notifyBO) {
- String orderStatus=notifyBO.getTradeStatus();
- if (!"SUCCESS".equals(orderStatus) && !"FINISH".equals(orderStatus)) {
- log.error("支付订单回调失败:{}",JSONUtil.toJsonStr(notifyBO));
- return;
- }
- String outTradeNo = notifyBO.getOutTradeNo();
- if (StrUtil.isNotEmpty(RedisUtil.get(outTradeNo))) {
- log.error("========订单已处理==========:{}", outTradeNo);
- return;
- }
- RedisUtil.setByMINUTES(outTradeNo, DateUtil.now(), 10);
- TbOrder tbOrder = tbOrderService.findByOutTradeNo(outTradeNo);
- if (tbOrder == null) {
- log.error("========订单不存在==========:{}", outTradeNo);
- return;
- }
- if (StrUtil.equals("SUCCESS", tbOrder.getOrderStatus())) {
- log.error("========订单已支付==========:{}", outTradeNo);
- return;
- }
- String total_fee = notifyBO.getTotalFee();
- BigDecimal money = new BigDecimal(total_fee).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP);
- String attachStr = tbOrder.getAttach();
- String transactionId = notifyBO.getTransactionId();
- Date now = new Date();
- String timeEnd=notifyBO.getTimeEnd();
- Date payTime=now;
- if (StrUtil.isNotEmpty(timeEnd)){
- payTime=DateUtil.parse(timeEnd,"yyyyMMddHHmmss");
- }
- if (StrUtil.isNotEmpty(attachStr)) {
- Attach attach = JSONUtil.toBean(attachStr, Attach.class);
- List<PriceBO> cars = JSONUtil.toList(attach.getC(), PriceBO.class);
- for (PriceBO bo1 : cars) {
- TbBusinessCar car = tbBusinessCarService.getById(bo1.getId());
- BigDecimal price = bo1.getP();
- if (price == null || price.doubleValue() <= 0) {
- log.error("付款金额不正确:{}", JSONUtil.toJsonStr(notifyBO));
- continue;
- }
- car.setPay(1).setMoney(car.getMoney().add(price)).setPayTime(payTime).setPayType(TbBusinessCar.PayTypeEnum.HAS_PAY_TYPE.getType());
- tbBusinessCarService.updateById(car);
- }
- tbFeeDetailsService.chargeParkFee(cars, transactionId, outTradeNo, payTime);//添加cars的收费明细
- String businessId = attach.getB();
- Date finalPayTime = payTime;
- if (StrUtil.isNotEmpty(businessId)) {
- List<String> businessIds = StrUtil.splitTrim(businessId, ",");
- List<TbBusinessItem> items = tbBusinessItemService.findByBusinessIdList(businessIds);
- List<TbBusiness> businessList = tbBusinessService.listByIds(businessIds);
- for (TbBusiness tbBusiness : businessList) {
- tbBusiness.setPayTime(payTime).setPayType(3).setConfirmInput(1).setConfirmInputTime(payTime)
- .setPayMoney(tbBusiness.getItemPrice())
- .setPayNo(transactionId);
- tbBusiness.setPayStatus(3);
- tbBusinessService.updateById(tbBusiness);
- TbGoods tbGoods = tbGoodsService.getById(tbBusiness.getGoodsId());
- List<TbBusinessCar> carList = tbBusinessCarService.findOtherBusinessCar(businessId);
- carList.forEach(tbBusinessCar -> {
- String carType = tbBusinessCar.getCarType();
- //
- if (TbItem.ItemTypeEnum.EMPTY_TYPE.getType().equals(carType) && tbGoods.getChinaCarPay() == 0
- || TbItem.ItemTypeEnum.WEIGHT_TYPE.getType().equals(carType) && tbGoods.getVietnamCarPay() == 0) {
- tbBusinessCar.setPay(1).setPayTime(finalPayTime);
- tbBusinessCarService.updateById(tbBusinessCar);
- }
- });
- }
- tbFeeDetailsService.chargeBusinessFee(items, transactionId, outTradeNo, payTime);//添加items的收费明细
- items.forEach(tbBusinessItem -> tbBusinessItem.setPayStatus(1).setPayTime(finalPayTime));
- tbBusinessItemService.updateBatchById(items);
- }
- tbFeeStatisticsService.addOrUpdateStatistic(payTime);//更新当前日期的日统计
- String a = attach.getA();
- if (StrUtil.isNotEmpty(a)) {//充值的======>
- AccountChargeBO chargeBO = JSONUtil.toBean(a, AccountChargeBO.class);
- tbAccountService.recharge(chargeBO.getId(), chargeBO.getC(), TbChargeRecord.Ch.WECHAT.getType(), money);
- }
- }
- tbOrder.setOrderStatus("SUCCESS")
- .setTransactionId(notifyBO.getTransactionId())
- .setCompleteDate(notifyBO.getTimeEnd());
- tbOrderService.updateById(tbOrder);
- }
- 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<String, Object> 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;
- }
- @Async
- public void sendTemplateMsg(String templateId, String openid, MsgDataBO data) {
- String accessToken = RedisUtil.get(wxConfig.getAccessTokenKey());
- BaseTemplate baseTemplate = new BaseTemplate(openid, templateId, data);
- String json = JSON.toJSONString(baseTemplate);
- String url = wxConfig.getSendMsgUrl().replace("ACCESS_TOKEN", accessToken);
- String resp = HttpUtil.post(url, json);
- log.info("send wx msg{},{},{};return :{}", templateId, openid, JSONUtil.toJsonStr(data), resp);
- }
- @Async
- public void sendTemplateMsg(String templateId, String openid, Object data, String detailUrl) {
- if (StrUtil.isEmpty(openid)){
- return;
- }
- String accessToken = RedisUtil.get(wxConfig.getAccessTokenKey());
- BaseTemplate baseTemplate = new BaseTemplate(openid, templateId, detailUrl, data);
- String json = JSON.toJSONString(baseTemplate);
- String url = wxConfig.getSendMsgUrl().replace("ACCESS_TOKEN", accessToken);
- String resp = HttpUtil.post(url, json);
- JSONObject result = JSONUtil.parseObj(resp);
- int code = result.getInt("errcode");
- log.info("send wx msg{},{},{};return :{}", templateId, openid, JSONUtil.toJsonStr(data), resp);
- WxSendMsg wxSendMsg = wxSendMsgService.findByOpenidAndDetailUrl(openid, detailUrl);
- if (code != 0) {
- if (wxSendMsg == null) {
- wxSendMsg = new WxSendMsg();
- wxSendMsg.setCreateTime(DateUtil.now());
- }
- wxSendMsg.setCode(code).setDetailUrl(detailUrl)
- .setMsgData(JSONUtil.toJsonStr(data)).setOpenid(openid).setTemplateId(templateId)
- .setReturnMsg(result.getStr("errmsg"));
- wxSendMsgService.saveOrUpdate(wxSendMsg);
- }else if (wxSendMsg != null){
- wxSendMsgService.delete(wxSendMsg.getId());
- }
- }
- private String handlerDesc(String desc){
- if (StrUtil.isEmpty(desc)){
- return "";
- }
- if (desc.getBytes(Charset.forName("utf-8")).length>128){
- desc=StrUtil.sub(desc,0,desc.lastIndexOf("-"));
- handlerDesc(desc);
- }
- return desc;
- }
- }
|