ganxiaomao преди 5 години
родител
ревизия
6b7333c612

+ 257 - 0
wjj-api/src/main/java/com/demo/wjj/controller/PaySaleController.java

@@ -0,0 +1,257 @@
+package com.demo.wjj.controller;
+
+import com.demo.wjj.bo.CreateOrderBo;
+import com.demo.wjj.bo.CreateOrderResult;
+import com.demo.wjj.po.WeiXinPay;
+import com.demo.wjj.service.PaySaleService;
+import com.demo.wjj.service.PayService;
+import com.demo.wjj.service.WeiXinPayService;
+import com.demo.wjj.utils.ApiResult;
+import com.demo.wjj.utils.ExecuteResult;
+import com.demo.wjj.utils.IpUtils;
+import com.demo.wjj.utils.Result;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * icegan--新增,销售员支付保证金
+ */
+@RequestMapping("/paysale")
+@RestController
+public class PaySaleController {
+    private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+    @Autowired
+    private PaySaleService payService;
+
+    @Autowired
+    private WeiXinPayService weiXinPayService;
+
+
+    /**
+     * 创建微信支付订单
+     * @param productId 产品id
+     * @param agentId 商家id
+     * @param openId openId
+     * @param name 联系人姓名
+     * @param mobile 联系人手机
+     * @param tp 是否通票
+     * @return
+     */
+    @PostMapping("/createOrder")
+    public ApiResult createOrder(@RequestParam(required = false) String productId,
+                                 @RequestParam(required = false) String agentId,
+                                 @RequestParam(required = false) String openId,
+                                 @RequestParam(required = false) String name,
+                                 @RequestParam(required = false) String mobile,
+                                 @RequestParam(required = false) String tp,
+                                 HttpServletRequest request) {
+        LOG.info("调用创建保证金微信支付订单(/pay/createOrder)接口, productId:{}, agentId:{}, openId:{}", productId, agentId, openId);
+
+        if (StringUtils.isBlank(productId)) {
+            LOG.info("productId为空");
+            return ApiResult.createFailure();
+        }
+
+        if (StringUtils.isBlank(agentId)) {
+            LOG.info("agentId为空");
+            return ApiResult.createFailure();
+        }
+
+        if (StringUtils.isBlank(openId)) {
+            LOG.info("openId为空");
+            return ApiResult.createFailure();
+        }
+
+        if (StringUtils.isBlank(name)) {
+            LOG.info("name为空");
+            return ApiResult.createFailure();
+        }
+
+        if (StringUtils.isBlank(mobile)) {
+            LOG.info("mobile为空");
+            return ApiResult.createFailure();
+        }
+
+        /* 手机端用户不能设置通票 wangqing 201811302208
+        if (StringUtils.isBlank(tp)) {
+            tp = "0";
+        }
+
+
+        final String[] tps = {"1", "0"};
+        if (!ArrayUtils.contains(tps, tp)) {
+            LOG.info("tp值非法, tp:{}", tp);
+            return ApiResult.createFailure();
+        }
+        */
+        CreateOrderBo createOrderBo = new CreateOrderBo();
+        createOrderBo.setProductId(productId);
+        createOrderBo.setAgentId(agentId);
+        createOrderBo.setOpenId(openId);
+        createOrderBo.setName(name);
+        createOrderBo.setMobile(mobile);
+        /* 手机端用户不能设置通票 wangqing 201811302208
+        createOrderBo.setTp(Integer.parseInt(tp));
+        */
+        createOrderBo.setClientIp(IpUtils.getIp(request));
+        try {
+            ExecuteResult<CreateOrderResult> executeResult = payService.createOrder(createOrderBo);
+            if (executeResult.isExecuteResult()) {
+                ApiResult<CreateOrderResult> apiResult = ApiResult.createSuccess(executeResult.getData());
+                LOG.info("调用创建保证金微信支付订单(/pay/createOrder)接口成功, apiResult:{}", apiResult);
+                return apiResult;
+            } else {
+                Result result = executeResult.getResult();
+                if (result == null) {
+                    result = Result.Failure;
+                }
+                return new ApiResult(result);
+            }
+
+        } catch (Exception e) {
+            LOG.error("调用创建保证金微信支付订单(/pay/createOrder)接口异常", e);
+            return ApiResult.createFailure();
+        }
+
+    }
+
+    /**
+     * 查询订单支付状态
+     * @param orderNo 订单编号
+     * @return
+     */
+    @GetMapping("/getOrderStatus")
+    public ApiResult queryOrderStatus(@RequestParam(required = false) String orderNo) {
+        LOG.info("调用获取订单支付状态(/pay/getOrderStatus)接口, orderNo:{}", orderNo);
+
+        if (StringUtils.isBlank(orderNo)) {
+            LOG.info("orderNo为空");
+            return ApiResult.createFailure();
+        }
+
+        try {
+            WeiXinPay weiXinPay = weiXinPayService.get(orderNo);
+            if (weiXinPay == null) {
+                LOG.info("未查找到微信支付订单, orderNo:{}", orderNo);
+                return ApiResult.createFailure();
+            }
+
+            Map<String, Integer> data = new HashMap<>();
+            data.put("success", WeiXinPay.ORDER_STATUS_SUCCESS == weiXinPay.getOrderStatus() ? 1 : 0);
+            ApiResult<Map<String, Integer>> apiResult = ApiResult.createSuccess(data);
+            LOG.info("调用获取订单支付状态(/pay/getOrderStatus)接口成功, apiResult:{}", apiResult);
+            return apiResult;
+        } catch (Exception e) {
+            LOG.info("调用获取订单支付状态(/pay/getOrderStatus)接口异常", e);
+            return ApiResult.createFailure();
+        }
+
+    }
+
+    /**
+     * 微信支付回调
+     * @param request request
+     * @return 响应内容
+     */
+    @RequestMapping(value = "/callback")
+    public String callback(HttpServletRequest request) {
+        LOG.info("调用微信支付订单回调(/pay/callback)接口");
+        ServletInputStream inputStream;
+
+        try {
+            inputStream = request.getInputStream();
+        } catch (IOException e) {
+            LOG.info("调用微信支付订单回调(/pay/callback)接口, 获取请求流异常", e);
+            return "";
+        }
+
+        int b;
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        try {
+            while ((b = inputStream.read()) != -1) {
+                outputStream.write(b);
+            }
+        } catch (Exception e) {
+            LOG.error("调用微信支付订单回调(/pay/callback)接口, 读取请求流内容异常", e);
+            return "";
+        } finally {
+            try {
+                outputStream.close();
+            } catch (IOException e) {
+                LOG.error("", e);
+            }
+        }
+
+        try {
+            String result = payService.payCallback(new String(outputStream.toByteArray(), StandardCharsets.UTF_8).trim());
+            LOG.info("调用微信支付订单回调(/pay/callback)接口成功, result => {}", result);
+            return result;
+        } catch (Exception e) {
+            LOG.info("调用微信支付订单回调(/pay/callback)接口异常", e);
+            return "";
+        }
+    }
+
+    @PostMapping("/applyRefund")
+    public ApiResult applyRefund(@RequestParam String id) {
+        LOG.info("调用微信申请退款(/pay/applyRefund)接口, id:{}", id);
+        if (StringUtils.isBlank(id)) {
+            LOG.info("id为空");
+            return ApiResult.createFailure();
+        }
+
+        try {
+            final ExecuteResult<String> executeResult = payService.refund(id);
+            ApiResult apiResult;
+            if (executeResult.isExecuteResult()) {
+                apiResult = ApiResult.createSuccess(null);
+            } else {
+                apiResult = ApiResult.createFailure();
+                apiResult.setMessage(executeResult.getData());
+            }
+            LOG.info("调用微信申请退款(/pay/applyRefund)接口成功, apiResult:{}", apiResult);
+            return apiResult;
+        } catch (Exception e) {
+            LOG.error("调用微信申请退款(/pay/applyRefund)接口异常", e);
+            return ApiResult.createFailure();
+        }
+    }
+
+    @RequestMapping("/refund/{depositId}/callback/integral")
+    public String refundCallbackIntegral(@PathVariable String depositId, @RequestBody String xml) {
+        LOG.info("调用微信退款回调(/refund/{appId}/{depositId}/callback)接口, depositId:{}, xml:{}", depositId, xml);
+
+        final String responseXml = "<xml><return_code>${result}</return_code><return_msg></return_msg></xml>";
+
+        if (StringUtils.isBlank(depositId)) {
+            LOG.info("depositId为空");
+            return responseXml.replace("${result}", "FAIL");
+        }
+
+        if (StringUtils.isBlank(xml)) {
+            LOG.info("xml为空");
+            return responseXml.replace("${result}", "FAIL");
+        }
+
+        try {
+            final String result = responseXml.replace("${result}", payService.refundCallback(depositId, xml));
+            LOG.info("调用微信退款回调(/refund/{appId}/{depositId}/callback)接口成功, result:{}", result);
+            return result;
+        } catch (Exception e) {
+            LOG.info("调用微信退款回调(/refund/{appId}/{depositId}/callback)接口异常", e);
+            return responseXml.replace("${result}", "FAIL");
+        }
+    }
+}

