|
|
@@ -34,10 +34,10 @@ import com.cyksj.dto.RedisKey;
|
|
|
import com.cyksj.dto.Result;
|
|
|
import com.cyksj.enums.GatewayResponse;
|
|
|
import com.cyksj.mapper.*;
|
|
|
-import com.cyksj.model.dto.AliPayParams;
|
|
|
-import com.cyksj.model.dto.H5JsPayParams;
|
|
|
-import com.cyksj.model.dto.WxMpTemplateData;
|
|
|
-import com.cyksj.model.dto.WxMpTemplateMessage;
|
|
|
+import com.cyksj.mapper.manage.coupon.CouponMapper;
|
|
|
+import com.cyksj.mapper.manage.coupon.CouponSkuMapper;
|
|
|
+import com.cyksj.mapper.manage.coupon.CouponUserMapper;
|
|
|
+import com.cyksj.model.dto.*;
|
|
|
import com.cyksj.model.entity.*;
|
|
|
import com.cyksj.model.manage.views.OrderDonView;
|
|
|
import com.cyksj.model.request.OrderAttach;
|
|
|
@@ -45,24 +45,27 @@ import com.cyksj.model.request.OrderPayRequest;
|
|
|
import com.cyksj.model.request.WxOrderRefundReq;
|
|
|
import com.cyksj.model.request.ZfbOrderRefundReq;
|
|
|
import com.cyksj.model.response.AliPayRefundRep;
|
|
|
+import com.cyksj.model.views.CouponNewUserView;
|
|
|
+import com.cyksj.model.views.CouponUserView;
|
|
|
import com.cyksj.redis.RedisService;
|
|
|
+import com.cyksj.service.coupon.CouponFontService;
|
|
|
import com.cyksj.service.order.OrderDonService;
|
|
|
import com.cyksj.service.wechat.WeChatService;
|
|
|
import com.cyksj.task.JobManager;
|
|
|
import com.ejlchina.searcher.BeanSearcher;
|
|
|
+import com.ejlchina.searcher.param.Operator;
|
|
|
import com.ejlchina.searcher.util.MapUtils;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.dao.DuplicateKeyException;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Optional;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_ALREADY_BE_USER;
|
|
|
import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_NOT_FIND;
|
|
|
@@ -120,10 +123,23 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
|
|
|
|
|
|
private final RefundOrderDonMapper refundOrderDonMapper;
|
|
|
|
|
|
+ private final CouponMapper couponMapper;
|
|
|
+
|
|
|
+ private final CouponFontService couponFontService;
|
|
|
+
|
|
|
+ private final CouponUserMapper couponUserMapper;
|
|
|
+
|
|
|
+ private final CouponSkuMapper couponSkuMapper;
|
|
|
|
|
|
@Transactional(rollbackFor = Throwable.class)
|
|
|
@Override
|
|
|
- public OrderDon submit(OrderPayRequest payRequest) {
|
|
|
+ public OrderDon submit(OrderPayRequest payRequest) throws Exception {
|
|
|
+ CouponUser couponUser = null;
|
|
|
+ if (StrUtil.isNotBlank(payRequest.getCouponExCode()) || payRequest.getCouponId() != null) {
|
|
|
+ checkCouponStatus(payRequest.getSkuId(), payRequest.getCouponExCode(), payRequest.getCouponId(), payRequest.getUserId(), false);
|
|
|
+ //记录优惠券使用状态
|
|
|
+ couponUser = couponStatusRecord(payRequest.getCouponExCode(), payRequest.getCouponId(), payRequest.getUserId());
|
|
|
+ }
|
|
|
User user = userMapper.selectById(payRequest.getUserId());
|
|
|
GoodsDonSku sku = goodsDonSkuMapper.selectById(payRequest.getSkuId());
|
|
|
GoodsDon goodsDon = goodsDonMapper.selectById(sku.getGoodsId());
|
|
|
@@ -202,7 +218,28 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
|
|
|
OrderDon orderDon = new OrderDon();
|
|
|
orderDon.setOrderNo(donNo);
|
|
|
orderDon.setOpenId(payOpenId);
|
|
|
+ if (sku.getPrice() != null && payRequest.getDonMoney().compareTo(sku.getPrice()) < 0) {
|
|
|
+ throw BusinessRuntimeException.getInstance("车位所付金额错误");
|
|
|
+ }
|
|
|
orderDon.setMoney(payRequest.getDonMoney());
|
|
|
+ orderDon.setRealMoney(payRequest.getDonMoney());
|
|
|
+ //存在优惠券
|
|
|
+ if (couponUser != null) {
|
|
|
+ Long couponId = couponUser.getCouponId();
|
|
|
+ Coupon coupon = couponMapper.getCouponById(couponId);
|
|
|
+ BigDecimal couponMoney = null;
|
|
|
+ if (coupon.getType() == Coupon.Type.discount) {
|
|
|
+ BigDecimal discountMoney = payRequest.getDonMoney().multiply(coupon.getDiscount());
|
|
|
+ orderDon.setMoney(discountMoney);
|
|
|
+ couponMoney = payRequest.getDonMoney().subtract(discountMoney);
|
|
|
+ } else if (coupon.getType() == Coupon.Type.reduce) {
|
|
|
+ BigDecimal subtractMoney = payRequest.getDonMoney().subtract(coupon.getReduceMoney());
|
|
|
+ orderDon.setMoney(subtractMoney);
|
|
|
+ couponMoney = payRequest.getDonMoney().subtract(subtractMoney);
|
|
|
+ }
|
|
|
+ orderDon.setCouponMoney(couponMoney);
|
|
|
+ orderDon.setCouponUserId(couponUser.getId());
|
|
|
+ }
|
|
|
orderDon.setSkuId(payRequest.getSkuId());
|
|
|
orderDon.setRelationId(relationId);
|
|
|
orderDon.setNum(payRequest.getNum());
|
|
|
@@ -210,9 +247,14 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
|
|
|
orderDon.setStatus(OrderDon.Status.noPayment);
|
|
|
orderDon.setUserId(user.getId());
|
|
|
orderDon.setType(OrderDon.Type.getType(payRequest.getType()));
|
|
|
+ if (relationId != 0) {
|
|
|
+ Long gtSkuId = groupsRelationMapper.getGroupTripsSkuIdByRelationId(relationId);
|
|
|
+ if (!gtSkuId.equals(orderDon.getSkuId())) {
|
|
|
+ throw BusinessRuntimeException.getInstance("车位与车队规格不一致");
|
|
|
+ }
|
|
|
+ }
|
|
|
this.saveOrUpdate(orderDon);
|
|
|
|
|
|
-
|
|
|
if (goodsDon.getType() == 2) {
|
|
|
saveTransport(payRequest.getAddressId(), orderDon.getId());
|
|
|
}
|
|
|
@@ -392,6 +434,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ //返还优惠券
|
|
|
+ if (orderDon.getCouponUserId() != 0) {
|
|
|
+ updateOrderDonCouponStatus(orderDon);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -422,9 +468,15 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public OrderDon renewal(OrderPayRequest payRequest) {
|
|
|
+ @Transactional(rollbackFor = Throwable.class)
|
|
|
+ public OrderDon renewal(OrderPayRequest payRequest) throws Exception {
|
|
|
User user = userMapper.selectById(payRequest.getUserId());
|
|
|
-
|
|
|
+ CouponUser couponUser = null;
|
|
|
+ if (StrUtil.isNotBlank(payRequest.getCouponExCode()) || payRequest.getCouponId() != null) {
|
|
|
+ checkCouponStatus(payRequest.getSkuId(), payRequest.getCouponExCode(), payRequest.getCouponId(), payRequest.getUserId(), true);
|
|
|
+ //记录优惠券使用状态
|
|
|
+ couponUser = couponStatusRecord(payRequest.getCouponExCode(), payRequest.getCouponId(), payRequest.getUserId());
|
|
|
+ }
|
|
|
Long relationId = payRequest.getRelationId();
|
|
|
if (relationId == null || relationId <= 0 || payRequest.getSkuId() == null || payRequest.getNum() == null) {
|
|
|
throw new BusinessRuntimeException("缺少必填参数");
|
|
|
@@ -469,6 +521,25 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
|
|
|
orderDon.setStatus(OrderDon.Status.noPayment);
|
|
|
orderDon.setUserId(user.getId());
|
|
|
orderDon.setGoodsId(goodsDon.getId());
|
|
|
+ orderDon.setRealMoney(orderDon.getMoney());
|
|
|
+ //存在优惠券
|
|
|
+ if (couponUser != null) {
|
|
|
+ Long couponId = couponUser.getCouponId();
|
|
|
+ Coupon coupon = couponMapper.getCouponById(couponId);
|
|
|
+ BigDecimal couponMoney = null;
|
|
|
+ if (coupon.getType() == Coupon.Type.discount) {
|
|
|
+ BigDecimal discountMoney = orderDon.getMoney().multiply(coupon.getDiscount());
|
|
|
+ orderDon.setMoney(discountMoney);
|
|
|
+ couponMoney = orderDon.getMoney().subtract(discountMoney);
|
|
|
+ } else if (coupon.getType() == Coupon.Type.reduce) {
|
|
|
+ BigDecimal subtractMoney = orderDon.getMoney().subtract(coupon.getReduceMoney());
|
|
|
+ orderDon.setMoney(subtractMoney);
|
|
|
+ couponMoney = orderDon.getMoney().subtract(subtractMoney);
|
|
|
+ }
|
|
|
+ orderDon.setCouponMoney(couponMoney);
|
|
|
+ orderDon.setCouponUserId(couponUser.getId());
|
|
|
+ }
|
|
|
+
|
|
|
this.saveOrUpdate(orderDon);
|
|
|
|
|
|
jobManager.addJob(EXPIRY_TIME, () -> {
|
|
|
@@ -586,6 +657,11 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
|
|
|
});
|
|
|
//虚物订单退款,清出车队,车票变为已过期
|
|
|
clearUnrealGoodsDetail(orderDon, goodsDon);
|
|
|
+ //若存在优惠券使用,退还优惠券
|
|
|
+ if (orderDon.getCouponUserId() != 0) {
|
|
|
+ redisService.set(String.format("%s-%s", orderDon.getId(), orderDon.getCouponUserId()), orderDon.getId(), 120l);
|
|
|
+ updateOrderDonCouponStatus(orderDon);
|
|
|
+ }
|
|
|
return GatewayResponse.SUCCESS.newBuilder().toResult("退款成功");
|
|
|
}
|
|
|
|
|
|
@@ -650,6 +726,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
|
|
|
});
|
|
|
//虚物订单退款,清出车队,车票变为已过期
|
|
|
clearUnrealGoodsDetail(orderDon, goodsDon);
|
|
|
+ if (orderDon.getCouponUserId() != 0) {
|
|
|
+ //zfb订单退款,返还优惠券
|
|
|
+ updateOrderDonCouponStatus(orderDon);
|
|
|
+ }
|
|
|
return GatewayResponse.SUCCESS.newBuilder().toResult("退款成功");
|
|
|
}
|
|
|
throw BusinessRuntimeException.getInstance("退款失败,e:{0}", response.getBody());
|
|
|
@@ -765,6 +845,12 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
|
|
|
orderDon.setRefundMoney(refundMoney);
|
|
|
orderDonMapper.updateById(orderDon);
|
|
|
}
|
|
|
+ if (orderDon.getCouponUserId() != 0) {
|
|
|
+ Object obj = redisService.get(String.format("%s-%s", orderDon.getId(), orderDon.getCouponUserId()));
|
|
|
+ if (obj == null) {
|
|
|
+ updateOrderDonCouponStatus(orderDon);
|
|
|
+ }
|
|
|
+ }
|
|
|
log.info("微信退款: 退款单号[{}] 退款成功.", outRefundNo);
|
|
|
}
|
|
|
|
|
|
@@ -936,4 +1022,140 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+ public void checkCouponStatus(Long skuId, String couponExCode, Long couponId, Long userId, Boolean isRenew) throws Exception {
|
|
|
+ log.info("开始校验兑换码:{},优惠券id:{}状态", couponExCode, couponId);
|
|
|
+ //实物还是虚物商品
|
|
|
+ GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectById(skuId);
|
|
|
+ GoodsDon goodsDon = goodsDonMapper.selectById(goodsDonSku.getGoodsId());
|
|
|
+ if (StrUtil.isNotBlank(couponExCode) && couponId != null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("优惠券与优惠码不可同时使用..");
|
|
|
+ }
|
|
|
+ if (StrUtil.isNotBlank(couponExCode)) {
|
|
|
+ CouponPopularizeDto exists = couponMapper.checkExCode(couponExCode);
|
|
|
+ if (exists == null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该优惠码不存在");
|
|
|
+ }
|
|
|
+ checkCouponGoods(goodsDon, skuId, exists.getType(), exists.getGoodsSkuIds(), true);
|
|
|
+ //检验是否续费可使用
|
|
|
+ if (isRenew && !exists.getIsRenew()) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该优惠券续费时不可使用");
|
|
|
+ }
|
|
|
+ if (exists.getScope() == Coupon.Scope.newUser) {
|
|
|
+ CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
|
|
|
+ if (couponNewUserView != null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该新用户优惠码有且仅可使用一次");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (exists.getIsValidTime() && exists.getValidEndTime().before(DateTime.now())) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该优惠码已失效");
|
|
|
+ }
|
|
|
+ if (exists.getIsValidTime() && exists.getValidStartTime().after(DateTime.now())) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该优惠码待生效");
|
|
|
+ }
|
|
|
+ } else if (couponId != null) {
|
|
|
+ CouponUserView couponUserView = beanSearcher.searchFirst(CouponUserView.class, MapUtils.builder()
|
|
|
+ .field(CouponUserView::getCouponId, couponId).op(Operator.Equal)
|
|
|
+ .field(CouponUserView::getUserId, userId).op(Operator.Equal)
|
|
|
+ .build());
|
|
|
+ if (couponUserView == null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该优惠券不存在");
|
|
|
+ }
|
|
|
+ if (couponUserView.getCouponUserStatus() == CouponUser.Status.used) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该优惠券已使用");
|
|
|
+ }
|
|
|
+ couponFontService.setCouponUserStatus(couponUserView, DateTime.now());
|
|
|
+ if (couponUserView.getCouponUserStatus() != CouponUser.Status.unused) {
|
|
|
+ throw BusinessRuntimeException.getInstance(couponUserView.getReason());
|
|
|
+ }
|
|
|
+ checkCouponGoods(goodsDon, skuId, couponUserView.getType(), couponUserView.getGoodsSkuIds(), false);
|
|
|
+ //检验是否续费可使用
|
|
|
+ if (isRenew && !couponUserView.getIsRenew()) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该优惠券续费时不可使用");
|
|
|
+ }
|
|
|
+ if (couponUserView.getScope() == Coupon.Scope.newUser) {
|
|
|
+ CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
|
|
|
+ if (couponNewUserView != null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该新用户优惠券有且仅可使用一次");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private CouponUser couponStatusRecord(String couponExCode, Long couponId, Long userId) {
|
|
|
+ log.info("兑换码:{},优惠券id:{},更新其优惠券状态", couponExCode, couponId);
|
|
|
+ CouponUser couponUser = null;
|
|
|
+ if (StrUtil.isNotBlank(couponExCode)) {
|
|
|
+ CouponPopularizeDto exists = couponMapper.checkExCode(couponExCode);
|
|
|
+ if (exists == null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该优惠码不存在");
|
|
|
+ }
|
|
|
+ couponUser = new CouponUser();
|
|
|
+ couponUser.setCouponId(exists.getCouponId());
|
|
|
+ if (exists.getPopularizeId() != null) {
|
|
|
+ couponUser.setCouponId(exists.getPopularizeCouponId());
|
|
|
+ couponUser.setPopularizeId(exists.getPopularizeId());
|
|
|
+ }
|
|
|
+ CouponUser received = couponUserMapper.selectOne(Wrappers.lambdaQuery(CouponUser.class).eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, couponUser.getCouponId()).last("limit 1"));
|
|
|
+ if (received != null && received.getStatus() != CouponUser.Status.unused) {
|
|
|
+ throw BusinessRuntimeException.getInstance("您已使用该优惠码所对应的优惠券");
|
|
|
+ }
|
|
|
+ couponUser.setUserId(userId);
|
|
|
+ couponUser.setStatus(CouponUser.Status.used);
|
|
|
+ couponUser.setChannel(CouponUser.Channel.exCode);
|
|
|
+ couponFontService.updateCouponUserValidTime(couponUser.getCouponId(), couponUser);
|
|
|
+ try {
|
|
|
+ couponUserMapper.insert(couponUser);
|
|
|
+ } catch (DuplicateKeyException e) {
|
|
|
+ log.info("用户已领取该{}优惠券", couponUser.getCouponId());
|
|
|
+ throw BusinessRuntimeException.getInstance("您已领取该优惠码对应的优惠券,请使用优惠券");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ couponUser = couponUserMapper.selectOne(Wrappers.lambdaQuery(CouponUser.class).eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, couponId).last("limit 1"));
|
|
|
+ if (couponUser == null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该优惠券不存在");
|
|
|
+ }
|
|
|
+ couponUser.setStatus(CouponUser.Status.used);
|
|
|
+ couponUserMapper.updateById(couponUser);
|
|
|
+ }
|
|
|
+ return couponUser;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 退款时,归还优惠券
|
|
|
+ */
|
|
|
+ private void updateOrderDonCouponStatus(OrderDon orderDon) {
|
|
|
+ log.info("订单:{}退款,优惠券返还start...", orderDon.getId());
|
|
|
+ CouponUser couponUser = couponUserMapper.selectById(orderDon.getCouponUserId());
|
|
|
+ if (CouponUser.Channel.exCode == couponUser.getChannel()) {
|
|
|
+ //兑换码兑换的优惠券退款时,直接删除
|
|
|
+ couponUserMapper.deleteById(couponUser.getId());
|
|
|
+ }else {
|
|
|
+ CouponUserView couponUserView = beanSearcher.searchFirst(CouponUserView.class, MapUtils.builder()
|
|
|
+ .field(CouponUserView::getCouponId, couponUser.getCouponId()).op(Operator.Equal)
|
|
|
+ .field(CouponUserView::getUserId, orderDon.getUserId()).op(Operator.Equal)
|
|
|
+ .build());
|
|
|
+ couponUserView.setCouponUserStatus(CouponUser.Status.unused);
|
|
|
+ couponFontService.setCouponUserStatus(couponUserView, DateTime.now());
|
|
|
+ couponUser.setStatus(couponUserView.getCouponUserStatus());
|
|
|
+ couponUserMapper.updateById(couponUser);
|
|
|
+ }
|
|
|
+ log.info("订单:{}退款,优惠券返还end...", orderDon.getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void checkCouponGoods(GoodsDon goodsDon, Long skuId, Coupon.Type type, String goodsSkuIds, Boolean isCouponCode) throws Exception {
|
|
|
+ if (goodsDon.getType() == 1) {
|
|
|
+ List<Coupon.CouponGoodsSku> skuIds = Jsons.parseList(goodsSkuIds, Coupon.CouponGoodsSku.class);
|
|
|
+ Set<Long> collect = skuIds.stream().map(Coupon.CouponGoodsSku::getSkuId).collect(Collectors.toSet());
|
|
|
+ if (!collect.contains(skuId)) {
|
|
|
+ throw BusinessRuntimeException.getInstance(String.format("该%s不适用于该规格", isCouponCode ? "优惠码" : "优惠券"));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ Long gid = goodsDon.getId();
|
|
|
+ CouponSku couponSku = couponSkuMapper.selectOne(Wrappers.lambdaQuery(CouponSku.class).eq(CouponSku::getGoodsId, gid).eq(CouponSku::getDeleted, true).select(CouponSku::getId).last("limit 1"));
|
|
|
+ if (couponSku == null) {
|
|
|
+ throw BusinessRuntimeException.getInstance(String.format("该%s不可用于实物商品", isCouponCode ? "优惠码" : "优惠券"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|