From ea8fec4b56d4a5cce828c15d72b08219f5844126 Mon Sep 17 00:00:00 2001 From: xiaohanzi Date: Sat, 13 Jun 2020 21:23:00 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8B=BC=E5=9B=A2?= =?UTF-8?q?=E3=80=81=E5=AE=9A=E6=97=B6=E3=80=81=E9=80=80=E6=AC=BE=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E6=97=B6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../schedule/OrderExpiringSchedule.java | 127 ++++++++++++++---- .../iformall/service/WxPayOrderService.java | 2 + .../service/impl/WxOrderGroupServiceImpl.java | 28 ++-- .../service/impl/WxPayOrderServiceImpl.java | 1 + .../impl/WxRefundOrderServiceImpl.java | 52 ++++--- 5 files changed, 156 insertions(+), 54 deletions(-) diff --git a/mallinkSchedule/src/main/java/com/iformall/schedule/OrderExpiringSchedule.java b/mallinkSchedule/src/main/java/com/iformall/schedule/OrderExpiringSchedule.java index 156c2c39e..fa5411138 100644 --- a/mallinkSchedule/src/main/java/com/iformall/schedule/OrderExpiringSchedule.java +++ b/mallinkSchedule/src/main/java/com/iformall/schedule/OrderExpiringSchedule.java @@ -1,33 +1,45 @@ package com.iformall.schedule; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.iformall.common.ErrorCode; import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxCUser; import com.iformall.domain.po.WxOrder; +import com.iformall.domain.po.WxPayAccount; +import com.iformall.domain.po.WxPayOrder; import com.iformall.enums.EnumAppType; import com.iformall.enums.EnumOrderStatus; import com.iformall.enums.EnumOrderType; +import com.iformall.enums.EnumPayStatus; import com.iformall.enums.EnumRefundStatus; import com.iformall.exception.MallinkException; import com.iformall.mapper.WxAppinfoMapper; +import com.iformall.mapper.WxCUserMapper; import com.iformall.mapper.WxCouponMapper; import com.iformall.mapper.WxOrderGroupMapper; import com.iformall.mapper.WxOrderMapper; +import com.iformall.mapper.WxPayAccountMapper; +import com.iformall.mapper.WxPayOrderMapper; +import com.iformall.service.WxAppinfoService; import com.iformall.service.WxOrderService; +import com.iformall.service.WxPayOrderService; import com.iformall.service.WxRefundOrderService; +import com.iformall.service.helper.WxPayOrderServiceHelper; import com.iformall.utils.DateUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; @Component public class OrderExpiringSchedule { @@ -53,7 +65,22 @@ public class OrderExpiringSchedule { @Autowired WxCouponMapper wxCouponMapper; - + + @Autowired + WxPayOrderMapper wxPayOrderMapper; + + @Autowired + WxCUserMapper wxCUserMapper; + + @Autowired + WxAppinfoService wxAppinfoService; + + @Autowired + WxPayAccountMapper wxPayAccountMapper; + + @Autowired + WxPayOrderService wxPayOrderService; + @Scheduled(cron = "0 */5 * * * *?") // 每5分钟检查一次 //@Scheduled(cron = "*/10 * * * * ?") // 测试10秒中一次 public void orderExpireSchedule() { @@ -62,13 +89,16 @@ public class OrderExpiringSchedule { Date curDate = new Date(); Date expireDate = new Date(curDate.getTime() - NORMAL_TIME_OUT ); + //直接调用不会触发事务,spring事务基于AOP代理 + OrderExpiringSchedule proxy = (OrderExpiringSchedule) AopContext.currentProxy(); + // 券相关订单, 15分钟未支付, 订单过期 dateMap.put("type", EnumOrderType.COUPON.getCode()); dateMap.put("endDate", expireDate); List orderCoupons = wxOrderMapper.findListOfUnpaidOrderByDate(dateMap); orderCoupons.stream().forEach( o -> { try { - orderExpired(o); + proxy.orderExpired(o); } catch (Exception e) { logger.error("券过期失败" + e.getMessage()); } @@ -82,7 +112,7 @@ public class OrderExpiringSchedule { List orderPresss = wxOrderMapper.findListOfCompleteUnPaidPressOrderByDate(dateMap); orderPresss.stream().forEach( o -> { try { - orderPressExpired(o, true); + proxy.orderPressExpired(o, true); } catch (Exception e) { logger.error("砍价券支付过期失败" + e.getMessage()); } @@ -93,7 +123,7 @@ public class OrderExpiringSchedule { orderPresss = wxOrderMapper.findListOfUnpaidPressOrderByDate(dateMap); orderPresss.stream().forEach( o -> { try { - orderPressExpired(o, false); + proxy.orderPressExpired(o, false); } catch (Exception e) { logger.error("砍价券过期失败" +e.getMessage()); } @@ -105,7 +135,7 @@ public class OrderExpiringSchedule { order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_UNPAID.getCode()); wxOrderMapper.selectList(new QueryWrapper(order)).stream().forEach(o -> { try { - orderGroupExpired((WxOrder) o); + proxy.orderGroupExpired((WxOrder) o); } catch (Exception e) { logger.error("拼团取消失败" + e.getMessage()); } @@ -117,7 +147,7 @@ public class OrderExpiringSchedule { order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_OVERTIME.getCode()); wxOrderMapper.selectList(new QueryWrapper(order)).stream().forEach(o -> { try { - returnMoney((WxOrder) o); + proxy.returnMoney((WxOrder) o); } catch (Exception e) { logger.error("拼团过期退款失败" + e.getMessage()); } @@ -128,7 +158,7 @@ public class OrderExpiringSchedule { order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_CANCEL.getCode()); wxOrderMapper.selectList(new QueryWrapper(order)).stream().forEach(o -> { try { - returnMoney((WxOrder) o); + proxy.returnMoney((WxOrder) o); } catch (Exception e) { logger.error("拼团券下架退款失败" + e.getMessage()); } @@ -138,7 +168,7 @@ public class OrderExpiringSchedule { order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_FAILD.getCode()); wxOrderMapper.selectList(new QueryWrapper(order)).stream().forEach(o -> { try { - returnMoney((WxOrder) o); + proxy.returnMoney((WxOrder) o); } catch (Exception e) { logger.error("参团失败退款失败" + e.getMessage()); } @@ -147,9 +177,49 @@ public class OrderExpiringSchedule { } + + public boolean wxPaySuccess(WxOrder order) { + WxPayOrder payOrderq = new WxPayOrder(); + payOrderq.setOrderId(order.getId()); + List payorderlist = wxPayOrderMapper.findList(payOrderq); + if (null == payorderlist || payorderlist.size() <=0 ) { + return false; + } + WxPayOrder wxpayOrder = payorderlist.get(0); + if (null == wxpayOrder) { + return false; + } + WxCUser user = wxCUserMapper.selectById(wxpayOrder.getCUserId()); + //找不到用户,问题单,不能删 + if (null == user) { + return true; + } + WxAppinfo appInfo = wxAppinfoService.getByAppId(user.getAppId()); + //找不到appInfo,问题单,不能删 + if(appInfo == null) { + return true; + } + WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); + //找不到appInfo,问题单,不能删 + if (null == payAccount) { + return true; + } + Map retMap = WxPayOrderServiceHelper.wxOrderPayStatusMap(wxpayOrder, order, appInfo, payAccount); + int status = WxPayOrderServiceHelper.getPayStatusFromMap(retMap, wxpayOrder.getPayOrderNo()); + //如果是支付成功,则更新信息 + if (EnumPayStatus.PAY_STATUS_SUCCESS.getCode() == status) { + wxPayOrderService.handleSuccessOrder(wxpayOrder, order, retMap); + return true; + } + return false; + } + + @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) public void orderExpired(WxOrder order) { - + if (wxPaySuccess(order)) { + return; + } // 库存退回 wxOrderService.stockBack(order); @@ -168,6 +238,10 @@ public class OrderExpiringSchedule { @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) public void orderPressExpired(WxOrder order, boolean payExpired) { + if (wxPaySuccess(order)) { + return; + } + Date curDate = new Date(); WxOrder updateOrder = new WxOrder(); updateOrder.setId(order.getId()); @@ -188,7 +262,11 @@ public class OrderExpiringSchedule { @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) public void orderGroupExpired(WxOrder order) { - Date curDate = new Date(); + if (wxPaySuccess(order)) { + return; + } + + Date curDate = new Date(); WxOrder updateOrder = new WxOrder(); updateOrder.setId(order.getId()); updateOrder.updateTenantInfo(order); @@ -205,7 +283,10 @@ public class OrderExpiringSchedule { @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) public void returnMoney(WxOrder order) { - + //支付成功的才退款 + if (!wxPaySuccess(order)) { + return; + } //获取APP信息 WxAppinfo appinfo = new WxAppinfo(); appinfo.updateTenantInfo(order); diff --git a/mallinkService/src/main/java/com/iformall/service/WxPayOrderService.java b/mallinkService/src/main/java/com/iformall/service/WxPayOrderService.java index 68909540b..e57ae2645 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxPayOrderService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxPayOrderService.java @@ -15,6 +15,8 @@ import com.iformall.enums.EnumPayWay; public interface WxPayOrderService { + public void handleSuccessOrder(WxPayOrder oldRecord,WxOrder order,Map retMap); + public WxPayOrder handleWxOrderQuery(WxPayOrder oldRecord,WxOrder order,WxAppinfo appInfo,WxPayAccount payAccount,IdWorker idworker,boolean repeatPay); /** diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderGroupServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderGroupServiceImpl.java index a01aad3c6..491adc7d6 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderGroupServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderGroupServiceImpl.java @@ -34,8 +34,6 @@ import java.util.stream.Collectors; public class WxOrderGroupServiceImpl implements WxOrderGroupService { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final Long notOrderGroupId = 0L; - private final int endPeople = 0; @Autowired WxOrderGroupMapper wxOrderGroupMapper; @@ -72,22 +70,30 @@ public class WxOrderGroupServiceImpl implements WxOrderGroupService { public void createOrderGroup(WxOrder order, WxCoupon wxCoupon) { Long orderGroupId = order.getOrderGroupId(); //查看是否首次拼团,orderGroupId不等于0代表不是首次拼团,因为第二个加入的拼团者肯定有团单号 - if (!orderGroupId.equals(notOrderGroupId)) { + if (!orderGroupId.equals(0L)) { // 非首次拼团 // 参与拼团 WxOrderGroup wxOrderGroup = wxOrderGroupMapper.selectById(orderGroupId); - if(wxOrderGroup.getRemainPeople() < endPeople + 1) { - logger.info(">>>>>>>>>>>>参团失败 修改订单状态后定时退款 团单号" + orderGroupId); - throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD); + if (null == wxOrderGroup) { + //错误,更新状态,定时任务会发起退款 + order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_FAILD.getCode()); + wxOrderMapper.updateById(order); + throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD.getCode(),"WxOrderGroup is null."+orderGroupId); + } + if(wxOrderGroup.getRemainPeople()<1) { + //错误,更新状态,定时任务会发起退款 + order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_FAILD.getCode()); + wxOrderMapper.updateById(order); + throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD.getCode(),"参团人数已满,将稍后退款。"); } Integer remainPeople = wxOrderGroup.getRemainPeople()-1; - wxOrderGroup.setStatus(remainPeople == endPeople ? EnumOrderStatus.ORDER_STATUS_COOPERATING_COMPLETE.getCode() : wxOrderGroup.getStatus()); + wxOrderGroup.setStatus(remainPeople == 0 ? EnumOrderStatus.ORDER_STATUS_COOPERATING_COMPLETE.getCode() : wxOrderGroup.getStatus()); wxOrderGroup.setUpdateDate(new Date()); logger.info("非首次拼团,更新拼团信息, 剩余人数-1"); int row = wxOrderGroupMapper.updateOrderGroup(wxOrderGroup); if (row != 1) { - logger.info(">>>>>>>>>>>>参团失败 修改订单状态后定时退款 团单号" + orderGroupId); - throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD); + //TODO 这个时候应该要发起异步退款。 + throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD.getCode(),"参团失败,将稍后退款."); } // 更新订单信息 @@ -100,7 +106,7 @@ public class WxOrderGroupServiceImpl implements WxOrderGroupService { logger.error("更新订单信息失败", e); throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FAILD); } - if (remainPeople == endPeople) { + if (remainPeople == 0) { actionAfterOrderGroupSuccess(order, orderGroupId); } } else { @@ -233,7 +239,7 @@ public class WxOrderGroupServiceImpl implements WxOrderGroupService { if (orderTemp == null) { return new ResultData(ErrorCode.ORDER_IS_NOT_FIND); } - if (orderTemp.getOrderGroupId().equals(notOrderGroupId)) { + if (orderTemp.getOrderGroupId().equals(0L)) { return new ResultData(ErrorCode.ORDER_GROUP_COOPERATING_FAILD); } WxCouponChannel wxCouponChannel = wxCouponChannelMapper.selectById(orderTemp.getCouponChannelId()); diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java index 5cc16d72a..206ea7065 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java @@ -120,6 +120,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { //方法必须为public AopContext.currentProxy() @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) + @Override public void handleSuccessOrder(WxPayOrder oldRecord,WxOrder order,Map retMap) { Date curDate = new Date(); if (oldRecord.getPayOrderStatus() != EnumPayStatus.PAY_STATUS_SUCCESS.getCode()) { diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java index f196bb745..6f11acde7 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java @@ -19,6 +19,7 @@ import com.iformall.pay.WxRefundOrderP; import com.iformall.pay.WxRefundOrderSP; import com.iformall.service.WxOrderService; import com.iformall.service.WxRefundOrderService; +import com.iformall.service.helper.WxPayOrderServiceHelper; import com.iformall.utils.BeanUtils; import com.iformall.utils.CipherUtil; import com.iformall.utils.Utility; @@ -317,6 +318,36 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { logger.error("已经核销过的券: couponOrder-" + couponOrderId); throw new MallinkException(ErrorCode.COUPON_ORDER_IS_USED); } + + //TODO 查询订单状态是否是支付成功的状态,支付成功的状态才能退款。 + // 查找支付订单 + WxPayOrder payOrderQ = new WxPayOrder(); + payOrderQ.updateTenantInfo(wxCouponOrder); + payOrderQ.setCUserId(wxOrder.getCUserId()); + payOrderQ.setOrderId(wxOrder.getId()); + payOrderQ.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode()); + + WxPayOrder payOrder = null; + List list = wxPayOrderMapper.findList(payOrderQ); + if (list.size() > 0) { + if (list.size() > 1) { + return new ResultData(ErrorCode.PAY_ORDER_ERROR.getCode(),"异常:该订单找到多条支付信息wxpayorder!"); + } + payOrder = list.get(0); + } + if (payOrder == null) { + logger.error("支付订单不存在(payOrder不存在)"); + return new ResultData(ErrorCode.PAY_ORDER_NOT_FOUND); + } + WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); + if (null == payAccount) { + throw new MallinkException(ErrorCode.PAY_ORDER_QUERY_ERROR.getCode(), "payAccount为空[payId:"+appInfo.getPayId()+"]"); + } + int status = WxPayOrderServiceHelper.wxOrderPayStatus(payOrder, wxOrder, appInfo, payAccount); + if (EnumPayStatus.PAY_STATUS_SUCCESS.getCode() != status) { + return new ResultData(ErrorCode.PAY_ORDER_ERROR.getCode(),"该订单查询微信支付状态为未支付成功,无法退款。"); + } + final IdWorker idWorker = IdWorker.get(); Long refundOrderId = idWorker.nextId(); @@ -377,26 +408,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { } } - // 查找支付订单 - WxPayOrder payOrderQ = new WxPayOrder(); - payOrderQ.updateTenantInfo(wxCouponOrder); - payOrderQ.setCUserId(wxOrder.getCUserId()); - payOrderQ.setOrderId(wxOrder.getId()); - payOrderQ.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode()); - WxPayOrder payOrder = null; - List list = wxPayOrderMapper.findList(payOrderQ); - if (list.size() > 0) { - if (list.size() > 1) { - logger.error("TODO: payOrder成功记录应该只有一条????!!!"); - } - logger.warn(""); - payOrder = list.get(0); - } - if (payOrder == null) { - logger.error("支付订单不存在(payOrder不存在)"); - return new ResultData(ErrorCode.PAY_ORDER_NOT_FOUND); - } WxRefundOrder record = new WxRefundOrder(); record.setPayOrderNo(String.valueOf(payOrder.getId())); @@ -428,7 +440,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { logger.error("退款订单数据库插入出错: " + record.toString()); throw new MallinkException(ErrorCode.DB_FAIL); } - WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); + if (StringUtils.isBlank(payAccount.getApiKey())) { logger.error("支付密钥为空"); throw new MallinkException(ErrorCode.API_KEY_NOT_FOUND.getCode(), "支付密钥为空,请联系商城管理员"); From 3faa3ab22332a46acdc694297f31984038cd9540 Mon Sep 17 00:00:00 2001 From: xiaohanzi Date: Sun, 14 Jun 2020 17:38:47 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=BA=93=E5=AD=98?= =?UTF-8?q?=E5=B9=B6=E5=8F=91=E8=B6=85=E5=8F=91bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/market/WxCouponController.java | 11 +- .../controller/WxCouponChannelController.java | 4 +- .../java/com/iformall/mq/MqBaseConsumer.java | 7 +- .../domain/po/msg/UpdateCouponStockMsg.java | 31 ++ .../java/com/iformall/enums/EnumCacheKey.java | 2 +- .../com/iformall/enums/EnumMsgMqTopic.java | 1 + .../com/iformall/enums/EnumMsgRecordType.java | 1 + .../com/iformall/mapper/WxCouponMapper.java | 2 +- .../com/iformall/service/WxCouponService.java | 2 +- .../service/impl/WxCouponSendServiceImpl.java | 2 +- .../service/impl/WxCouponServiceImpl.java | 4 +- .../service/impl/WxOrderServiceImpl.java | 388 +++++++++++++----- .../impl/UpdateCouponStockMsgServiceImpl.java | 35 ++ .../java/com/iformall/utils/RedisLock.java | 50 ++- 14 files changed, 415 insertions(+), 125 deletions(-) create mode 100644 mallinkService/src/main/java/com/iformall/domain/po/msg/UpdateCouponStockMsg.java create mode 100644 mallinkService/src/main/java/com/iformall/service/msg/impl/UpdateCouponStockMsgServiceImpl.java diff --git a/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponController.java b/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponController.java index fd92888e1..4fcb9b40f 100644 --- a/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponController.java +++ b/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponController.java @@ -17,6 +17,8 @@ import com.iformall.service.WxCouponPasswordService; import com.iformall.service.WxCouponService; import com.iformall.service.WxFlowService; import com.iformall.utils.DateUtils; +import com.iformall.utils.RedisLock; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -46,6 +48,8 @@ public class WxCouponController extends BaseController { private WxCouponChannelMapper wxCouponChannelMapper; @Autowired private WxFlowService wxFlowService; + @Autowired + RedisLock redisLock; @ApiOperation("分页列表接口") @GetMapping("list") @@ -95,7 +99,7 @@ public class WxCouponController extends BaseController { if (resultData.code != 200) { return resultData; } - + redisLock.setCouponStock(wxCoupon.getId(), wxCoupon.getInventory()); //启动投放审批 if(wxCoupon.getFlowParams() !=null && wxCoupon.getFlowParams().size()>0) { wxCoupon.getFlowParams().put("businessId",wxCoupon.getId()); @@ -124,7 +128,7 @@ public class WxCouponController extends BaseController { return new ResultData(ResultData.ERROR, "有活动正在上架,请先下架。"); } } - + redisLock.setCouponStock(wxCoupon.getId(), wxCoupon.getInventory()); //启动审批流 if (wxCoupon.getFlowParams() != null && wxCoupon.getFlowParams().size() > 0) { logger.info("------coupon.update().businessType:"+wxCoupon.getFlowParams().get("businessType")); @@ -139,6 +143,7 @@ public class WxCouponController extends BaseController { wxCoupon.setPutApplyStatus(EnumRentContractAppStatus.APPLYING.getCode()); } } + return wxCouponService.saveOrUpdate(wxCoupon); } @@ -246,7 +251,9 @@ public class WxCouponController extends BaseController { updateCoupon.setStockApplyStatus(EnumRentContractAppStatus.APPLYING.getCode()); updateCoupon.setUpdateDate(new Date()); wxCouponService.update(updateCoupon); + redisLock.setCouponStock(wxCoupon.getId(), wxCoupon.getInventory()); } else { + redisLock.setCouponStock(wxCoupon.getId(), wxCoupon.getInventory()); return wxCouponService.updateCouponStockAndEndTime(wxCoupon); } diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxCouponChannelController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxCouponChannelController.java index 2f615f4aa..e297af145 100644 --- a/mallinkCApi/src/main/java/com/iformall/controller/WxCouponChannelController.java +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxCouponChannelController.java @@ -43,7 +43,7 @@ public class WxCouponChannelController extends BaseController { @Autowired private WxMerchantService wxMerchantService; - @RedisCache(expireTime = 600) + @RedisCache(expireTime = 100) @ApiOperation("分页列表接口") @GetMapping("list") @ApiImplicitParams({ @@ -101,7 +101,7 @@ public class WxCouponChannelController extends BaseController { } } - @RedisCache(expireTime = 600) + @RedisCache(expireTime = 100) @ApiOperation("分页列表接口") @GetMapping("change") public ResultData change(@ModelAttribute WxCouponChannel wxCouponChannel) { diff --git a/mallinkMQConsumer/src/main/java/com/iformall/mq/MqBaseConsumer.java b/mallinkMQConsumer/src/main/java/com/iformall/mq/MqBaseConsumer.java index 8f49733a8..33df70929 100644 --- a/mallinkMQConsumer/src/main/java/com/iformall/mq/MqBaseConsumer.java +++ b/mallinkMQConsumer/src/main/java/com/iformall/mq/MqBaseConsumer.java @@ -41,7 +41,9 @@ public class MqBaseConsumer { private FmInsideNotifyPaySuccessMsgServiceImpl fmInsideNotifyPaySuccessMsgService; @Autowired private FmInsideNotifyRefundSuccessMsgServiceImpl fmInsideNotifyRefundSuccessMsgService; - + @Autowired + UpdateCouponStockMsgServiceImpl updateCouponStockMsgService; + public void doMessage(String message) { @@ -95,6 +97,9 @@ public class MqBaseConsumer { // 内部消息 - 微信退款通知 FmInsideNotifyRefundSuccessMsg msg = (FmInsideNotifyRefundSuccessMsg)JsonUtil.readValue(message,FmInsideNotifyRefundSuccessMsg.class); fmInsideNotifyRefundSuccessMsgService.send(msg); + } else if (EnumMsgRecordType.COUPON_STOCK.getCode().equals(baseMsg.getMsgType())) { + UpdateCouponStockMsg msg = (UpdateCouponStockMsg)JsonUtil.readValue(message,UpdateCouponStockMsg.class); + updateCouponStockMsgService.send(msg); } baseMsg.setMsgStatus(EnumMsgRecordStatus.CONSUME_SUCC.getCode()); wxMsgRecordMapper.updateByBaseMsg(baseMsg); diff --git a/mallinkService/src/main/java/com/iformall/domain/po/msg/UpdateCouponStockMsg.java b/mallinkService/src/main/java/com/iformall/domain/po/msg/UpdateCouponStockMsg.java new file mode 100644 index 000000000..354273ad6 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/domain/po/msg/UpdateCouponStockMsg.java @@ -0,0 +1,31 @@ +package com.iformall.domain.po.msg; + +import cn.binarywang.wx.miniapp.bean.WxMaTemplateData; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; +import java.util.Map; + +/** + * 更新券库存消息 + * @author Stormeye + * @date 2019/4/9 13:55 + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class UpdateCouponStockMsg extends BaseMsg { + private static final long serialVersionUID = 223232132183760321L; + + public static final String OPERATE_TYPE_INCREASE = "increase"; + public static final String OPERATE_TYPE_DECREASE = "decrease"; + + @io.swagger.annotations.ApiModelProperty(value="券Id",name="couponId") + private Long couponId; + @io.swagger.annotations.ApiModelProperty(value="更新数量",name="number") + private long number; + @io.swagger.annotations.ApiModelProperty(value="操作类型 1-增加库存 ,2-减少库存",name="operateType") + private String operateType; +} diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumCacheKey.java b/mallinkService/src/main/java/com/iformall/enums/EnumCacheKey.java index 0f9ac04f6..d6e2d88ac 100644 --- a/mallinkService/src/main/java/com/iformall/enums/EnumCacheKey.java +++ b/mallinkService/src/main/java/com/iformall/enums/EnumCacheKey.java @@ -9,7 +9,7 @@ import java.util.Map; public enum EnumCacheKey { C_INDEX_PAGE_LIST(0, "couponChannelList_"), - + COUPON_STOCK(1,"couponStock_") ; private static Map map = new HashMap(); static { diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumMsgMqTopic.java b/mallinkService/src/main/java/com/iformall/enums/EnumMsgMqTopic.java index 30525cfdd..e342de989 100644 --- a/mallinkService/src/main/java/com/iformall/enums/EnumMsgMqTopic.java +++ b/mallinkService/src/main/java/com/iformall/enums/EnumMsgMqTopic.java @@ -5,6 +5,7 @@ package com.iformall.enums; */ public enum EnumMsgMqTopic { DEFAULT("topic-1", "默认"), + STOCK("stock","库存"), ; public static EnumMsgMqTopic getEnum(String code) { diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumMsgRecordType.java b/mallinkService/src/main/java/com/iformall/enums/EnumMsgRecordType.java index dcb6cffb9..95b4583da 100644 --- a/mallinkService/src/main/java/com/iformall/enums/EnumMsgRecordType.java +++ b/mallinkService/src/main/java/com/iformall/enums/EnumMsgRecordType.java @@ -17,6 +17,7 @@ public enum EnumMsgRecordType { INSIDE_C_LOGIN(102, "C端用户登录"), INSIDE_NOTIFY_PAY_SUCCESS(103, "微信支付回调"), INSIDE_NOTIFY_REFUND_SUCCESS(104, "微信退款回调"), + COUPON_STOCK(105, "券库存更新"), ; public static EnumMsgRecordType getEnum(Integer code) { diff --git a/mallinkService/src/main/java/com/iformall/mapper/WxCouponMapper.java b/mallinkService/src/main/java/com/iformall/mapper/WxCouponMapper.java index 148b34fb8..46eabed99 100644 --- a/mallinkService/src/main/java/com/iformall/mapper/WxCouponMapper.java +++ b/mallinkService/src/main/java/com/iformall/mapper/WxCouponMapper.java @@ -20,7 +20,7 @@ public interface WxCouponMapper extends CommonMapper { WxCouponCVo findVoDetail(@Param("id")Long id); WxCouponCVo findVoStatusDetail(@Param("id")Long id); - Integer reduceInventory(@Param("id")Long id,@Param("number")Integer number,@Param("remainInventory")Integer remainInventory); + Integer reduceInventory(@Param("id")Long id,@Param("number")Integer number); Integer backInventory(@Param("id")Long id, @Param("number")Integer number,@Param("remainInventory")Integer remainInventory); diff --git a/mallinkService/src/main/java/com/iformall/service/WxCouponService.java b/mallinkService/src/main/java/com/iformall/service/WxCouponService.java index aec2933b7..a403d896b 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxCouponService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxCouponService.java @@ -212,7 +212,7 @@ public interface WxCouponService { * @param number 减少数量 * @param remainInventory 当前库存 */ - void reduceRemainInventory(Long id, Integer number, Integer remainInventory); + void reduceRemainInventory(Long id, Integer number); /** * 库存退回 diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxCouponSendServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxCouponSendServiceImpl.java index abd1d586d..d9cd6510f 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxCouponSendServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxCouponSendServiceImpl.java @@ -181,7 +181,7 @@ public class WxCouponSendServiceImpl implements WxCouponSendService { } //更新库存 - wxCouponService.reduceRemainInventory(wxCouponOfDb.getId(), merchantLnventory, wxCouponOfDb.getRemainInventory()); + wxCouponService.reduceRemainInventory(wxCouponOfDb.getId(), merchantLnventory); } @Override diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxCouponServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxCouponServiceImpl.java index 4b31c2d05..321fb8267 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxCouponServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxCouponServiceImpl.java @@ -714,8 +714,8 @@ public class WxCouponServiceImpl implements WxCouponService { @Override @Transactional(isolation= Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class}) - public void reduceRemainInventory(Long id, Integer number, Integer remainInventory) { - int num = wxCouponMapper.reduceInventory(id, number, remainInventory); + public void reduceRemainInventory(Long id, Integer number) { + int num = wxCouponMapper.reduceInventory(id, number); if (num == 0) { throw new MallinkException(ErrorCode.ORDER_SAVE_ERR); } diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java index 5f7673db8..84882f22b 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java @@ -1,5 +1,31 @@ package com.iformall.service.impl; +import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -10,34 +36,99 @@ import com.iformall.common.IdWorker; import com.iformall.common.ResultData; import com.iformall.domain.dto.OrderSaveDto; import com.iformall.domain.dto.WxSharingOrderDto; -import com.iformall.domain.po.*; +import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxCUser; +import com.iformall.domain.po.WxCardInfo; +import com.iformall.domain.po.WxCoupon; +import com.iformall.domain.po.WxCouponChannel; +import com.iformall.domain.po.WxCouponMerchant; +import com.iformall.domain.po.WxCouponOrder; +import com.iformall.domain.po.WxCouponPassword; +import com.iformall.domain.po.WxCouponSend; +import com.iformall.domain.po.WxCreditHistory; +import com.iformall.domain.po.WxMerchant; +import com.iformall.domain.po.WxMerchantBUser; +import com.iformall.domain.po.WxOrder; +import com.iformall.domain.po.WxOrderGroup; +import com.iformall.domain.po.WxOrderPress; +import com.iformall.domain.po.WxPayAccount; +import com.iformall.domain.po.WxPayOrder; import com.iformall.domain.po.base.TenantEntity; import com.iformall.domain.po.msg.FmInsideOrderSuccessMsg; -import com.iformall.domain.vo.*; -import com.iformall.enums.*; +import com.iformall.domain.po.msg.UpdateCouponStockMsg; +import com.iformall.domain.vo.WxCouponSendVo; +import com.iformall.domain.vo.WxMerchantVo; +import com.iformall.domain.vo.WxOrderCouponPressVo; +import com.iformall.domain.vo.WxOrderCouponVo; +import com.iformall.domain.vo.WxOrderPayExpVo; +import com.iformall.domain.vo.WxOrderPayVo; +import com.iformall.domain.vo.WxOrderQueryVo; +import com.iformall.enums.EnumAssignTagsTrigger; +import com.iformall.enums.EnumCacheKey; +import com.iformall.enums.EnumCouponChannelStatus; +import com.iformall.enums.EnumCouponConditionType; +import com.iformall.enums.EnumCouponMerchantStatus; +import com.iformall.enums.EnumCouponOrderStatus; +import com.iformall.enums.EnumCouponPasswordStatus; +import com.iformall.enums.EnumCouponPasswordSupport; +import com.iformall.enums.EnumCouponSendSendType; +import com.iformall.enums.EnumCouponSendType; +import com.iformall.enums.EnumCouponStatus; +import com.iformall.enums.EnumCouponTransfer; +import com.iformall.enums.EnumCouponType; +import com.iformall.enums.EnumMerchantStatus; +import com.iformall.enums.EnumMerchantType; +import com.iformall.enums.EnumMsgMqKey; +import com.iformall.enums.EnumMsgMqTag; +import com.iformall.enums.EnumMsgMqTopic; +import com.iformall.enums.EnumMsgRecordType; +import com.iformall.enums.EnumOrderPressType; +import com.iformall.enums.EnumOrderStatus; +import com.iformall.enums.EnumOrderType; +import com.iformall.enums.EnumPayShare; +import com.iformall.enums.EnumPayStatus; +import com.iformall.enums.EnumPayType; +import com.iformall.enums.EnumProfitSharingOrderType; +import com.iformall.enums.EnumScoreType; +import com.iformall.enums.EnumUserType; +import com.iformall.enums.EnumValidStatus; import com.iformall.exception.MallinkException; -import com.iformall.mapper.*; +import com.iformall.mapper.WxAppinfoMapper; +import com.iformall.mapper.WxCUserBasicInfoMapper; +import com.iformall.mapper.WxCUserMapper; +import com.iformall.mapper.WxCardInfoMapper; +import com.iformall.mapper.WxCouponChannelMapper; +import com.iformall.mapper.WxCouponMapper; +import com.iformall.mapper.WxCouponMerchantMapper; +import com.iformall.mapper.WxCouponOrderMapper; +import com.iformall.mapper.WxCouponPasswordMapper; +import com.iformall.mapper.WxMallMapper; +import com.iformall.mapper.WxMerchantBUserMapper; +import com.iformall.mapper.WxMerchantMapper; +import com.iformall.mapper.WxOrderGroupMapper; +import com.iformall.mapper.WxOrderMapper; +import com.iformall.mapper.WxOrderPressMapper; +import com.iformall.mapper.WxPayAccountMapper; +import com.iformall.mapper.WxPayOrderMapper; import com.iformall.mq.MqBaseProducer; -import com.iformall.service.*; -import com.iformall.utils.*; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.math.BigDecimal; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; +import com.iformall.service.ExcelService; +import com.iformall.service.WxAppinfoService; +import com.iformall.service.WxCUserService; +import com.iformall.service.WxCUserTagsService; +import com.iformall.service.WxCouponActionLogService; +import com.iformall.service.WxCouponSendService; +import com.iformall.service.WxCreditHistoryService; +import com.iformall.service.WxMsgLimitService; +import com.iformall.service.WxOrderService; +import com.iformall.service.WxPayOrderService; +import com.iformall.service.WxProfitSharingOrderService; +import com.iformall.service.WxScoreRulesService; +import com.iformall.utils.Constant; +import com.iformall.utils.DateUtils; +import com.iformall.utils.PayUtils; +import com.iformall.utils.PressUtils; +import com.iformall.utils.RedisLock; +import com.iformall.utils.Utility; @Service public class WxOrderServiceImpl implements WxOrderService { @@ -479,94 +570,165 @@ public class WxOrderServiceImpl implements WxOrderService { } } - /** - * 减库存 - * - * @param user - * @param coupon - * @param couponIdStr - */ - private void stockReduce(WxCUser user, WxCoupon coupon, String couponIdStr) { - long time = System.currentTimeMillis() + RedisLock.TIMEOUT; - String timeStr = String.valueOf(time); - // 库存加锁 - if (!redisLock.lock(couponIdStr, timeStr)) { - logger.error("此券被锁定, couponId: " + couponIdStr); - throw new MallinkException(ErrorCode.TOO_MANY_REQUEST); - } - - // 检查 优惠券 库存 - if (coupon.getRemainInventory() <= 0) { - //解锁 - redisLock.unlock(couponIdStr, timeStr); - logger.error("此券库存为0, couponId: " + couponIdStr); - throw new MallinkException(ErrorCode.REMAIN_IS_EMPTY); - } - - int count = 0; - // 有价券 - if (coupon.getSalePrice() > 0) { - // 检查是否未支付订单 - try { - count = getUserOrderCount(user, coupon); - } catch (Exception e) { - //解锁 - redisLock.unlock(couponIdStr, timeStr); - throw new MallinkException(ErrorCode.DB_FAIL); - } - if (count > 0) { - //解锁 - redisLock.unlock(couponIdStr, timeStr); - logger.error("此券有未支付的订单, couponId: " + couponIdStr + ", count: " + count); - throw new MallinkException(ErrorCode.ORDER_UNPAID); - } - } - //检查拼团中的数量 - try { - count = getUserOrderGroupCount(user, coupon); - } catch (Exception e) { - //解锁 - redisLock.unlock(couponIdStr, timeStr); - throw new MallinkException(ErrorCode.DB_FAIL); - } - if (count >= coupon.getUseLimitQuantity()) { - //解锁 - redisLock.unlock(couponIdStr, timeStr); - logger.error("此券购买数量已超限, couponId: " + couponIdStr + ", count: " + count); - throw new MallinkException(ErrorCode.ORDER_IS_LIMITED); - } - - // 检查用户已购买数量 - try { - count = getUserCouponOrderCount(user, coupon); - } catch (Exception e) { - //解锁 - redisLock.unlock(couponIdStr, timeStr); - throw new MallinkException(ErrorCode.DB_FAIL); - } - if (count >= coupon.getUseLimitQuantity()) { - //解锁 - redisLock.unlock(couponIdStr, timeStr); - logger.error("此券购买数量已超限, couponId: " + couponIdStr + ", count: " + count); - throw new MallinkException(ErrorCode.ORDER_IS_LIMITED); - } - - try { - // 减库存 - int num = wxCouponMapper.reduceInventory(coupon.getId(), 1, coupon.getRemainInventory()); - if (num <= 0) { - logger.error("此券减库存失败, couponId: " + couponIdStr); - throw new MallinkException(ErrorCode.ORDER_IS_FAIL); - } - } catch (RuntimeException e) { - logger.error("此券减库存失败, couponId: " + couponIdStr); - throw new MallinkException(ErrorCode.ORDER_IS_FAIL); - } finally { - // 解锁 - redisLock.unlock(couponIdStr, timeStr); - } - } + * 减库存 + * + * @param user + * @param coupon + * @param couponIdStr + */ + private void stockReduce(WxCUser user, WxCoupon coupon, String couponIdStr) { + + long redisStock = redisLock.getCouponStock(Long.parseLong(couponIdStr)); + if (redisStock<=0) { + throw new MallinkException(ErrorCode.ORDER_IS_FAIL.getCode(),"券库存已为零!"); + } + // 检查 优惠券 库存 + if (coupon.getRemainInventory() <= 0) { + throw new MallinkException(ErrorCode.REMAIN_IS_EMPTY); + } + + int count = 0; + // 有价券 + if (coupon.getSalePrice() > 0) { + // 检查是否未支付订单 + try { + count = getUserOrderCount(user, coupon); + } catch (Exception e) { + throw new MallinkException(ErrorCode.DB_FAIL); + } + if (count > 0) { + logger.error("此券有未支付的订单, couponId: " + couponIdStr + ", count: " + count); + throw new MallinkException(ErrorCode.ORDER_UNPAID); + } + } + //检查拼团中的数量 + try { + count = getUserOrderGroupCount(user, coupon); + } catch (Exception e) { + throw new MallinkException(ErrorCode.DB_FAIL); + } + if (count >= coupon.getUseLimitQuantity()) { + logger.error("此券购买数量已超限, couponId: " + couponIdStr + ", count: " + count); + throw new MallinkException(ErrorCode.ORDER_IS_LIMITED); + } + + // 检查用户已购买数量 + try { + count = getUserCouponOrderCount(user, coupon); + } catch (Exception e) { + throw new MallinkException(ErrorCode.DB_FAIL); + } + if (count >= coupon.getUseLimitQuantity()) { + logger.error("此券购买数量已超限, couponId: " + couponIdStr + ", count: " + count); + throw new MallinkException(ErrorCode.ORDER_IS_LIMITED); + } + + try { + //减库存,从redis中取,然后发mq消息同步到数据库 + long stock = redisLock.decrease(EnumCacheKey.COUPON_STOCK.getMessage()+coupon.getId(), 1); + if (stock <= 0 ) { + throw new MallinkException(ErrorCode.ORDER_IS_FAIL.getCode(),"券库存已为零!"); + } + UpdateCouponStockMsg msg = new UpdateCouponStockMsg(); + msg.setCouponId(coupon.getId()); + msg.setNumber(1); + msg.setOperateType(UpdateCouponStockMsg.OPERATE_TYPE_DECREASE); + msg.setMsgType(EnumMsgRecordType.COUPON_STOCK.getCode()); + mqBaseProducer.sendMessage(msg, EnumMsgMqTopic.STOCK.getCode(), "*", "decrease_stock_"+coupon.getId()); + } catch (RuntimeException e) { + logger.error("此券减库存失败, couponId: " + couponIdStr); + throw new MallinkException(ErrorCode.ORDER_IS_FAIL); + } + } + +// /** +// * 减库存 +// * +// * @param user +// * @param coupon +// * @param couponIdStr +// */ +// private void stockReduce(WxCUser user, WxCoupon coupon, String couponIdStr) { +// long time = System.currentTimeMillis() + RedisLock.TIMEOUT; +// String timeStr = String.valueOf(time); +// // 库存加锁 +// if (!redisLock.lock(couponIdStr, timeStr)) { +// logger.error("此券被锁定, couponId: " + couponIdStr); +// throw new MallinkException(ErrorCode.TOO_MANY_REQUEST); +// } +// +// // 检查 优惠券 库存 +// if (coupon.getRemainInventory() <= 0) { +// //解锁 +// redisLock.unlock(couponIdStr, timeStr); +// logger.error("此券库存为0, couponId: " + couponIdStr); +// throw new MallinkException(ErrorCode.REMAIN_IS_EMPTY); +// } +// +// int count = 0; +// // 有价券 +// if (coupon.getSalePrice() > 0) { +// // 检查是否未支付订单 +// try { +// count = getUserOrderCount(user, coupon); +// } catch (Exception e) { +// //解锁 +// redisLock.unlock(couponIdStr, timeStr); +// throw new MallinkException(ErrorCode.DB_FAIL); +// } +// if (count > 0) { +// //解锁 +// redisLock.unlock(couponIdStr, timeStr); +// logger.error("此券有未支付的订单, couponId: " + couponIdStr + ", count: " + count); +// throw new MallinkException(ErrorCode.ORDER_UNPAID); +// } +// } +// //检查拼团中的数量 +// try { +// count = getUserOrderGroupCount(user, coupon); +// } catch (Exception e) { +// //解锁 +// redisLock.unlock(couponIdStr, timeStr); +// throw new MallinkException(ErrorCode.DB_FAIL); +// } +// if (count >= coupon.getUseLimitQuantity()) { +// //解锁 +// redisLock.unlock(couponIdStr, timeStr); +// logger.error("此券购买数量已超限, couponId: " + couponIdStr + ", count: " + count); +// throw new MallinkException(ErrorCode.ORDER_IS_LIMITED); +// } +// +// // 检查用户已购买数量 +// try { +// count = getUserCouponOrderCount(user, coupon); +// } catch (Exception e) { +// //解锁 +// redisLock.unlock(couponIdStr, timeStr); +// throw new MallinkException(ErrorCode.DB_FAIL); +// } +// if (count >= coupon.getUseLimitQuantity()) { +// //解锁 +// redisLock.unlock(couponIdStr, timeStr); +// logger.error("此券购买数量已超限, couponId: " + couponIdStr + ", count: " + count); +// throw new MallinkException(ErrorCode.ORDER_IS_LIMITED); +// } +// +// try { +// // 减库存 +// int num = wxCouponMapper.reduceInventory(coupon.getId(), 1); +// if (num <= 0) { +// logger.error("此券减库存失败, couponId: " + couponIdStr); +// throw new MallinkException(ErrorCode.ORDER_IS_FAIL); +// } +// } catch (RuntimeException e) { +// logger.error("此券减库存失败, couponId: " + couponIdStr); +// throw new MallinkException(ErrorCode.ORDER_IS_FAIL); +// } finally { +// // 解锁 +// redisLock.unlock(couponIdStr, timeStr); +// } +// } @Override public void stockBack(WxOrder updateOrder) { @@ -575,7 +737,7 @@ public class WxOrderServiceImpl implements WxOrderService { Long couponId = updateOrder.getProductId(); String couponIdStr = "" + couponId; //加锁 - long time = System.currentTimeMillis() + RedisLock.TIMEOUT; + long time = System.currentTimeMillis() + 300*RedisLock.TIMEOUT; String timeStr = String.valueOf(time); if (!redisLock.lock(couponIdStr, timeStr)) { @@ -602,6 +764,7 @@ public class WxOrderServiceImpl implements WxOrderService { logger.error("此券加库存失败, couponId: " + couponIdStr); throw new MallinkException(ErrorCode.ORDER_IS_FAIL); } + redisLock.increase(EnumCacheKey.COUPON_STOCK.getMessage()+coupon.getId(), 1); } catch (Exception e) { logger.error("数据库更新失败,库存+1失败, e:" + e.getMessage()); throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "库存恢复失败"); @@ -1717,6 +1880,7 @@ public class WxOrderServiceImpl implements WxOrderService { throw new MallinkException(ErrorCode.SYS_REPEAT_SUBMIT_EXCEPTION); } cUserTokenRedisTemplate.opsForValue().set(key, user, 1000, TimeUnit.MILLISECONDS); + order = saveFreeOrderForCoupon(user, coupon, orderSaveDto.getCouponChannelId(), orderSaveDto.getFormId(), null); if (order != null) { // 6. 下订单完成,发送内部消息 diff --git a/mallinkService/src/main/java/com/iformall/service/msg/impl/UpdateCouponStockMsgServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/msg/impl/UpdateCouponStockMsgServiceImpl.java new file mode 100644 index 000000000..fe46cf65c --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/msg/impl/UpdateCouponStockMsgServiceImpl.java @@ -0,0 +1,35 @@ +package com.iformall.service.msg.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.iformall.domain.po.msg.BaseMsg; +import com.iformall.domain.po.msg.UpdateCouponStockMsg; +import com.iformall.enums.EnumPayWay; +import com.iformall.service.WxCouponService; +import com.iformall.service.msg.MsgSendService; + +/** + * + * @author Stormeye Wu + * @date 2019/5/10 + */ +@Service +public class UpdateCouponStockMsgServiceImpl implements MsgSendService { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private WxCouponService wxCouponService; + + @Override + public void send(BaseMsg baseMsg) throws Exception { + UpdateCouponStockMsg msg = (UpdateCouponStockMsg)baseMsg; + if (null != msg ) { + if (msg.getOperateType().equals(UpdateCouponStockMsg.OPERATE_TYPE_DECREASE)) { + wxCouponService.reduceRemainInventory(msg.getCouponId(), (int)msg.getNumber()); + } + } + } +} diff --git a/mallinkService/src/main/java/com/iformall/utils/RedisLock.java b/mallinkService/src/main/java/com/iformall/utils/RedisLock.java index 47b18bc17..07a05aff5 100644 --- a/mallinkService/src/main/java/com/iformall/utils/RedisLock.java +++ b/mallinkService/src/main/java/com/iformall/utils/RedisLock.java @@ -8,6 +8,8 @@ import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; +import com.iformall.enums.EnumCacheKey; + import java.util.concurrent.TimeUnit; /** @@ -24,7 +26,7 @@ public class RedisLock { private StringRedisTemplate stringRedisTemplate; public static final int TIMEOUT = 10*1000;//超时时间 10s - + /** * 加锁 * @param key productId - 商品的唯一标志 @@ -102,5 +104,49 @@ public class RedisLock { logger.error("[Redis分布式锁] 解锁出现异常了,{}",e); } } - + + + /** + * 原子性增加 + */ + public long increase(String key, long delta) { + try { + return stringRedisTemplate.opsForValue().increment(key, delta); + }catch(Exception e) { + logger.error("[Redis分布式锁] increase error,{}",e); + } + return 0; + } + + /** + * 原子性减少 + */ + public long decrease(String key, long delta) { + try { + stringRedisTemplate.opsForValue().decrement(key, delta); + }catch(Exception e) { + logger.error("[Redis分布式锁] decrease error,{}",e); + } + return 0; + } + + + public long getCouponStock(long couponId) { + try { + String longstr = stringRedisTemplate.opsForValue().get(EnumCacheKey.COUPON_STOCK.getMessage()+String.valueOf(couponId)); + return Long.parseLong(longstr); + }catch (Exception e) { + logger.error("[Redis分布式锁] getCouponStock error,{}",e); + } + return 0; + } + + public void setCouponStock(long couponId,long number) { + try { + stringRedisTemplate.opsForValue().set(EnumCacheKey.COUPON_STOCK.getMessage()+String.valueOf(couponId), String.valueOf(number)); + }catch(Exception e) { + logger.error("[Redis分布式锁] setCouponStock error,{}",e); + } + + } }