|
@@ -113,6 +113,7 @@ import com.fs.hisStore.constants.StoreConstants;
|
|
|
import com.fs.hisStore.domain.*;
|
|
import com.fs.hisStore.domain.*;
|
|
|
import com.fs.hisStore.enums.*;
|
|
import com.fs.hisStore.enums.*;
|
|
|
import com.fs.hisStore.service.*;
|
|
import com.fs.hisStore.service.*;
|
|
|
|
|
+import com.fs.store.domain.FsStoreDelivers;
|
|
|
import com.fs.system.domain.SysConfig;
|
|
import com.fs.system.domain.SysConfig;
|
|
|
import com.fs.system.service.ISysConfigService;
|
|
import com.fs.system.service.ISysConfigService;
|
|
|
import com.fs.system.service.ISysDictTypeService;
|
|
import com.fs.system.service.ISysDictTypeService;
|
|
@@ -180,6 +181,7 @@ import java.time.ZonedDateTime;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.time.format.DateTimeParseException;
|
|
import java.time.format.DateTimeParseException;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
@@ -219,6 +221,8 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private FsStoreCartScrmMapper cartMapper;
|
|
private FsStoreCartScrmMapper cartMapper;
|
|
|
|
|
|
|
|
|
|
+// @Autowired
|
|
|
|
|
+// private FsStoreDeliversMapper fsStoreDeliversMapper;
|
|
|
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private FsUserCompanyUserMapper fsUserCompanyUserMapper;
|
|
private FsUserCompanyUserMapper fsUserCompanyUserMapper;
|
|
@@ -244,6 +248,12 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private RedissonClient redissonClient;
|
|
private RedissonClient redissonClient;
|
|
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private com.fs.common.core.redis.service.ActivityStockService activityStockService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private IFsStoreProductActivityService activityService;
|
|
|
|
|
+
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private IFsStoreCartScrmService cartService;
|
|
private IFsStoreCartScrmService cartService;
|
|
|
|
|
|
|
@@ -446,6 +456,15 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private FsUserCompanyPackageScrmMapper fsUserCompanyPackageScrmMapper;
|
|
private FsUserCompanyPackageScrmMapper fsUserCompanyPackageScrmMapper;
|
|
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FsStoreProductDiscountMapper fsStoreProductDiscountMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FsStoreProductFlashSaleMapper fsStoreProductFlashSaleMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FsStoreProductActivityMapper activityMapper;
|
|
|
|
|
+
|
|
|
@Value("${cloud_host.company_name}")
|
|
@Value("${cloud_host.company_name}")
|
|
|
private String companyName;
|
|
private String companyName;
|
|
|
@PostConstruct
|
|
@PostConstruct
|
|
@@ -781,6 +800,24 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
cartMapper.updateFsStoreCart(fsStoreCart);
|
|
cartMapper.updateFsStoreCart(fsStoreCart);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ if(cartParam.getProductType() != null && (cartParam.getProductType() == 6 || cartParam.getProductType() == 7) ){//更新金额
|
|
|
|
|
+ for (FsStoreCartQueryVO c : carts){
|
|
|
|
|
+ //获取对应商品金额
|
|
|
|
|
+ FsStoreProductActivity activity = activityMapper.selectActivityByProductIdAndSpecId(c.getProductId(), c.getProductAttrValueId());
|
|
|
|
|
+ if(activity == null){
|
|
|
|
|
+ return R.error("操作失败,对应活动未找到或已过期!");
|
|
|
|
|
+ }
|
|
|
|
|
+ //更新购物车信息
|
|
|
|
|
+ FsStoreCartScrm cartScrm = new FsStoreCartScrm();
|
|
|
|
|
+ cartScrm.setId(c.getId());
|
|
|
|
|
+ BigDecimal price = cartParam.getProductType() == 7?activity.getDiscountPrice():activity.getFlashPrice();
|
|
|
|
|
+ cartScrm.setChangePrice(price);
|
|
|
|
|
+ c.setPrice(price);
|
|
|
|
|
+ c.setChangePrice(price);
|
|
|
|
|
+ cartMapper.updateFsStoreCart(cartScrm);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
String uuid = IdUtil.randomUUID();
|
|
String uuid = IdUtil.randomUUID();
|
|
|
redisCache.setCacheObject("orderKey:" + uuid, cartParam.getCartIds(), 300, TimeUnit.SECONDS);
|
|
redisCache.setCacheObject("orderKey:" + uuid, cartParam.getCartIds(), 300, TimeUnit.SECONDS);
|
|
|
redisCache.setCacheObject("orderCarts:" + uuid, carts, 300, TimeUnit.SECONDS);
|
|
redisCache.setCacheObject("orderCarts:" + uuid, carts, 300, TimeUnit.SECONDS);
|
|
@@ -933,6 +970,22 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
if (cartIds != null) {
|
|
if (cartIds != null) {
|
|
|
//获取购物车列表
|
|
//获取购物车列表
|
|
|
List<FsStoreCartQueryVO> carts = redisCache.getCacheObject("orderCarts:" + param.getOrderKey());
|
|
List<FsStoreCartQueryVO> carts = redisCache.getCacheObject("orderCarts:" + param.getOrderKey());
|
|
|
|
|
+
|
|
|
|
|
+ // 校验:购物车商品是否在活动期间,活动期间不允许走普通下单
|
|
|
|
|
+ if (carts != null) {
|
|
|
|
|
+ long now = System.currentTimeMillis();
|
|
|
|
|
+ for (FsStoreCartQueryVO cart : carts) {
|
|
|
|
|
+ FsStoreProductScrm product = productService.selectFsStoreRedisProductById(cart.getProductId());
|
|
|
|
|
+ if (product != null && product.getActivityType() != null && product.getActivityType() != 0
|
|
|
|
|
+ && product.getActivityStartTime() != null && product.getActivityEndTime() != null) {
|
|
|
|
|
+ if (now >= product.getActivityStartTime().getTime() && now <= product.getActivityEndTime().getTime()) {
|
|
|
|
|
+ String typeName = product.getActivityType() == 6 ? "秒杀" : "限时折扣";
|
|
|
|
|
+ return R.error("商品【" + product.getProductName() + "】正在" + typeName + "活动中,请从活动专区购买");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
//获取地址
|
|
//获取地址
|
|
|
FsUserAddressScrm address = userAddressMapper.selectFsUserAddressById(param.getAddressId());
|
|
FsUserAddressScrm address = userAddressMapper.selectFsUserAddressById(param.getAddressId());
|
|
|
//生成分布式唯一值
|
|
//生成分布式唯一值
|
|
@@ -1236,6 +1289,422 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 创建秒杀/限时折扣活动订单(独立接口,流程与createOrder一致)
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional
|
|
|
|
|
+ public R createActivityOrder(long userId, FsStoreOrderCreateParam param) {
|
|
|
|
|
+ Long associatedId = null;
|
|
|
|
|
+ Integer orderType = param.getOrderType();
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 活动参数校验
|
|
|
|
|
+ if (orderType == null || (orderType != 6 && orderType != 7)) {
|
|
|
|
|
+ return R.error("无效的活动类型");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (param.getAssociatedId() == null || param.getAssociatedId() <= 0) {
|
|
|
|
|
+ return R.error("活动ID不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 校验活动时间和状态
|
|
|
|
|
+ com.fs.common.core.redis.service.ActivityValidateResult validateResult =
|
|
|
|
|
+ activityStockService.validateActivityWithDetail(orderType, param.getAssociatedId());
|
|
|
|
|
+ if (!validateResult.isValid()) {
|
|
|
|
|
+ return R.error(validateResult.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 确保Redis活动信息和规格库存已初始化(活动无独立库存,用规格库存)
|
|
|
|
|
+ FsStoreProductActivity activityInfo = activityService.selectFsStoreProductActivityById(param.getAssociatedId());
|
|
|
|
|
+ if (activityInfo == null) {
|
|
|
|
|
+ return R.error("活动信息不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ activityStockService.initActivityInfo(
|
|
|
|
|
+ param.getAssociatedId(), 1,
|
|
|
|
|
+ activityInfo.getStartTime().getTime(), activityInfo.getEndTime().getTime(),
|
|
|
|
|
+ activityInfo.getProductId(), activityInfo.getSpecId(), null
|
|
|
|
|
+ );
|
|
|
|
|
+ if (activityInfo.getSpecId() != null && activityInfo.getSpecStock() != null) {
|
|
|
|
|
+ activityStockService.initProductSpecStock(activityInfo.getSpecId(), activityInfo.getSpecStock());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3.5 提前获取购物车,计算活动商品总件数,确保Lua扣减数量与DB扣减数量一致
|
|
|
|
|
+ String preCartIds = redisCache.getCacheObject("orderKey:" + param.getOrderKey());
|
|
|
|
|
+ List<FsStoreCartQueryVO> preCarts = null;
|
|
|
|
|
+ int activityDeductNum = 1; // 默认扣减1件
|
|
|
|
|
+ if (preCartIds != null) {
|
|
|
|
|
+ preCarts = redisCache.getCacheObject("orderCarts:" + param.getOrderKey());
|
|
|
|
|
+ if (preCarts != null) {
|
|
|
|
|
+ activityDeductNum = 0;
|
|
|
|
|
+ for (FsStoreCartQueryVO cart : preCarts) {
|
|
|
|
|
+ if (cart.getCartNum() != null) {
|
|
|
|
|
+ activityDeductNum += cart.getCartNum();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (activityDeductNum <= 0) {
|
|
|
|
|
+ activityDeductNum = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 4. Lua原子扣减活动库存(已移除 getStock() 预检查——先查再扣存在竞态窗口,Lua脚本本身会原子判断库存是否充足)
|
|
|
|
|
+ boolean deductSuccess = activityStockService.deductStock(orderType, param.getAssociatedId(), activityDeductNum);
|
|
|
|
|
+ if (!deductSuccess) {
|
|
|
|
|
+ return R.error("活动商品已售罄,请稍后重试");
|
|
|
|
|
+ }
|
|
|
|
|
+ associatedId = param.getAssociatedId();
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ FsUserCompanyUser fsUserCompanyUser = fsUserCompanyUserMapper.selectFsUserCompanyUserByUserId(userId);
|
|
|
|
|
+ if (ObjectUtil.isNotEmpty(fsUserCompanyUser) && param.getVideoId()!=null && param.getCompanyId() == null){
|
|
|
|
|
+ param.setCompanyId(fsUserCompanyUser.getCompanyId());
|
|
|
|
|
+ param.setCompanyUserId(fsUserCompanyUser.getCompanyUserId());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!CloudHostUtils.hasCloudHostName("鹤颜堂")){
|
|
|
|
|
+ if (ObjectUtil.isEmpty(param.getAddressId())){
|
|
|
|
|
+ return R.error("地址不能为空!");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ FsStoreOrderComputedParam computedParam = new FsStoreOrderComputedParam();
|
|
|
|
|
+ BeanUtils.copyProperties(param, computedParam);
|
|
|
|
|
+ //计算金额
|
|
|
|
|
+ FsStoreOrderComputeDTO dto;
|
|
|
|
|
+ try {
|
|
|
|
|
+ dto = this.computedOrder(userId, computedParam);
|
|
|
|
|
+ } catch (ServiceException e) {
|
|
|
|
|
+ if ("偏远地区暂不可购买".equals(e.getMessage())) {
|
|
|
|
|
+ return R.error("偏远地区暂不可购买");
|
|
|
|
|
+ }
|
|
|
|
|
+ throw e;
|
|
|
|
|
+ }
|
|
|
|
|
+ String cartIds = redisCache.getCacheObject("orderKey:" + param.getOrderKey());
|
|
|
|
|
+ Integer payType = redisCache.getCacheObject("createOrderPayType:" + param.getCreateOrderKey());
|
|
|
|
|
+ if (payType != null) {
|
|
|
|
|
+ param.setPayType(payType.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+ BigDecimal integral = BigDecimal.ZERO;
|
|
|
|
|
+ if (cartIds != null) {
|
|
|
|
|
+ //获取购物车列表
|
|
|
|
|
+ List<FsStoreCartQueryVO> carts = redisCache.getCacheObject("orderCarts:" + param.getOrderKey());
|
|
|
|
|
+ //获取地址
|
|
|
|
|
+ FsUserAddressScrm address = userAddressMapper.selectFsUserAddressById(param.getAddressId());
|
|
|
|
|
+ //生成分布式唯一值
|
|
|
|
|
+ String orderSn = SnowflakeUtil.nextIdStr();
|
|
|
|
|
+ //是否使用积分
|
|
|
|
|
+ Boolean isIntegral = false;
|
|
|
|
|
+ //组合数据
|
|
|
|
|
+ FsStoreOrderScrm storeOrder = new FsStoreOrderScrm();
|
|
|
|
|
+ storeOrder.setStoreHouseCode("CK01");
|
|
|
|
|
+ if(param.getCompanyId()!=null){
|
|
|
|
|
+ storeOrder.setCompanyId(param.getCompanyId());
|
|
|
|
|
+ }
|
|
|
|
|
+ if(param.getCompanyUserId()!=null){
|
|
|
|
|
+ storeOrder.setCompanyUserId(param.getCompanyUserId());
|
|
|
|
|
+ }
|
|
|
|
|
+ if ("北京卓美".equals(companyName) && param.getVideoId()!=null){
|
|
|
|
|
+ storeOrder.setVideoId(param.getVideoId());
|
|
|
|
|
+ storeOrder.setCourseId(param.getCourseId());
|
|
|
|
|
+ storeOrder.setPeriodId(param.getPeriodId());
|
|
|
|
|
+ storeOrder.setProjectId(param.getProjectId());
|
|
|
|
|
+ }
|
|
|
|
|
+ String json = configService.selectConfigByKey("store.config");
|
|
|
|
|
+ StoreConfig config= JSONUtil.toBean(json, StoreConfig.class);
|
|
|
|
|
+
|
|
|
|
|
+ //绑定销售
|
|
|
|
|
+ if("北京卓美".equals(companyName) && param.getVideoId()!=null && storeOrder.getCompanyId() == null || !("北京卓美").equals(companyName)){
|
|
|
|
|
+ FsUserScrm fsuser= userService.selectFsUserById(userId);
|
|
|
|
|
+ if(ObjectUtil.isEmpty(config.getOrderAttribution())
|
|
|
|
|
+ ||!config.getOrderAttribution().equals(1)){
|
|
|
|
|
+ if(param.getCompanyUserId()!=null){
|
|
|
|
|
+ if (ObjectUtil.isNotEmpty(fsuser.getCompanyUserId())&&!fsuser.getCompanyUserId().equals(param.getCompanyUserId())){
|
|
|
|
|
+ CompanyUser companyUser=companyUserService.selectCompanyUserById(fsuser.getCompanyUserId());
|
|
|
|
|
+ return R.error(String.format("请联系【%s】销售进行购买商品!",companyUser.getUserName()));
|
|
|
|
|
+ }else {
|
|
|
|
|
+ fsuser.setCompanyUserId(param.getCompanyUserId());
|
|
|
|
|
+ userService.updateFsUser(fsuser);
|
|
|
|
|
+ }
|
|
|
|
|
+ CompanyUser companyUser=companyUserService.selectCompanyUserById(param.getCompanyUserId());
|
|
|
|
|
+ if(companyUser!=null){
|
|
|
|
|
+ storeOrder.setDeptId(companyUser.getDeptId());
|
|
|
|
|
+ }
|
|
|
|
|
+ }else {
|
|
|
|
|
+ storeOrder.setCompanyUserId(fsuser.getCompanyUserId());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ CompanyUserUser map=new CompanyUserUser();
|
|
|
|
|
+ map.setCompanyUserId(param.getCompanyUserId());
|
|
|
|
|
+ map.setUserId(userId);
|
|
|
|
|
+ List<CompanyUserUser> list= companyUserUserMapper.selectCompanyUserUserList(map);
|
|
|
|
|
+ if(list==null||list.size()==0){
|
|
|
|
|
+ CompanyUser companyUser=companyUserService.selectCompanyUserById(param.getCompanyUserId());
|
|
|
|
|
+ if(companyUser!=null&&companyUser.getStatus().equals("0")){
|
|
|
|
|
+ map.setCompanyId(companyUser.getCompanyId());
|
|
|
|
|
+ companyUserUserMapper.insertCompanyUserUser(map);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ storeOrder.setUserId(userId);
|
|
|
|
|
+ storeOrder.setOrderCode(orderSn);
|
|
|
|
|
+ if (ObjectUtil.isNotEmpty(address)){
|
|
|
|
|
+ storeOrder.setRealName(address.getRealName());
|
|
|
|
|
+ storeOrder.setUserPhone(address.getPhone());
|
|
|
|
|
+ storeOrder.setUserAddress(address.getProvince() + " " + address.getCity() +
|
|
|
|
|
+ " " + address.getDistrict() + " " + address.getDetail().trim());
|
|
|
|
|
+ }
|
|
|
|
|
+ storeOrder.setCartId(cartIds);
|
|
|
|
|
+ storeOrder.setTotalNum(Long.parseLong(String.valueOf(carts.size())));
|
|
|
|
|
+ storeOrder.setTotalPrice(dto.getTotalPrice());
|
|
|
|
|
+ storeOrder.setTotalPostage(dto.getPayPostage());
|
|
|
|
|
+
|
|
|
|
|
+ //优惠券处理
|
|
|
|
|
+ if (param.getCouponUserId() != null) {
|
|
|
|
|
+ FsStoreCouponUserScrm couponUser = couponUserService.selectFsStoreCouponUserById(param.getCouponUserId());
|
|
|
|
|
+ if (couponUser != null && couponUser.getStatus() == 0) {
|
|
|
|
|
+ storeOrder.setCouponId(couponUser.getId());
|
|
|
|
|
+ storeOrder.setCouponPrice(couponUser.getCouponPrice());
|
|
|
|
|
+ couponUser.setStatus(1);
|
|
|
|
|
+ couponUser.setUseTime(new Date());
|
|
|
|
|
+ couponUserService.updateFsStoreCouponUser(couponUser);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ //处理推荐人
|
|
|
|
|
+ FsUserScrm user = userService.selectFsUserById(storeOrder.getUserId());
|
|
|
|
|
+ if (user.getSpreadUserId() != null && user.getSpreadUserId() > 0) {
|
|
|
|
|
+ storeOrder.setTuiUserId(user.getSpreadUserId());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (param.getTuiUserId() != null) {
|
|
|
|
|
+ FsUserScrm tuiUser = userService.selectFsUserById(param.getTuiUserId());
|
|
|
|
|
+ if (tuiUser != null && tuiUser.getIsPromoter() == 1) {
|
|
|
|
|
+ storeOrder.setTuiUserId(param.getTuiUserId());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ storeOrder.setPayPostage(dto.getPayPostage());
|
|
|
|
|
+ storeOrder.setDeductionPrice(dto.getDeductionPrice());
|
|
|
|
|
+ storeOrder.setPaid(0);
|
|
|
|
|
+ storeOrder.setPayType(param.getPayType());
|
|
|
|
|
+ if (isIntegral) {
|
|
|
|
|
+ storeOrder.setPayIntegral(integral);
|
|
|
|
|
+ }
|
|
|
|
|
+ storeOrder.setUseIntegral(BigDecimal.valueOf(dto.getUsedIntegral()));
|
|
|
|
|
+ storeOrder.setBackIntegral(BigDecimal.ZERO);
|
|
|
|
|
+ storeOrder.setGainIntegral(BigDecimal.ZERO);
|
|
|
|
|
+ storeOrder.setMark(param.getMark());
|
|
|
|
|
+ //获取成本价
|
|
|
|
|
+ BigDecimal costPrice = this.getOrderSumPrice(carts, "costPrice");
|
|
|
|
|
+ storeOrder.setCost(costPrice);
|
|
|
|
|
+ storeOrder.setIsChannel(1);
|
|
|
|
|
+ storeOrder.setShippingType(1);
|
|
|
|
|
+ storeOrder.setCreateTime(new Date());
|
|
|
|
|
+
|
|
|
|
|
+ if (config.getServiceFee() != null) {
|
|
|
|
|
+ storeOrder.setServiceFee(config.getServiceFee());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //后台制单处理
|
|
|
|
|
+ if (param.getPayPrice() != null && param.getPayPrice().compareTo(BigDecimal.ZERO) > 0) {
|
|
|
|
|
+ if (param.getPayPrice().compareTo(dto.getTotalPrice()) > 0) {
|
|
|
|
|
+ return R.error("改价价格不能大于商品总价");
|
|
|
|
|
+ }
|
|
|
|
|
+ storeOrder.setPayPrice(param.getPayPrice());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ storeOrder.setPayPrice(dto.getPayPrice());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //付款方式
|
|
|
|
|
+ if (param.getPayType().equals("1") || param.getPayType().equals("99")) {
|
|
|
|
|
+ storeOrder.setStatus(0);
|
|
|
|
|
+ if("广州郑多燕".equals(cloudHostProper.getCompanyName())){
|
|
|
|
|
+ BigDecimal amount = redisCache.getCacheObject("createOrderAmount:" + param.getCreateOrderKey());
|
|
|
|
|
+ storeOrder.setPayDelivery(amount != null ? amount : BigDecimal.ZERO);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (param.getPayType().equals("2")) {
|
|
|
|
|
+ storeOrder.setStatus(1);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (param.getPayType().equals("3")) {
|
|
|
|
|
+ BigDecimal amount = param.getAmount();
|
|
|
|
|
+ if (amount != null && amount.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
|
|
+ storeOrder.setStatus(0);
|
|
|
|
|
+ storeOrder.setPayMoney(amount);
|
|
|
|
|
+ storeOrder.setPayDelivery(storeOrder.getPayPrice().subtract(amount));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ storeOrder.setStatus(1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ Boolean isPay = true;
|
|
|
|
|
+ if (param.getOrderCreateType() != null && param.getOrderCreateType() == 3 && param.getCompanyId() != null) {
|
|
|
|
|
+ Company company = companyMapper.selectCompanyById(param.getCompanyId());
|
|
|
|
|
+ if (company != null) {
|
|
|
|
|
+ if (company.getIsPay() != null && company.getIsPay() == 0 && param.getIsUserApp()) {
|
|
|
|
|
+ storeOrder.setStatus(1);
|
|
|
|
|
+ isPay = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ storeOrder.setOrderCreateType(param.getOrderCreateType());
|
|
|
|
|
+ Long prescribe = carts.stream().filter(item -> item.getProductType() != null && item.getProductType() == 2).count();
|
|
|
|
|
+ if (prescribe > 0) {
|
|
|
|
|
+ storeOrder.setIsPrescribe(1);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ storeOrder.setIsPrescribe(0);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (storeOrder.getCustomerId() == null) {
|
|
|
|
|
+ storeOrder.setCustomerId(param.getCustomerId());
|
|
|
|
|
+ }
|
|
|
|
|
+ FsStoreOrderScrm tempOrder = redisCache.getCacheObject("orderInfo:" + param.getCreateOrderKey());
|
|
|
|
|
+ if (tempOrder != null) {
|
|
|
|
|
+ storeOrder.setOrderType(tempOrder.getOrderType());
|
|
|
|
|
+ storeOrder.setOrderMedium(tempOrder.getOrderMedium());
|
|
|
|
|
+ redisCache.deleteObject("orderInfo:" + param.getCreateOrderKey());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ storeOrder.setOrderType(param.getOrderType());
|
|
|
|
|
+ storeOrder.setOrderMedium(param.getOrderMedium());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //活动商品只扣Redis(已在上文扣减),DB延后扣减
|
|
|
|
|
+ // storeOrder.setAssociatedId
|
|
|
|
|
+ storeOrder.setAssociatedId(associatedId);
|
|
|
|
|
+ Integer flag = fsStoreOrderMapper.insertFsStoreOrder(storeOrder);
|
|
|
|
|
+ if (flag == 0) {
|
|
|
|
|
+ return R.error("订单创建失败");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 活动商品:订单创建成功后,同步扣减DB中的商品规格库存和销量(与普通下单一致)
|
|
|
|
|
+ this.deStockIncSale(carts);
|
|
|
|
|
+
|
|
|
|
|
+ if (!isPay && storeOrder.getCompanyId() != null) {
|
|
|
|
|
+ addOrderAudit(storeOrder);
|
|
|
|
|
+ }
|
|
|
|
|
+ //使用了积分扣积分
|
|
|
|
|
+ if (dto.getUsedIntegral() > 0) {
|
|
|
|
|
+ this.decIntegral(userId, dto.getUsedIntegral(), dto.getDeductionPrice(), storeOrder.getId().toString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //保存OrderItem
|
|
|
|
|
+ List<FsStoreOrderItemScrm> listOrderItem = new ArrayList<>();
|
|
|
|
|
+ for (FsStoreCartQueryVO vo : carts) {
|
|
|
|
|
+ checkAndRecordPurchaseLimit(userId, vo.getProductId(), vo.getCartNum());
|
|
|
|
|
+ FsStoreCartDTO fsStoreCartDTO = new FsStoreCartDTO();
|
|
|
|
|
+ fsStoreCartDTO.setProductId(vo.getProductId());
|
|
|
|
|
+ fsStoreCartDTO.setPrice(vo.getPrice());
|
|
|
|
|
+ fsStoreCartDTO.setSku(vo.getProductAttrName());
|
|
|
|
|
+ fsStoreCartDTO.setProductName(vo.getProductName());
|
|
|
|
|
+ fsStoreCartDTO.setNum(vo.getCartNum());
|
|
|
|
|
+ fsStoreCartDTO.setBarCode(vo.getBarCode());
|
|
|
|
|
+ fsStoreCartDTO.setGroupBarCode(vo.getGroupBarCode());
|
|
|
|
|
+ fsStoreCartDTO.setBrokerage(vo.getBrokerage());
|
|
|
|
|
+ fsStoreCartDTO.setBrokerageTwo(vo.getBrokerageTwo());
|
|
|
|
|
+ fsStoreCartDTO.setBrokerageThree(vo.getBrokerageThree());
|
|
|
|
|
+ if (StringUtils.isEmpty(vo.getProductAttrImage())) {
|
|
|
|
|
+ fsStoreCartDTO.setImage(vo.getProductImage());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ fsStoreCartDTO.setImage(vo.getProductAttrImage());
|
|
|
|
|
+ }
|
|
|
|
|
+ FsStoreOrderItemScrm item = new FsStoreOrderItemScrm();
|
|
|
|
|
+ item.setOrderId(storeOrder.getId());
|
|
|
|
|
+ item.setOrderCode(orderSn);
|
|
|
|
|
+ item.setCartId(vo.getId());
|
|
|
|
|
+ item.setProductId(vo.getProductId());
|
|
|
|
|
+ item.setJsonInfo(JSONUtil.toJsonStr(fsStoreCartDTO));
|
|
|
|
|
+ item.setNum(vo.getCartNum());
|
|
|
|
|
+ item.setIsAfterSales(0);
|
|
|
|
|
+ if (vo.getProductType().equals(2)) {
|
|
|
|
|
+ item.setIsPrescribe(1);
|
|
|
|
|
+ }
|
|
|
|
|
+ fsStoreOrderItemMapper.insertFsStoreOrderItem(item);
|
|
|
|
|
+ listOrderItem.add(item);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (listOrderItem.size() > 0) {
|
|
|
|
|
+ String itemJson = JSONUtil.toJsonStr(listOrderItem);
|
|
|
|
|
+ storeOrder.setItemJson(itemJson);
|
|
|
|
|
+ fsStoreOrderMapper.updateFsStoreOrder(storeOrder);
|
|
|
|
|
+ }
|
|
|
|
|
+ //购物车状态修改
|
|
|
|
|
+ cartMapper.updateIsPay(cartIds);
|
|
|
|
|
+
|
|
|
|
|
+ //删除缓存
|
|
|
|
|
+ redisCache.deleteObject("orderKey:" + param.getOrderKey());
|
|
|
|
|
+ if (config.getIsBrushOrders() == null || !(config.getIsBrushOrders() && param.getCompanyUserId() != null)) {
|
|
|
|
|
+ redisCache.deleteObject("orderCarts:" + param.getOrderKey());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //添加记录
|
|
|
|
|
+ orderStatusService.create(storeOrder.getId(), OrderLogEnum.CREATE_ORDER.getValue(),
|
|
|
|
|
+ OrderLogEnum.CREATE_ORDER.getDesc());
|
|
|
|
|
+
|
|
|
|
|
+ //加入redis,24小时自动取消
|
|
|
|
|
+ String redisKey = String.valueOf(StrUtil.format("{}{}",
|
|
|
|
|
+ StoreConstants.REDIS_ORDER_OUTTIME_UNPAY, storeOrder.getId()));
|
|
|
|
|
+ if (config.getUnPayTime() != null && config.getUnPayTime() > 0) {
|
|
|
|
|
+ redisCache.setCacheObject(redisKey, storeOrder.getId(), config.getUnPayTime(), TimeUnit.MINUTES);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ redisCache.setCacheObject(redisKey, storeOrder.getId(), 30, TimeUnit.MINUTES);
|
|
|
|
|
+ }
|
|
|
|
|
+ //添加支付到期时间
|
|
|
|
|
+ Calendar calendar = Calendar.getInstance();
|
|
|
|
|
+ calendar.setTime(storeOrder.getCreateTime());
|
|
|
|
|
+ if (config.getUnPayTime() != null) {
|
|
|
|
|
+ calendar.add(Calendar.MINUTE, config.getUnPayTime());
|
|
|
|
|
+ }
|
|
|
|
|
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
+ String payLimitTime = format.format(calendar.getTime());
|
|
|
|
|
+ redisCache.setCacheObject("orderAmount:" + storeOrder.getId(), storeOrder.getPayMoney(), 24, TimeUnit.HOURS);
|
|
|
|
|
+ //删除推荐订单KEY
|
|
|
|
|
+ String createOrderKey = param.getCreateOrderKey();
|
|
|
|
|
+ if("鸿森堂".equals(cloudHostProper.getCompanyName())){
|
|
|
|
|
+ BigDecimal amount = redisCache.getCacheObject("createOrderAmount:" + createOrderKey);
|
|
|
|
|
+ redisCache.setCacheObject("orderAmount:" + storeOrder.getId(), amount, 24, TimeUnit.HOURS);
|
|
|
|
|
+ }else {
|
|
|
|
|
+ if (StringUtils.isNotEmpty(createOrderKey)) {
|
|
|
|
|
+ if (config.getIsBrushOrders() == null || !(config.getIsBrushOrders() && param.getCompanyUserId() != null)) {
|
|
|
|
|
+ redisCache.deleteObject("createOrderKey:" + createOrderKey);
|
|
|
|
|
+ redisCache.deleteObject("orderCarts:" + createOrderKey);
|
|
|
|
|
+ redisCache.deleteObject("createOrderMoney:" + createOrderKey);
|
|
|
|
|
+ }
|
|
|
|
|
+ BigDecimal amount = redisCache.getCacheObject("createOrderAmount:" + createOrderKey);
|
|
|
|
|
+ redisCache.deleteObject("createOrderAmount:" + createOrderKey);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 订单创建成功后,异步同步活动中间表库存到DB(最终一致性兜底)
|
|
|
|
|
+ final Long finalAssociatedId = param.getAssociatedId();
|
|
|
|
|
+ final Integer finalOrderType = orderType;
|
|
|
|
|
+ CompletableFuture.runAsync(() -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (finalOrderType == 6) {
|
|
|
|
|
+ activityStockService.syncFlashSaleStockToDb(finalAssociatedId,
|
|
|
|
|
+ (long) activityStockService.getStock(finalOrderType, finalAssociatedId));
|
|
|
|
|
+ } else if (finalOrderType == 7) {
|
|
|
|
|
+ activityStockService.syncDiscountStockToDb(finalAssociatedId,
|
|
|
|
|
+ (long) activityStockService.getStock(finalOrderType, finalAssociatedId));
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("活动中间表库存异步同步失败,associatedId={}, orderType={}", finalAssociatedId, finalOrderType, e);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return R.ok().put("order", storeOrder).put("payLimitTime", payLimitTime);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return R.error("订单已过期");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ // Redis已扣减成功,订单创建过程异常,必须回滚Redis库存
|
|
|
|
|
+ try {
|
|
|
|
|
+ activityStockService.rollbackStock(orderType, param.getAssociatedId(), activityDeductNum);
|
|
|
|
|
+ log.info("订单创建异常,Redis库存已回滚,associatedId={}, orderType={}, 回滚数量={}",
|
|
|
|
|
+ param.getAssociatedId(), orderType, activityDeductNum);
|
|
|
|
|
+ } catch (Exception rollbackEx) {
|
|
|
|
|
+ log.error("订单创建异常后Redis库存回滚失败!associatedId={},orderType={},需要人工处理",
|
|
|
|
|
+ param.getAssociatedId(), orderType, rollbackEx);
|
|
|
|
|
+ }
|
|
|
|
|
+ log.error("活动订单创建异常,orderType={}, associatedId={}", orderType, param.getAssociatedId(), e);
|
|
|
|
|
+ throw e;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
public R createOrderByPrescribe(Long prescribeId) {
|
|
public R createOrderByPrescribe(Long prescribeId) {
|
|
|
FsPrescribe prescribe = prescribeMapper.selectFsPrescribeByPrescribeId(prescribeId);
|
|
FsPrescribe prescribe = prescribeMapper.selectFsPrescribeByPrescribeId(prescribeId);
|
|
@@ -1356,6 +1825,14 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @deprecated 已改用deStockIncSale统一扣减
|
|
|
|
|
+ */
|
|
|
|
|
+ @Deprecated
|
|
|
|
|
+ private void decActivityProductStock(List<FsStoreCartQueryVO> cartInfo) {
|
|
|
|
|
+ deStockIncSale(cartInfo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
//未支付取消订单
|
|
//未支付取消订单
|
|
|
@Override
|
|
@Override
|
|
|
public void cancelOrder(Long orderId) {
|
|
public void cancelOrder(Long orderId) {
|
|
@@ -2646,6 +3123,12 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
//退库存
|
|
//退库存
|
|
|
//获取订单下的商品
|
|
//获取订单下的商品
|
|
|
List<FsStoreOrderItemVO> orderItemVOS = fsStoreOrderItemMapper.selectFsStoreOrderItemListByOrderId(order.getId());
|
|
List<FsStoreOrderItemVO> orderItemVOS = fsStoreOrderItemMapper.selectFsStoreOrderItemListByOrderId(order.getId());
|
|
|
|
|
+
|
|
|
|
|
+ // 活动订单:先回滚Redis规格库存
|
|
|
|
|
+ if (isActivityOrder(order)) {
|
|
|
|
|
+ refundActivityStock(order, orderItemVOS);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
for (FsStoreOrderItemVO vo : orderItemVOS) {
|
|
for (FsStoreOrderItemVO vo : orderItemVOS) {
|
|
|
if (vo.getIsAfterSales() == 1) {
|
|
if (vo.getIsAfterSales() == 1) {
|
|
|
productService.incProductStock(vo.getNum(), vo.getProductId(), vo.getProductAttrValueId());
|
|
productService.incProductStock(vo.getNum(), vo.getProductId(), vo.getProductAttrValueId());
|
|
@@ -3464,6 +3947,13 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
private void refundStock(FsStoreOrderScrm order) {
|
|
private void refundStock(FsStoreOrderScrm order) {
|
|
|
//获取订单下的商品
|
|
//获取订单下的商品
|
|
|
List<FsStoreOrderItemVO> orderItemVOS = fsStoreOrderItemMapper.selectFsStoreOrderItemListByOrderId(order.getId());
|
|
List<FsStoreOrderItemVO> orderItemVOS = fsStoreOrderItemMapper.selectFsStoreOrderItemListByOrderId(order.getId());
|
|
|
|
|
+
|
|
|
|
|
+ // 活动订单:先回滚Redis规格库存
|
|
|
|
|
+ if (isActivityOrder(order)) {
|
|
|
|
|
+ refundActivityStock(order, orderItemVOS);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // DB规格库存回滚
|
|
|
for (FsStoreOrderItemVO vo : orderItemVOS) {
|
|
for (FsStoreOrderItemVO vo : orderItemVOS) {
|
|
|
productService.incProductStock(vo.getNum(), vo.getProductId()
|
|
productService.incProductStock(vo.getNum(), vo.getProductId()
|
|
|
, vo.getProductAttrValueId());
|
|
, vo.getProductAttrValueId());
|
|
@@ -3471,6 +3961,46 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 判断是否为活动订单(秒杀 orderType=6 或限时折扣 orderType=7)
|
|
|
|
|
+ */
|
|
|
|
|
+ private boolean isActivityOrder(FsStoreOrderScrm order) {
|
|
|
|
|
+ return order != null
|
|
|
|
|
+ && order.getOrderType() != null
|
|
|
|
|
+ && (order.getOrderType() == 6 || order.getOrderType() == 7)
|
|
|
|
|
+ && order.getAssociatedId() != null
|
|
|
|
|
+ && order.getAssociatedId() > 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 活动订单退款时回滚Redis规格库存(Lua原子操作)。
|
|
|
|
|
+ * 异常不中断退款主流程,但记录错误日志以便人工排查。
|
|
|
|
|
+ */
|
|
|
|
|
+ private void refundActivityStock(FsStoreOrderScrm order, List<FsStoreOrderItemVO> items) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ int totalRefundNum = 0;
|
|
|
|
|
+ if (items != null) {
|
|
|
|
|
+ for (FsStoreOrderItemVO vo : items) {
|
|
|
|
|
+ if (vo.getNum() != null) {
|
|
|
|
|
+ totalRefundNum += vo.getNum();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (totalRefundNum > 0) {
|
|
|
|
|
+ activityStockService.rollbackStock(
|
|
|
|
|
+ order.getOrderType(),
|
|
|
|
|
+ order.getAssociatedId(),
|
|
|
|
|
+ totalRefundNum);
|
|
|
|
|
+ log.info("活动订单退款Redis库存回滚成功,orderId={},orderType={},associatedId={},quantity={}",
|
|
|
|
|
+ order.getId(), order.getOrderType(), order.getAssociatedId(), totalRefundNum);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("活动订单退款Redis库存回滚失败!orderId={},orderType={},associatedId={},需人工处理",
|
|
|
|
|
+ order.getId(), order.getOrderType(), order.getAssociatedId(), e);
|
|
|
|
|
+ // 不中断退款流程
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 获取订单价格
|
|
* 获取订单价格
|
|
@@ -6431,10 +6961,32 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
|
|
|
FsStoreOrderPriceDTO priceGroup = this.getOrderPriceGroup(carts, userAddress);
|
|
FsStoreOrderPriceDTO priceGroup = this.getOrderPriceGroup(carts, userAddress);
|
|
|
BigDecimal payPostage = priceGroup.getStorePostage();
|
|
BigDecimal payPostage = priceGroup.getStorePostage();
|
|
|
BigDecimal badCode = BigDecimal.valueOf(-1);
|
|
BigDecimal badCode = BigDecimal.valueOf(-1);
|
|
|
- // 检查运费计算结果,如果是 -1 表示偏远地区不可购买
|
|
|
|
|
if (payPostage.compareTo(badCode) == 0) {
|
|
if (payPostage.compareTo(badCode) == 0) {
|
|
|
throw new ServiceException("偏远地区暂不可购买");
|
|
throw new ServiceException("偏远地区暂不可购买");
|
|
|
}
|
|
}
|
|
|
return payPostage;
|
|
return payPostage;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+// @Override
|
|
|
|
|
+// public R getExpressMulti(FsStoreOrder order) {
|
|
|
|
|
+// //顺丰轨迹查询处理
|
|
|
|
|
+// String lastFourNumber = PhoneUtils.getLastFourNum(order.getUserPhone());
|
|
|
|
|
+// // 获取该订单关联的物流信息
|
|
|
|
|
+// List<FsStoreDelivers> fsStoreDelivers = fsStoreDeliversMapper.findByOrderId(order.getId());
|
|
|
|
|
+// if(CollectionUtils.isEmpty(fsStoreDelivers)){
|
|
|
|
|
+// return R.ok("当前订单号暂无物流信息");
|
|
|
|
|
+// }
|
|
|
|
|
+//
|
|
|
|
|
+// List<ExpressInfoDTO> result = new ArrayList<>();
|
|
|
|
|
+// for (FsStoreDelivers fsStoreDeliver : fsStoreDelivers) {
|
|
|
|
|
+// ExpressInfoDTO dto=expressService.getExpressInfo(order.getOrderCode(),
|
|
|
|
|
+// fsStoreDeliver.getDeliverSn(),
|
|
|
|
|
+// fsStoreDeliver.getDeliverId(),
|
|
|
|
|
+// lastFourNumber);
|
|
|
|
|
+// result.add(dto);
|
|
|
|
|
+// }
|
|
|
|
|
+//
|
|
|
|
|
+// return R.ok().put("data",result);
|
|
|
|
|
+// }
|
|
|
|
|
+
|
|
|
}
|
|
}
|