+ 12 - 0
wjj-core/src/main/java/com/demo/wjj/po/Deposit.java

@@ -70,6 +70,10 @@ public class Deposit {
      * 订单编号
      */
     private String agentPayNo;
+    /**
+     * icegan--新增,用户类型:1,车商;2,销售员
+     */
+    private Integer userType=1;
 
     public String getId() {
         return id;
@@ -174,4 +178,12 @@ public class Deposit {
     public void setAgentPayNo(String agentPayNo) {
         this.agentPayNo = agentPayNo;
     }
+
+    public Integer getUserType() {
+        return userType;
+    }
+
+    public void setUserType(Integer userType) {
+        this.userType = userType;
+    }
 }

+ 5 - 5
wjj-core/src/main/java/com/demo/wjj/po/Sale.java

@@ -128,7 +128,7 @@ public class Sale extends BasePo {
 
     private String platTpSet;
 
-    private Integer deposite;
+    private Integer deposit;
 
     public Date getRegisteDate() {
         return registeDate;
@@ -298,11 +298,11 @@ public class Sale extends BasePo {
         this.platTpSet = platTpSet;
     }
 
-    public Integer getDeposite() {
-        return deposite;
+    public Integer getDeposit() {
+        return deposit;
     }
 
-    public void setDeposite(Integer deposite) {
-        this.deposite = deposite;
+    public void setDeposit(Integer deposit) {
+        this.deposit = deposit;
     }
 }

+ 38 - 0
wjj-core/src/main/java/com/demo/wjj/service/PaySaleService.java

@@ -0,0 +1,38 @@
+package com.demo.wjj.service;
+
+import com.demo.wjj.bo.CreateOrderBo;
+import com.demo.wjj.bo.CreateOrderResult;
+import com.demo.wjj.utils.ExecuteResult;
+
+/**
+ * 销售员支付保证金
+ */
+public interface PaySaleService {
+    /**
+     * 创建订单
+     * @param createOrderBo 创建订单
+     * @return 创建订单结果
+     */
+    ExecuteResult<CreateOrderResult> createOrder(CreateOrderBo createOrderBo);
+
+    /**
+     * 支付回调
+     * @param xmlStr 回调xml
+     */
+    String payCallback(String xmlStr);
+
+    /**
+     * 微信退款
+     * @param id 保证金id
+     * @return 退款是否成功
+     */
+    ExecuteResult<String> refund(String id);
+
+    /**
+     * 微信退款回调
+     * @param depositId
+     * @param xml xml
+     * @return
+     */
+    String refundCallback(String depositId, String xml);
+}

+ 879 - 0
wjj-core/src/main/java/com/demo/wjj/service/impl/PaySaleServiceImpl.java

@@ -0,0 +1,879 @@
+package com.demo.wjj.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.demo.wjj.bo.*;
+import com.demo.wjj.mapper.OfferMapper;
+import com.demo.wjj.po.*;
+import com.demo.wjj.service.*;
+import com.demo.wjj.utils.*;
+import com.sun.xml.internal.messaging.saaj.util.ByteInputStream;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@Service
+public class PaySaleServiceImpl implements PaySaleService {
+    private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+    /**
+     * 回调地址域名
+     */
+    @Value("${weixin.pay.domain}")
+    private String domain;
+
+    /**
+     * 微信支付接口
+     */
+    @Value("${weixin.pay.apiAddress}")
+    private String payApiAddress;
+
+    @Autowired
+    private AgentService agentService;
+
+    @Autowired
+    private DiggerAgentService diggerAgentService;
+
+    @Autowired
+    private WeiXinPayService weiXinPayService;
+
+    @Autowired
+    private DepositService depositService;
+
+    @Autowired
+    private OfferService offerService;
+
+    @Autowired
+    private DisplaceOfferUserService displaceOfferUserService;
+
+    @Autowired
+    private SaleService saleService;
+
+    @Autowired
+    private OfferMapper offerMapper;
+
+    @CommitTransactional
+    @Override
+    public ExecuteResult<CreateOrderResult> createOrder(CreateOrderBo createOrderBo) {
+        LOG.info("进入创建订单, createOrderBo:{}", createOrderBo);
+
+        String agentId = createOrderBo.getAgentId();
+        if (StringUtils.isBlank(agentId)) {
+            LOG.warn("agentId为空");
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        String openId = createOrderBo.getOpenId();
+        if (StringUtils.isBlank(openId)) {
+            LOG.warn("微信openId为空");
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        String productId = createOrderBo.getProductId();
+        if (StringUtils.isBlank(productId)) {
+            LOG.warn("productId为空");
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        Agent agent = agentService.getAgent(agentId);
+        if (agent == null) {
+            LOG.info("未查找到商家信息, agentId:{}", agentId);
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        final String appId = agent.getMchAppId();
+        if (StringUtils.isBlank(appId)) {
+            LOG.info("商家appId为空");
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        String appSecret = agent.getMchAppSecret();
+        if (StringUtils.isBlank(appSecret)) {
+            LOG.info("商家appSecret为空");
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        String mchId = agent.getMchId();
+        if (StringUtils.isBlank(mchId)) {
+            LOG.info("微信商家mchId为空");
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        Sale sale = saleService.getSale(agentId, openId);
+        if(sale == null){
+            LOG.info("未查找到销售员信息, agentId:{}, openId:{}", agentId, openId);
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.NO_AUTHORITY);
+        }
+
+        //如果是通票用户,无需支付保证金
+        if(sale.getPlatTpSet().equals("1")){
+            LOG.info("销售员是通票用户,无需支付保证金, agentId:{}, openId:{}", agentId, openId);
+            return  new ExecuteResult<CreateOrderResult>().setExecuteResult(false).setResult(Result.DIGGER_NO_PAY_DEPOSIT);
+        }
+
+        ExecuteResult<DiggerOfferBo> executeResult = offerService.queryDiggerPayOffer(agentId, openId, productId);
+
+        //获取保证金
+        Integer deposit = offerMapper.selectDisplaceDeposit(productId);
+
+
+        if (deposit == null || deposit <= 0) {
+            LOG.info("销售员保证金无效, deposit:{}", deposit);
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        CreateOrderParameter orderParameter = new CreateOrderParameter();
+        orderParameter.setAppId(appId);
+        orderParameter.setMchId(mchId);
+        orderParameter.setDeviceInfo("WEB");
+        orderParameter.setNonceStr(generateNonceStr());
+        orderParameter.setBody("保证金");
+        orderParameter.setAttach("productId@" + productId);
+        final String outTradeNo = generateTradeNo(agentId, sale.getSaleId());
+        orderParameter.setOutTradeNo(outTradeNo);
+        orderParameter.setTotalFee(deposit);
+        orderParameter.setSpbillCreateIp(createOrderBo.getClientIp());
+        orderParameter.setOpenId(openId);
+        orderParameter.setNotifyUrl(createNotifyUrl());
+        orderParameter.setSign(SignFactory.generate(orderParameter.createRequestParameter(), appSecret));
+
+        // 请求微信接口
+        String parameterXml = orderParameter.toString();
+        LOG.info("请求参数xml格式:{}", parameterXml);
+        byte[] bytes;
+        try {
+            bytes = parameterXml.getBytes("utf-8");
+        } catch (UnsupportedEncodingException e) {
+            LOG.error("编码请求参数异常", e);
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+        HttpResult httpResult = HttpUtils.post(payApiAddress, bytes);
+        if (httpResult.getStatusCode() != 200) {
+            LOG.info("请求微信创建订单接口失败, statusCode:{}", httpResult.getStatusCode());
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        PaySaleServiceImpl.OrderResponse response = parseOrderResponse(httpResult.getContent());
+        if (response == null) {
+            LOG.info("解析订单响应内容失败");
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        String prepayId = response.getPrepayId();
+        if (StringUtils.isBlank(prepayId)) {
+            LOG.info("解析订单参数prepayId为空");
+            return new ExecuteResult<CreateOrderResult>()
+                    .setExecuteResult(false)
+                    .setResult(Result.Failure);
+        }
+
+        WeiXinPay weiXinPay = new WeiXinPay();
+        weiXinPay.setProductId(productId);
+        weiXinPay.setProductType(1);
+        weiXinPay.setOrderNo(outTradeNo);
+        weiXinPay.setWxOpenId(openId);
+        weiXinPay.setAgentId(agentId);
+        weiXinPay.setDiggerAgentId(sale.getAgentId());
+        weiXinPay.setDeposit(deposit);
+        weiXinPay.setCreateTime(new Date());
+        weiXinPay.setOrderStatus(WeiXinPay.ORDER_STATUS_WAIT);
+        weiXinPay.setPrepayId(prepayId);
+
+        PayParameterJson payParameter = new PayParameterJson();
+        payParameter.setMobile(createOrderBo.getMobile());
+        payParameter.setName(createOrderBo.getName());
+        /* 手机端用户不能设置通票 wangqing 201811302208
+        payParameter.setTp(createOrderBo.getTp());
+        */
+        weiXinPay.setParameterJson(JSON.toJSONString(payParameter));
+        weiXinPayService.save(weiXinPay);
+
+        Deposit newDeposit = new Deposit();
+        newDeposit.setId(UuidUtils.generate());
+        newDeposit.setProductName("保证金");
+//        newDeposit.setWxPayNo(prepayId);
+        newDeposit.setDaId(sale.getAgentId());
+        newDeposit.setAgentId(agentId);
+        newDeposit.setAgentName(agent.getAgentName());
+        newDeposit.setAgentPayNo(outTradeNo);
+        newDeposit.setPayAmout(new Double(deposit / 100));
+        newDeposit.setPayStatus("0");
+        newDeposit.setPayCreatetime(new Date());
+        newDeposit.setUserType(2);//销售员
+        /* 手机端用户不能设置通票 wangqing 201811302208
+        newDeposit.setIsCommon(createOrderBo.getTp() + "");
+        */
+        // 默认不是通票, 通票是不需要支付保证金
+        newDeposit.setIsCommon("0");
+        depositService.save(newDeposit);
+
+        CreateOrderResult createOrderResult = new CreateOrderResult();
+        createOrderResult.setAppId(appId);
+        createOrderResult.setTimeStamp(String.valueOf(System.currentTimeMillis() / 1000));
+        createOrderResult.setNonceStr(RandomUtils.generate(10));
+        createOrderResult.setPackageStr(prepayId);
+        createOrderResult.setSignType("MD5");
+        createOrderResult.setPaySign(SignFactory.generate(createOrderResult.createRequestParameter(), appSecret));
+        createOrderResult.setOrderNo(outTradeNo);
+
+        LOG.info("退出创建订单, createOrderResult:{}", createOrderResult);
+        return new ExecuteResult<CreateOrderResult>().setExecuteResult(true).setData(createOrderResult);
+    }
+
+    private PaySaleServiceImpl.OrderResponse parseOrderResponse(String content) {
+        LOG.info("进入解析订单响应内容, content:{}", content);
+        if (StringUtils.isBlank(content)) {
+            LOG.info("响应内容为空");
+            return null;
+        }
+
+        byte[] bytes = content.getBytes();
+        ByteInputStream byteInputStream = new ByteInputStream(bytes, bytes.length);
+
+        PaySaleServiceImpl.OrderResponse response = new PaySaleServiceImpl.OrderResponse();
+        BeanWrapper bean = new BeanWrapperImpl(response);
+        SAXReader reader = new SAXReader();
+        Document document;
+        try {
+            document = reader.read(byteInputStream);
+        } catch (Exception e) {
+            LOG.error("读取响应内容流失败", e);
+            return null;
+        }
+
+        Element root = document.getRootElement();
+        List<Element> elements = root.elements();
+
+        String name;
+        String attribute;
+        for (Element element : elements) {
+            name = element.getName();
+            attribute = response.getAttribute(name);
+
+            if (attribute != null) {
+                bean.setPropertyValue(attribute, element.getStringValue());
+            }
+        }
+        LOG.info("退出解析订单响应内容, response:{}", response);
+        return response;
+    }
+
+
+    /**
+     * 创建微信支付回调地址
+     * @return 微信支付回调地址
+     */
+    private String createNotifyUrl() {
+        final String path = "pay/callback";
+
+        if (domain.endsWith("/")) {
+            return domain + path;
+        } else {
+            return domain + "/" + path;
+        }
+    }
+
+    /**
+     * 创建交易订单号
+     * @param agentId 商家id
+     * @param daId 车商id
+     * @return 交易订单号
+     */
+    private String generateTradeNo(String agentId, String daId) {
+        LOG.info("进入创建交易订单号, agentId:{}, daId:{}", agentId, daId);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+
+        String str = "";
+        final int length = 4;
+        Random random = new Random();
+        for (int i = 1; i <= length; i++) {
+            str += random.nextInt(10);
+        }
+
+        String tradeNo = sdf.format(new Date()) + daId.replace("-", "") + str;
+        LOG.info("退出创建交易订单, tradeNo:{}, daId:{}", tradeNo, daId);
+        return tradeNo;
+    }
+
+    /**
+     * 生成随机串
+     * @return 随机串
+     */
+    private String generateNonceStr() {
+        final int length = 10;
+        String str = "";
+        Random random = new Random();
+        for (int i = 1; i <= length; i++) {
+            str += random.nextInt(10);
+        }
+        return str;
+    }
+
+    @CommitTransactional
+    @Override
+    public String payCallback(String xmlStr) {
+        LOG.info("进入微信订单支付回调, xmlStr:{}", xmlStr);
+
+        if (StringUtils.isBlank(xmlStr)) {
+            LOG.info("xmlStr为空");
+            return null;
+        }
+
+        Map<String, String> result = parseCallBack(xmlStr);
+        if (result == null || MapUtils.isEmpty(result)) {
+            LOG.info("解析微信支付回调xml失败");
+            return null;
+        }
+
+        final String signKey = "sign";
+        String sign = result.get(signKey);
+        if (StringUtils.isBlank(sign)) {
+            LOG.info("sign为空");
+            return null;
+        }
+
+        final String outTradeNoKey = "out_trade_no";
+        String outTradeNo = result.get(outTradeNoKey);
+        if (StringUtils.isBlank(outTradeNo)) {
+            LOG.info("商户订单号为空");
+            return null;
+        }
+
+        final String transactionIdKey = "transaction_id";
+        final String transactionId = result.get(transactionIdKey);
+        if (StringUtils.isBlank(transactionId)) {
+            LOG.info("微信支付订单号为空");
+            return null;
+        }
+
+        WeiXinPay weiXinPay = weiXinPayService.get(outTradeNo);
+        if (weiXinPay == null) {
+            LOG.info("未查找到微信支付订单, outTradeNo:{}", outTradeNo);
+            return null;
+        }
+
+        String response = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
+        if (weiXinPay.getOrderStatus() != 1) {
+            LOG.info("微信订单支付状态为非支付状态, orderStatus:{}", weiXinPay.getOrderStatus());
+            LOG.info("退出微信订单支付回调, result => {}", response);
+            return response;
+        }
+
+        boolean updateResult = weiXinPayService.updateOrderCallback(outTradeNo, xmlStr);
+        if (!updateResult) {
+            LOG.info("更新微信支付订单回调xml失败");
+            return null;
+        }
+
+        String agentId = weiXinPay.getAgentId();
+        if (StringUtils.isBlank(agentId)) {
+            LOG.info("微信支付订单对应的商家id为空");
+            return null;
+        }
+
+        Agent agent = agentService.getAgent(agentId);
+        if (agent == null) {
+            LOG.info("未查找到商家, agentId:{}", agentId);
+            return null;
+        }
+
+        String mchAppSecret = agent.getMchAppSecret();
+        if (StringUtils.isBlank(mchAppSecret)) {
+            LOG.info("商家mchAppSecret为空, agentId:{}", agentId);
+            return null;
+        }
+
+        result.remove(signKey);
+        String generateSign = SignFactory.generate(result, mchAppSecret);
+        LOG.info("生成的sign: {}", generateSign);
+        if (!sign.equals(generateSign)) {
+            LOG.info("签名验证失败");
+            return null;
+        }
+
+
+        final String returnCodeKey = "return_code";
+        String returnCode = result.get(returnCodeKey);
+        if ("SUCCESS".equals(returnCode)) {
+            final String payMoneyKey = "total_fee";
+            String payMoney = result.get(payMoneyKey);
+            if (StringUtils.isBlank(payMoney) || !NumberUtils.isDigits(payMoney)) {
+                LOG.info("订单支付金额非法, payMoney:{}", payMoney);
+                return null;
+            }
+
+            if (Integer.parseInt(payMoney) != weiXinPay.getDeposit()) {
+                LOG.info("支付金额与订单金额不一致, payMoney:{}, deposit:{}", payMoney, weiXinPay.getDeposit());
+                weiXinPayService.updateOrderStatus(weiXinPay.getId(), WeiXinPay.ORDER_STATUS_MONEY_ERROR);
+                return null;
+            } else {
+                weiXinPayService.updateOrderStatus(weiXinPay.getId(), WeiXinPay.ORDER_STATUS_SUCCESS);
+                depositService.updatePayStatus(weiXinPay.getOrderNo(), transactionId, "1");
+
+                PayParameterJson payParameterJson = JSON.parseObject(weiXinPay.getParameterJson(), PayParameterJson.class);
+
+                saveDisplaceOffUser(weiXinPay, payParameterJson);
+                /* 手机端用户不能设置通票 wangqing 201811302208
+                if (payParameterJson.getTp() == 1) {
+                    diggerAgentService.updateTp(weiXinPay.getDiggerAgentId(), payParameterJson.getTp() + "");
+                }
+                */
+            }
+
+        } else {
+            boolean updateStatusResult = weiXinPayService.updateOrderStatus(weiXinPay.getId(), WeiXinPay.ORDER_STATUS_FAUILRE);
+            if (!updateStatusResult) {
+                LOG.info("更新订单状态失败");
+                return null;
+            }
+        }
+
+        LOG.info("退出微信订单支付回调, result => {}", response);
+        return response;
+    }
+
+    /**
+     * 保存置换报价用户信息
+     * @param weiXinPay 微信支付
+     * @param payParameterJson 支付参数
+     */
+    private void saveDisplaceOffUser(WeiXinPay weiXinPay, PayParameterJson payParameterJson) {
+        LOG.info("进入保存置换报价用户信息, weiXinPay:{}, payParameterJson:{}", weiXinPay, payParameterJson);
+
+        DisplaceOfferUser displaceOfferUser = new DisplaceOfferUser();
+        displaceOfferUser.setDisplaceId(weiXinPay.getProductId());
+        displaceOfferUser.setCreateTime(new Date());
+        displaceOfferUser.setMobile(payParameterJson.getMobile());
+        displaceOfferUser.setName(payParameterJson.getName());
+        displaceOfferUser.setDiggerAgentId(weiXinPay.getDiggerAgentId());
+
+        final boolean saveResult = displaceOfferUserService.save(displaceOfferUser);
+        LOG.info("退出保存置换报价用户信息, result => {}", saveResult);
+    }
+
+    /**
+     * 解析回调xml
+     * @param xmlStr xml
+     * @return
+     */
+    private Map<String, String> parseCallBack(String xmlStr) {
+        LOG.info("进入解析微信支付回调xml, xmlStr:{}", xmlStr);
+
+        SAXReader reader = new SAXReader();
+        Document document;
+
+        byte[] bytes;
+        try {
+            bytes = xmlStr.getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            LOG.error("编码响应内容异常", e);
+            return null;
+        }
+
+        try {
+            reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+            reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
+            reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+
+            document = reader.read(new ByteInputStream(bytes, bytes.length));
+        } catch (Exception e) {
+            LOG.error("读取响应内容异常", e);
+            return null;
+        }
+
+        Map<String, String> result = new HashMap<>();
+        Element root = document.getRootElement();
+        List<Element> elements = root.elements();
+        for (Element element : elements) {
+            result.put(element.getName(), element.getStringValue());
+        }
+        LOG.info("退出解析微信支付回调xml, result => {}", result);
+        return result;
+    }
+
+    private static class OrderResponse {
+        private Map<String, String> attributeMap = new HashMap<>();
+
+        public OrderResponse() {
+            attributeMap.put("return_code", "returnCode");
+            attributeMap.put("return_msg", "returnMsg");
+            attributeMap.put("appid", "appId");
+            attributeMap.put("mch_id", "mchId");
+            attributeMap.put("device_info", "deviceInfo");
+            attributeMap.put("nonce_str", "nonceStr");
+            attributeMap.put("sign", "sign");
+            attributeMap.put("result_code", "resultCode");
+            attributeMap.put("err_code", "errCode");
+            attributeMap.put("err_code_des", "errCodeDes");
+            attributeMap.put("trade_type", "tradeType");
+            attributeMap.put("prepay_id", "prepayId");
+            attributeMap.put("code_url", "codeUrl");
+        }
+
+        @Override
+        public String toString() {
+            return JSON.toJSONString(this);
+        }
+
+        public String getAttribute(String key) {
+            return attributeMap.get(key);
+        }
+
+        private String returnCode;
+        private String returnMsg;
+        private String appId;
+        private String mchId;
+        private String deviceInfo;
+        private String nonceStr;
+        private String sign;
+        private String resultCode;
+        private String errCode;
+        private String errCodeDes;
+        private String tradeType;
+        private String prepayId;
+        private String codeUrl;
+
+        public String getReturnCode() {
+            return returnCode;
+        }
+
+        public void setReturnCode(String returnCode) {
+            this.returnCode = returnCode;
+        }
+
+        public String getReturnMsg() {
+            return returnMsg;
+        }
+
+        public void setReturnMsg(String returnMsg) {
+            this.returnMsg = returnMsg;
+        }
+
+        public String getAppId() {
+            return appId;
+        }
+
+        public void setAppId(String appId) {
+            this.appId = appId;
+        }
+
+        public String getMchId() {
+            return mchId;
+        }
+
+        public void setMchId(String mchId) {
+            this.mchId = mchId;
+        }
+
+        public String getDeviceInfo() {
+            return deviceInfo;
+        }
+
+        public void setDeviceInfo(String deviceInfo) {
+            this.deviceInfo = deviceInfo;
+        }
+
+        public String getNonceStr() {
+            return nonceStr;
+        }
+
+        public void setNonceStr(String nonceStr) {
+            this.nonceStr = nonceStr;
+        }
+
+        public String getSign() {
+            return sign;
+        }
+
+        public void setSign(String sign) {
+            this.sign = sign;
+        }
+
+        public String getResultCode() {
+            return resultCode;
+        }
+
+        public void setResultCode(String resultCode) {
+            this.resultCode = resultCode;
+        }
+
+        public String getErrCode() {
+            return errCode;
+        }
+
+        public void setErrCode(String errCode) {
+            this.errCode = errCode;
+        }
+
+        public String getErrCodeDes() {
+            return errCodeDes;
+        }
+
+        public void setErrCodeDes(String errCodeDes) {
+            this.errCodeDes = errCodeDes;
+        }
+
+        public String getTradeType() {
+            return tradeType;
+        }
+
+        public void setTradeType(String tradeType) {
+            this.tradeType = tradeType;
+        }
+
+        public String getPrepayId() {
+            return prepayId;
+        }
+
+        public void setPrepayId(String prepayId) {
+            this.prepayId = prepayId;
+        }
+
+        public String getCodeUrl() {
+            return codeUrl;
+        }
+
+        public void setCodeUrl(String codeUrl) {
+            this.codeUrl = codeUrl;
+        }
+    }
+
+    @CommitTransactional
+    @Override
+    public ExecuteResult<String> refund(String id) {
+        LOG.info("进入微信退款, id:{}", id);
+
+        if (StringUtils.isBlank(id)) {
+            LOG.info("保证金id为空");
+            return new ExecuteResult<String>().setExecuteResult(false).setData("请求参数错误");
+        }
+
+        Deposit deposit = depositService.getDeposit(id);
+        if (deposit == null) {
+            LOG.info("未查询到保证金, id:{}", id);
+            return new ExecuteResult<String>().setExecuteResult(false).setData("未查询到保证金信息");
+        }
+
+        final String refunded = "2";
+        if (refunded.equals(deposit.getPayStatus())) {
+            LOG.info("保证金已退款, id:{}", id);
+            return new ExecuteResult<String>().setExecuteResult(false).setData("保证金已退款");
+        }
+
+        final String[] allowedRefund = {"1", "4"};  //已支付/退款失败
+        if (!ArrayUtils.contains(allowedRefund, deposit.getPayStatus())) {
+            LOG.info("保证金状态处于不允许退款状态, status:{}", deposit.getPayStatus());
+            return new ExecuteResult<String>().setExecuteResult(false).setData("保证金支付状态错误");
+        }
+
+        final Agent agent = agentService.getAgent(deposit.getAgentId());
+        if (agent == null) {
+            LOG.info("未查找到商家, agentId:{}", deposit.getAgentId());
+            return new ExecuteResult<String>().setExecuteResult(false).setData("未查找到支付保证金对应的商家信息");
+        }
+
+        final String apiUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
+
+        final String outRefundNo;
+        if (StringUtils.isBlank(deposit.getRefundNo())) {
+            LOG.info("微信退款单号为空,自动生成单号");
+            outRefundNo = generateTradeNo(agent.getAgentId(), deposit.getDaId());
+        } else {
+            LOG.info("微信退款单号不为空, 使用已存在单号. {}", deposit.getRefundNo());
+            outRefundNo = deposit.getRefundNo();
+        }
+
+        ApplyRefundParameter refundParameter = new ApplyRefundParameter();
+        refundParameter.setAppId(agent.getAppId());
+        refundParameter.setMchId(agent.getMchAppId());
+        refundParameter.setNonceStr(RandomUtils.generate(10));
+        refundParameter.setTransactionId(deposit.getWxPayNo());
+        refundParameter.setOutRefundNo(outRefundNo);
+        final int depositAmount = deposit.getPayAmout().intValue();
+        refundParameter.setTotalFee(depositAmount);
+        refundParameter.setRefundFee(depositAmount);
+        refundParameter.setNotifyUrl(domain + "/pay/refund/" + deposit.getId() + "/callback");
+        refundParameter.setSign(SignFactory.generate(refundParameter.createRequestParameter(), agent.getAppSecret()));
+
+        final String refundFail = "4";
+        String content = null;
+
+        final HttpResult httpResult = HttpUtils.post(apiUrl, refundParameter.toString().getBytes(StandardCharsets.UTF_8));
+        if (httpResult.getStatusCode() != 200) {
+            LOG.info("请求微信退款接口失败, statusCode:{}", httpResult.getStatusCode());
+            updateApplyRefund(deposit.getId(), refunded, content);
+            return new ExecuteResult<String>().setExecuteResult(false).setData("请求微信退款接口失败");
+        }
+
+        content = httpResult.getContent();
+        if (StringUtils.isBlank(content)) {
+            LOG.info("请求微信退款接口, 响应内容为空");
+            updateApplyRefund(deposit.getId(), refundFail, content);
+            return new ExecuteResult<String>().setExecuteResult(false).setData("请求微信退款接口失败");
+        }
+
+        LOG.debug("请求微信退款接口, 响应内容:{}", content);
+
+        ApplyRefundResponse applyRefundResponse = new ApplyRefundResponse();
+        try {
+            applyRefundResponse.parseResponse(content);
+        } catch (DocumentException e) {
+            LOG.error("解析申请微信退款响应内容异常", e);
+            updateApplyRefund(deposit.getId(), refundFail, content);
+            return new ExecuteResult<String>().setExecuteResult(false).setData("请求微信退款接口失败");
+        }
+
+        if ("SUCCESS".equals(applyRefundResponse.getReturnCode())) {
+            if ("SUCCESS".equals(applyRefundResponse.getResultCode())) {
+                LOG.info("请求微信申请退款成功");
+                final String applyRefundSuccess = "3";
+                updateApplyRefund(deposit.getId(), applyRefundSuccess, content);
+                return new ExecuteResult<String>().setExecuteResult(true);
+            } else {
+                LOG.info("请求微信申请退款失败");
+                updateApplyRefund(deposit.getId(), refundFail, content);
+                return new ExecuteResult<String>().setExecuteResult(false).setData(applyRefundResponse.getErrCodeDes());
+            }
+        } else {
+            LOG.info("请求微信申请退款失败");
+            updateApplyRefund(deposit.getId(), refundFail, content);
+            return new ExecuteResult<String>().setExecuteResult(false).setData(applyRefundResponse.getReturnMsg());
+        }
+    }
+
+    @CommitTransactional
+    @Override
+    public String refundCallback(String depositId, String xml) {
+        LOG.info("进入微信退款回调, depositId:{}, xml:{}", depositId, xml);
+
+        final Deposit deposit = depositService.getDeposit(depositId);
+        if (deposit == null) {
+            LOG.info("未查找到保证金, depositId:{}", depositId);
+            return "FAIL";
+        }
+
+        if ("2".equals(deposit.getPayStatus())) {
+            LOG.info("保证金已退款, depositId:{}", deposit);
+            return "SUCCESS";
+        }
+
+        if (!"3".equals(deposit.getPayStatus())) {
+            LOG.info("保证金状态未非退款中状态, status:{}", deposit.getPayStatus());
+            return "FAIL";
+        }
+
+        final Agent agent = agentService.getAgent(deposit.getAgentId());
+        if (agent == null) {
+            LOG.info("未查找到商家, agentId:{}", deposit.getAgentId());
+            return "FAIL";
+        }
+
+        final String refundFail = "4";
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+        SAXReader reader = new SAXReader();
+        try {
+            final Document document = reader.read(inputStream);
+            final Element rootElement = document.getRootElement();
+            final String returnCode = rootElement.element("return_code").getStringValue();
+
+            if ("SUCCESS".equals(returnCode)) {
+                final Element reqInfo = rootElement.element("req_info");
+                if (reqInfo == null) {
+                    LOG.info("xml中未包含req_info节点");
+                    updateRefund(depositId, refundFail, xml);
+                    return "FAIL";
+                }
+                final String reqInfoContent = reqInfo.getStringValue();
+                final byte[] decodeBase64 = Base64.decodeBase64(reqInfoContent.getBytes(StandardCharsets.UTF_8));
+                final String secretMD5 = DigestUtils.md5Hex(agent.getMchAppSecret()).toLowerCase();
+                final String name = "AES/ECB/PKCS7Padding";
+                String decryptXml;
+                try {
+                    Cipher cipher = Cipher.getInstance(name, "BC");
+                    SecretKeySpec keySpec = new SecretKeySpec(secretMD5.getBytes(StandardCharsets.UTF_8), "AES");
+                    cipher.init(Cipher.DECRYPT_MODE, keySpec);
+                    byte[] decoded = cipher.doFinal(decodeBase64);
+                    decryptXml = new String(decoded, StandardCharsets.UTF_8);
+                    LOG.info("微信退款解密xml:{}", decryptXml);
+                } catch (Exception e) {
+                    LOG.error("解密微信退款xml异常", e);
+                    updateRefund(depositId, refundFail, xml);
+                    return "FAIL";
+                }
+
+                ByteArrayInputStream inputStream1 = new ByteArrayInputStream(decryptXml.getBytes(StandardCharsets.UTF_8));
+                SAXReader reader1 = new SAXReader();
+                final Document document1 = reader1.read(inputStream1);
+                final Element rootElement1 = document1.getRootElement();
+                final String refundStatus = rootElement1.element("refund_status").getStringValue();
+                final String refundSuccess = "2";
+                updateRefund(depositId, "SUCCESS".equalsIgnoreCase(refundStatus) ? refundSuccess : refundFail, xml);
+                LOG.info("退出微信退款回调");
+                return "SUCCESS";
+
+            } else {
+                LOG.info("微信退款失败");
+                updateRefund(depositId, refundFail, xml);
+                return "FAIL";
+            }
+
+        } catch (Exception e) {
+            LOG.error("解析微信退款回调xml异常", e);
+            updateRefund(depositId, refundFail, xml);
+            return "FAIL";
+        }
+    }
+
+    private void updateApplyRefund(String id, String status, String xml) {
+        depositService.updateApplyRefund(id, status, xml);
+    }
+
+    private void updateRefund(String id, String status, String xml) {
+        depositService.updateRefund(id, status, xml);
+    }
+}

+ 3 - 2
wjj-core/src/main/resources/mybatis/DepositMapper.xml

@@ -4,8 +4,8 @@
 
     <!--插入保证金-->
     <insert id="insert">
-        INSERT INTO tb_deposit(id, da_id, agent_id, agent_name, product_name, wx_pay_no, pay_amout, pay_status, pay_create_time, is_common, agent_pay_no)
-        VALUES(#{id}, #{daId}, #{agentId}, #{agentName}, #{productName}, #{wxPayNo}, #{payAmout}, #{payStatus}, #{payCreatetime}, #{isCommon}, #{agentPayNo})
+        INSERT INTO tb_deposit(id, da_id, agent_id, agent_name, product_name, wx_pay_no, pay_amout, pay_status, pay_create_time, is_common, agent_pay_no,user_type)
+        VALUES(#{id}, #{daId}, #{agentId}, #{agentName}, #{productName}, #{wxPayNo}, #{payAmout}, #{payStatus}, #{payCreatetime}, #{isCommon}, #{agentPayNo}, #{userType})
     </insert>
 
     <!--更新保证金支付状态-->
@@ -37,6 +37,7 @@
         <result column="pay_create_time" property="payCreatetime"/>
         <result column="refund_create_time" property="refundCreateTime"/>
         <result column="is_common" property="isCommon"/>
+        <result column="user_type" property="userType"/>
     </resultMap>
 
     <!--查询保证金-->

+ 1 - 1
wjj-core/src/main/resources/mybatis/SaleMapper.xml

@@ -52,7 +52,7 @@
     </select>
 
     <select id="selectSaleOfId" resultMap="sale">
-        SELECT s.id, s.agent_id, s.agent_name, s.sale_id, s.sale_name, s.sale_phone, s.sale_wxnc,s.wx_openid
+        SELECT s.id, s.agent_id, s.agent_name, s.sale_id, s.sale_name, s.sale_phone, s.sale_wxnc,s.wx_openid,s.member_level,s.integral,s.plat_tp_set,s.deposit
         FROM tb_sales s
         WHERE s.regeister_status = '1' AND s.agent_opt = '1' AND s.sale_id = #{saleId}
     </select>