瀏覽代碼

添加取消订单接口

houweiyu 4 年之前
父節點
當前提交
4743ca7162

+ 3 - 0
dinner-core/src/main/java/com/fdage/base/entity/TmOrder.java

@@ -114,4 +114,7 @@ public class TmOrder implements Serializable {
     @ApiModelProperty(value = "预订人用户头像链接")
     private String reserveUserAvatar;
 
+    @ApiModelProperty(value = "退款流水ID")
+    private String refundId;
+
 }

+ 1 - 0
dinner-core/src/main/java/com/fdage/base/enums/IdPreEnum.java

@@ -12,6 +12,7 @@ public enum IdPreEnum {
     ORDER_PRE("ORD00001" , "订单ID前缀"),
     USER_PRE("USER0001" , "用户ID前缀"),
     FEEDBACK_PRE("FEEDBACK" , "反馈ID前缀"),
+    WX_REFUND_PRE("WXREFUND" , "微信支付退款流水ID前缀"),
     ;
 
     private String pre;

+ 13 - 0
dinner-core/src/main/java/com/fdage/base/service/impl/TmDeskServiceImpl.java

@@ -5,10 +5,14 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.fdage.base.entity.TmDesk;
 import com.fdage.base.dao.TmDeskDao;
+import com.fdage.base.entity.TmOrder;
 import com.fdage.base.service.ITmDeskService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
 
 /**
  * <p>
@@ -34,4 +38,13 @@ public class TmDeskServiceImpl extends ServiceImpl<TmDeskDao, TmDesk> implements
         return getBaseMapper().selectPage(page , lambdaQueryWrapper);
     }
 
+    @Transactional(rollbackFor = Exception.class)
+    public int updateWithId(TmDesk tmDesk){
+        if(null == tmDesk || null == tmDesk.getId()){
+            return -1;
+        }
+        tmDesk.setUpdateTime(LocalDateTime.now());
+        return getBaseMapper().updateById(tmDesk);
+    }
+
 }

+ 9 - 0
dinner-core/src/main/java/com/fdage/base/service/impl/TmOrderServiceImpl.java

@@ -105,5 +105,14 @@ public class TmOrderServiceImpl extends ServiceImpl<TmOrderDao, TmOrder> impleme
         return getBaseMapper().updateById(tmOrder);
     }
 
+    @Transactional(rollbackFor = Exception.class)
+    public int updateWithId(TmOrder tmOrder){
+        if(null == tmOrder || null == tmOrder.getId()){
+            return -1;
+        }
+        tmOrder.setUpdateTime(LocalDateTime.now());
+        return getBaseMapper().updateById(tmOrder);
+    }
+
 
 }

+ 63 - 3
dinner-core/src/main/java/com/fdage/base/utils/WechatUtil.java

@@ -55,7 +55,33 @@ public class WechatUtil {
      * @param
      * @return
      */
-    public static WechatRefundApiResult wxRefund(String out_trade_no, Double orderMoney, Double refundMoney) {
+    public static WechatRefundApiResult wxRefund(String out_trade_no,
+                                                 String outRefundId ,
+                                                 Double orderMoney, Double refundMoney) {
+        //初始化请求微信服务器的配置信息包括appid密钥等
+        //转换金钱格式
+        BigDecimal bdOrderMoney = new BigDecimal(orderMoney, MathContext.DECIMAL32);
+        BigDecimal bdRefundMoney = new BigDecimal(refundMoney, MathContext.DECIMAL32);
+        //构建请求参数
+//        Map<Object, Object> params = buildRequsetMapParam(out_trade_no, bdOrderMoney, bdRefundMoney);
+        Map<Object, Object> params = buildRequsetMapParam(out_trade_no, outRefundId , bdOrderMoney, bdRefundMoney);
+        String mapToXml = MapUtils.convertMap2Xml(params);
+        //请求微信
+        String reponseXml = sendSSLPostToWx(mapToXml, WechatConfig.getSslcsf());
+        WechatRefundApiResult result = (WechatRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundApiResult.class);
+        return result;
+    }
+
+    /**
+     * 方法描述:微信退款逻辑
+     * 创建时间:2017年4月12日  上午11:04:25
+     * 作者: xubo
+     *
+     * @param
+     * @return
+     */
+    public static WechatRefundApiResult wxRefund(String out_trade_no,
+                                                 Double orderMoney, Double refundMoney) {
         //初始化请求微信服务器的配置信息包括appid密钥等
         //转换金钱格式
         BigDecimal bdOrderMoney = new BigDecimal(orderMoney, MathContext.DECIMAL32);
@@ -101,6 +127,39 @@ public class WechatUtil {
     }
 
     /**
+     * 方法描述:得到请求微信退款请求的参数
+     * 创建时间:2017年6月8日  上午11:27:02
+     * 作者: xubo
+     *
+     * @param
+     * @return
+     */
+    private static Map<Object, Object> buildRequsetMapParam(String out_trade_no, String outRefundNo,
+                                                            BigDecimal bdOrderMoney,
+                                                            BigDecimal bdRefundMoney) {
+        Map<Object, Object> params = new HashMap<Object, Object>();
+        //微信分配的公众账号ID(企业号corpid即为此appId)
+        params.put("appid", ResourceUtil.getConfigByName("wx.appId"));
+        //微信支付分配的商户号
+        params.put("mch_id", ResourceUtil.getConfigByName("wx.mchId"));
+        //随机字符串,不长于32位。推荐随机数生成算法
+        params.put("nonce_str", DataUtils.getRandomString(16));
+        //商户侧传给微信的订单号
+        params.put("out_trade_no", out_trade_no);
+        //商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
+        params.put("out_refund_no", outRefundNo);
+        //订单总金额,单位为分,只能为整数
+        params.put("total_fee", bdOrderMoney.multiply(new BigDecimal(100)).intValue());
+        //退款总金额,订单总金额,单位为分,只能为整数
+        params.put("refund_fee", bdRefundMoney.multiply(new BigDecimal(100)).intValue());
+        //操作员帐号, 默认为商户号
+        params.put("op_user_id", ResourceUtil.getConfigByName("wx.mchId"));
+        //签名前必须要参数全部写在前面
+        params.put("sign", arraySign(params, ResourceUtil.getConfigByName("wx.paySignKey")));
+        return params;
+    }
+
+    /**
      * 请求微信https
      **/
     public static String sendSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf) {
@@ -144,7 +203,7 @@ public class WechatUtil {
      * @param
      * @return
      */
-    public Map<String, Object> wxRefundquery(String out_trade_no, String out_refund_no) {
+    public static Map<String, Object> wxRefundquery(String out_trade_no, String out_refund_no) {
         Map<Object, Object> params = new HashMap<Object, Object>();
         //微信分配的公众账号ID(企业号corpid即为此appId)
         params.put("appid", ResourceUtil.getConfigByName("wx.appId"));
@@ -154,6 +213,7 @@ public class WechatUtil {
         params.put("nonce_str", DataUtils.getRandomString(16));
         //商户侧传给微信的订单号
         params.put("out_trade_no", out_trade_no);
+        params.put("out_refund_no", out_refund_no);
         //签名前必须要参数全部写在前面
         //签名
         params.put("sign", arraySign(params, ResourceUtil.getConfigByName("wx.paySignKey")));
@@ -173,7 +233,7 @@ public class WechatUtil {
             response = httpClient.execute(httPost);
             HttpEntity entity = response.getEntity();
             String xmlStr = EntityUtils.toString(entity, "UTF-8");
-            System.out.println(xmlStr);
+            log.info("微信退款查询接口返回:{}",xmlStr);
             Map<String, Object> result = XmlUtil.xmlStrToMap(xmlStr);//.xmlStrToBean(xmlStr, WechatRefundApiResult.class);
             return result;
             //将信息保存到数据库

+ 74 - 0
dinner-core/src/main/java/com/fdage/controller/app/AppOrderController.java

@@ -3,16 +3,22 @@ package com.fdage.controller.app;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.fdage.base.dto.OrderAndCanteenRspDto;
 import com.fdage.base.dto.OrderAppReqDto;
+import com.fdage.base.dto.WechatRefundApiResult;
 import com.fdage.base.entity.TmCanteen;
 import com.fdage.base.entity.TmOrder;
 import com.fdage.base.entity.TmUser;
+import com.fdage.base.enums.IdPreEnum;
+import com.fdage.base.enums.OrderPayStatusEnum;
+import com.fdage.base.enums.OrderStatusEnum;
 import com.fdage.base.service.impl.TmCanteenServiceImpl;
 import com.fdage.base.service.impl.TmOrderServiceImpl;
 import com.fdage.base.utils.DataUtils;
+import com.fdage.base.utils.WechatUtil;
 import com.fdage.controller.BaseController;
 import fdage.back.sdk.base.entity.Result;
 import fdage.back.sdk.base.enums.ResultCodeEnum;
 import fdage.back.sdk.base.exception.CommonBaseException;
+import fdage.back.sdk.base.uuid.SnowFlakeUUidUtils;
 import fdage.back.sdk.core.alibabaUtils.AlibabaSmsService;
 import fdage.back.sdk.utils.ResourceUtil;
 import io.swagger.annotations.Api;
@@ -24,8 +30,10 @@ import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -101,6 +109,72 @@ public class AppOrderController extends BaseController {
         }
         return Result.success(tmOrder);
     }
+
+    @PostMapping("/cancelOrder")
+    @ApiOperation(value = "取消预定")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<TmOrder> cancelOrder(@RequestParam(value = "orderId") String orderId){
+
+        if(StringUtils.isBlank(orderId)){
+            return Result.failure("订单号不能为空");
+        }
+        TmOrder dbOrder = tmOrderService.getById(orderId);
+        if(null == dbOrder){
+            return Result.failure("订单号不存在");
+        }
+        //1、检查订单状态
+        if(null != dbOrder.getStatus()){
+            if(OrderStatusEnum.ORDER_CANCEL.getStatus().compareTo(dbOrder.getStatus()) == 0 ){
+                return Result.failure("订单号已经取消");
+            }
+            if(OrderStatusEnum.ORDER_USED.getStatus().compareTo(dbOrder.getStatus()) == 0){
+                return Result.failure("订单号已经使用,无法取消");
+            }
+        }
+        //2、检查订单支付状态
+        if(null != dbOrder.getPayStatus()){
+            if(OrderPayStatusEnum.REFUND_SUCCESS.getStatus().compareTo(dbOrder.getPayStatus()) == 0){
+                //这里更新订单的状态??? TODO:先去微信支付查询再反转状态?
+                dbOrder.setStatus(OrderStatusEnum.ORDER_CANCEL.getStatus());
+                dbOrder.setUpdateTime(LocalDateTime.now());
+                //更新订单状态为已经取消
+                if(!tmOrderService.updateById(dbOrder)){
+                    throw new CommonBaseException(ResultCodeEnum.D101 , "更新订单状态失败");
+                }
+                return Result.failure("订单号已退款成功");
+            }else if(OrderPayStatusEnum.REFUND_FAIL.getStatus().compareTo(dbOrder.getPayStatus()) == 0){
+                //上次退款失败,需要调用查询接口去查询
+                //TODO:
+
+            }
+        }
+        String refundId = SnowFlakeUUidUtils.generaUUid(null , null , IdPreEnum.WX_REFUND_PRE.getPre());
+        dbOrder.setPayStatus(OrderPayStatusEnum.REFUND_ING.getStatus());
+        dbOrder.setUpdateTime(LocalDateTime.now());
+        dbOrder.setRefundId(refundId);
+        if(!tmOrderService.updateById(dbOrder)){
+            throw new CommonBaseException(ResultCodeEnum.D101 , "更新订单状态为退款中失败");
+        }
+        //执行退款逻辑
+        WechatRefundApiResult result = WechatUtil.wxRefund(dbOrder.getId(), refundId ,
+                dbOrder.getOrderPrice().doubleValue(), dbOrder.getOrderPrice().doubleValue());
+        if (null != result && result.getResult_code().equals("SUCCESS")) {
+            dbOrder.setStatus(OrderStatusEnum.ORDER_CANCEL.getStatus());
+            dbOrder.setPayStatus(OrderPayStatusEnum.REFUND_SUCCESS.getStatus());
+            dbOrder.setUpdateTime(LocalDateTime.now());
+            if(!tmOrderService.updateById(dbOrder)){
+                throw new CommonBaseException(ResultCodeEnum.D101 , "更新订单状态为退款成功失败");
+            }
+            return Result.success( "成功退款");
+        } else {
+            dbOrder.setPayStatus(OrderPayStatusEnum.REFUND_FAIL.getStatus());
+            dbOrder.setUpdateTime(LocalDateTime.now());
+            if(!tmOrderService.updateById(dbOrder)){
+                throw new CommonBaseException(ResultCodeEnum.D101 , "更新订单状态为退款成功失败");
+            }
+            return Result.failure( "退款失败");
+        }
+    }
     @PostMapping("/addNew")
     @ApiOperation(value = "创建订单")
     public Result<TmOrder> addNew(@RequestBody OrderAppReqDto orderAppReqDto){

+ 92 - 22
dinner-core/src/main/java/com/fdage/controller/app/AppPayController.java

@@ -21,6 +21,7 @@ import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.log4j.Log4j2;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
@@ -162,35 +163,104 @@ public class AppPayController extends BaseController {
         return Result.failure("下单失败");
     }
 
-    /**
-     * 订单退款请求
-     */
-    @ApiOperation(value = "订单退款请求")
-    @PostMapping("refund")
-    public Object refund(Integer orderId) {
-        //
-        TmOrder orderInfo = tmOrderService.getById(orderId);
 
-        if (null == orderInfo) {
-            return Result.failure( "订单已取消");
+    @ApiOperation(value = "订单退款查询")
+    @PostMapping("refundQuery")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "orderId", value = "订单号", paramType = "query", required = true, dataType = "String")
+    })
+    public Object refund(@RequestParam(name = "orderId") String orderId) {
+
+        if(StringUtils.isBlank(orderId)){
+            return Result.failure("订单号不能为空");
+        }
+        TmOrder dbOrder = tmOrderService.getById(orderId);
+        if (null == dbOrder) {
+            return Result.failure( "订单不存在");
+        }
+        //1、检查订单状态
+        if(null != dbOrder.getStatus()){
+            if(OrderStatusEnum.ORDER_CANCEL.getStatus().compareTo(dbOrder.getStatus()) == 0 ){
+                return Result.failure("订单号已经取消");
+            }
+            if(OrderStatusEnum.ORDER_USED.getStatus().compareTo(dbOrder.getStatus()) == 0){
+                return Result.failure("订单号已经使用,无法取消");
+            }
         }
+        //2、检查订单支付状态
+        if(null != dbOrder.getPayStatus()){
+            if(OrderPayStatusEnum.REFUND_SUCCESS.getStatus().compareTo(dbOrder.getPayStatus()) == 0){
+                //这里更新订单的状态??? TODO:先去微信支付查询再反转状态?
+                dbOrder.setStatus(OrderStatusEnum.ORDER_CANCEL.getStatus());
+                //更新订单状态为已经取消
+                if(tmOrderService.updateWithId(dbOrder) != 1){
+                    throw new CommonBaseException(ResultCodeEnum.D101 , "更新订单状态失败");
+                }
+                return Result.failure("订单号已退款成功");
+            }else if(OrderPayStatusEnum.REFUND_FAIL.getStatus().compareTo(dbOrder.getPayStatus()) == 0){
+                //上次退款失败,需要调用查询接口去查询
+                //TODO:
 
-        if (orderInfo.getStatus() == 401 || orderInfo.getStatus() == 402) {
-            return Result.failure("订单已退款");
+            }
+        }
+        Map<String, Object> result = WechatUtil.wxRefundquery(dbOrder.getOrderNo() , dbOrder.getRefundId());
+        if(null == result || result.isEmpty()){
+            throw new CommonBaseException(ResultCodeEnum.D101 , "微信返回异常");
         }
-        WechatRefundApiResult result = WechatUtil.wxRefund(orderInfo.getId(),
-                orderInfo.getOrderPrice().doubleValue(), orderInfo.getOrderPrice().doubleValue());
-        if (result.getResult_code().equals("SUCCESS")) {
-            if (orderInfo.getStatus() == 201) {
-                orderInfo.setStatus(3);
-            } else if (orderInfo.getStatus() == 300) {
-                orderInfo.setStatus(3);
+        // 响应报文
+        String returnCode = MapUtils.getString("return_code", result);
+        String returnMsg = MapUtils.getString("return_msg", result);
+        if (StringUtils.isNotBlank(returnCode) && returnCode.equals("SUCCESS")) {
+            String refundStatus = "";
+            //TODO:改成jdk8的形式
+            for ( String key : result.keySet()) {
+                if(key.startsWith("refund_status_")){
+                    refundStatus = (String) result.get(key);
+                    break;
+                }
             }
-            tmOrderService.updateById(orderInfo);
-            return Result.success( "成功退款");
+            if("SUCCESS".equals(refundStatus)){
+                //退款成功,更新状态
+                boolean needUpdate = false;
+                if(null != dbOrder.getStatus()  && OrderStatusEnum.ORDER_CANCEL.getStatus().compareTo(dbOrder.getStatus()) != 0){
+                    needUpdate = true;
+                    dbOrder.setStatus(OrderStatusEnum.ORDER_CANCEL.getStatus());
+                }
+                if(null != dbOrder.getPayStatus() && OrderPayStatusEnum.REFUND_SUCCESS.getStatus().compareTo(dbOrder.getPayStatus()) != 0){
+                    needUpdate = true;
+                    dbOrder.setPayStatus(OrderPayStatusEnum.REFUND_SUCCESS.getStatus());
+                }
+                if(needUpdate){
+                    if(tmOrderService.updateWithId(dbOrder) != 1){
+                        throw new CommonBaseException(ResultCodeEnum.D101 , "更新订单为取消成功状态失败");
+                    }
+                    TmDesk tmDesk = tmDeskService.getById(dbOrder.getDeskId());
+                    if(null != tmDesk){
+                        if(null == tmDesk.getStatus() || tmDesk.getStatus().compareTo(1) == 0){
+                            tmDesk.setStatus(0);
+                            if(tmDeskService.updateWithId(tmDesk) != 1){
+                                throw new CommonBaseException(ResultCodeEnum.D101 , "更新订单为取消成功状态失败");
+                            }
+                        }
+                    }
+                }
+                return Result.success( "退款成功");
+            }else if("REFUNDCLOSE".equals(refundStatus)){
+                log.info("微信支付退款查询,微信返回退款关闭");
+                //退款关闭
+            }else if("PROCESSING".equals(refundStatus)){
+                //退款处理中
+                log.info("微信支付退款查询,微信返回退款处理中");
+            }else if("CHANGE".equals(refundStatus)){
+                //退款异常
+                log.info("微信支付退款查询,微信返回退款异常");
+            }
+            return Result.success( "退款处理中");
         } else {
-            return Result.failure( "退款失败");
+            return Result.failure( "退款查询失败:"+ returnMsg);
         }
+
+
     }