|
@@ -1,27 +1,74 @@
|
|
|
package edu.travel.commodity.service.impl;
|
|
|
|
|
|
+import cn.hutool.core.bean.BeanUtil;
|
|
|
+import cn.hutool.core.lang.Snowflake;
|
|
|
+import cn.hutool.core.util.IdUtil;
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import edu.travel.adapter.service.country.CountryAdapter;
|
|
|
+import edu.travel.adapter.service.currency.CurrencyAdapter;
|
|
|
+import edu.travel.adapter.service.order.OrderAdapter;
|
|
|
+import edu.travel.adapter.service.order.OrderItemAdapter;
|
|
|
+import edu.travel.adapter.service.order.ShopOrderLogAdapter;
|
|
|
+import edu.travel.commodity.constant.RedisKey;
|
|
|
+import edu.travel.commodity.entity.ShopAddress;
|
|
|
+import edu.travel.commodity.entity.ShopProduct;
|
|
|
import edu.travel.commodity.entity.ShopProductSku;
|
|
|
+import edu.travel.commodity.enums.OrderStateEnum;
|
|
|
import edu.travel.commodity.mapper.ShopProductSkuMapper;
|
|
|
import edu.travel.commodity.mapper.ShopProductSpecMapper;
|
|
|
+import edu.travel.commodity.service.ShopAddressService;
|
|
|
+import edu.travel.commodity.service.ShopProductService;
|
|
|
import edu.travel.commodity.service.ShopProductSkuService;
|
|
|
+import edu.travel.exception.BaseException;
|
|
|
+import edu.travel.remote.dto.*;
|
|
|
import edu.travel.remote.vo.ShopSkuSpecValueVo;
|
|
|
+import edu.travel.remote.vo.ShopSnapshotVo;
|
|
|
+import edu.travel.remote.vo.SpecValueVo;
|
|
|
+import edu.travel.rpc.RPCBaseResponse;
|
|
|
+import edu.travel.vo.BaseCountryServeVo;
|
|
|
+import edu.travel.vo.ShopCurrencyVo;
|
|
|
+import io.seata.spring.annotation.GlobalTransactional;
|
|
|
+import org.redisson.api.RLock;
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.web.context.request.RequestContextHolder;
|
|
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
|
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
+import java.math.BigDecimal;
|
|
|
import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
+
|
|
|
@Service
|
|
|
public class ShopProductSkuServiceImpl extends ServiceImpl<ShopProductSkuMapper, ShopProductSku> implements ShopProductSkuService {
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
private ShopProductSpecMapper shopProductSpecMapper;
|
|
|
-
|
|
|
+ @Autowired
|
|
|
+ private ShopProductService shopProductService;
|
|
|
+ @Autowired
|
|
|
+ private RedissonClient redissonClient;
|
|
|
+ @Autowired
|
|
|
+ private ShopProductSkuMapper shopProductSkuMapper;
|
|
|
+ @Autowired
|
|
|
+ private ShopAddressService shopAddressService;
|
|
|
+ @Autowired
|
|
|
+ private CountryAdapter countryAdapter;
|
|
|
+ @Autowired
|
|
|
+ private CurrencyAdapter currencyAdapter;
|
|
|
+ @Autowired
|
|
|
+ private OrderAdapter orderAdapter;
|
|
|
+ @Autowired
|
|
|
+ private OrderItemAdapter orderItemAdapter;
|
|
|
+ @Autowired
|
|
|
+ private ShopOrderLogAdapter shopOrderLogAdapter;
|
|
|
+ @Autowired
|
|
|
+ private ShopProductSkuService shopProductSkuService;
|
|
|
/**
|
|
|
* 查询SKU下的规格和对应的规格值 规格 排序 规格值排序
|
|
|
* sku -> 规格 ->规格值
|
|
@@ -36,5 +83,138 @@ public class ShopProductSkuServiceImpl extends ServiceImpl<ShopProductSkuMapper,
|
|
|
return list.stream().collect(Collectors.groupingBy(ShopSkuSpecValueVo::getSkuId));
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ @GlobalTransactional
|
|
|
+ public String shopProductSku(AddShopOrderDto params) {
|
|
|
+ List<AddShopProductOrderDto> products = params.getProducts();
|
|
|
+ //商品ID
|
|
|
+ Set<String> product = products.stream().map(AddShopProductOrderDto::getProductId).collect(Collectors.toSet());
|
|
|
+ List<ShopProduct> list1 = shopProductService.lambdaQuery().in(ShopProduct::getId, product).eq(ShopProduct::getStatus, 0).list();
|
|
|
+ if(list1.size()<products.size()){
|
|
|
+ throw new BaseException("商品不存在");
|
|
|
+ }
|
|
|
+ HashMap<String, ShopProduct> productMap = new HashMap<>();
|
|
|
+ for (ShopProduct shopProduct : list1) {
|
|
|
+ productMap.put(shopProduct.getId().toString(), shopProduct);
|
|
|
+ }
|
|
|
+ List<ShopProductSku> list = shopProductSkuMapper.getByProductSkus(products);
|
|
|
+ if(list.size()<products.size()){
|
|
|
+ throw new BaseException("商品规格已下架");
|
|
|
+ }
|
|
|
+ ShopAddress address = shopAddressService.getById(params.getAddressId());
|
|
|
+ if(ObjectUtil.isEmpty(address)){
|
|
|
+ throw new BaseException("地址不存在");
|
|
|
+ }
|
|
|
+ RPCBaseResponse<ShopCurrencyVo> formId1 = currencyAdapter.getFormId(params.getCurrencyId());
|
|
|
+ ShopCurrencyVo currency = formId1.getData();
|
|
|
+ RPCBaseResponse<BaseCountryServeVo> formId =
|
|
|
+ countryAdapter.getFormId(params.getCountry());
|
|
|
+ BaseCountryServeVo country = formId.getData();
|
|
|
+ //product+skuId 升序
|
|
|
+ List<String> collect = list.stream().map(item -> item.getProductId()+":"+ item.getSkuId()).sorted().collect(Collectors.toList());
|
|
|
+ RLock[] locks=new RLock[products.size()];
|
|
|
+ for (int i = 0; i < locks.length; i++) {
|
|
|
+ String s = collect.get(i);
|
|
|
+ locks[i] = redissonClient.getFairLock(RedisKey.PRODUCT_ORDER+s);
|
|
|
+ }
|
|
|
+ RLock multiLock = redissonClient.getMultiLock(locks);
|
|
|
+
|
|
|
+
|
|
|
+ try {
|
|
|
+ if(multiLock.tryLock(20, TimeUnit.SECONDS)){
|
|
|
+ List<ShopProductSku> ls = shopProductSkuMapper.getByProductSkus(products);
|
|
|
+ HashMap<String, ShopProductSku> map = new HashMap<>();
|
|
|
+ for (ShopProductSku l : ls) {
|
|
|
+ map.put(l.getProductId().toString()+l.getSkuId(),l);
|
|
|
+ }
|
|
|
+ BigDecimal all = new BigDecimal(0L);
|
|
|
+
|
|
|
+ ArrayList<AddOrderItemDto> orderItems = new ArrayList<>();
|
|
|
+ Snowflake snowflake = IdUtil.createSnowflake(1, 1);
|
|
|
+ long orderNum = snowflake.nextId();
|
|
|
+ for (AddShopProductOrderDto dto : products) {
|
|
|
+ if(dto.getQuantity()<=0) {
|
|
|
+ throw new BaseException("购买数量异常");
|
|
|
+ }
|
|
|
+ ShopProduct shopProduct = productMap.get(dto.getProductId());
|
|
|
+ ShopProductSku shopProductSku = map.get(dto.getProductId() + dto.getSkuId());
|
|
|
+ if(ObjectUtil.isEmpty(shopProductSku)||ObjectUtil.isEmpty(shopProduct)){
|
|
|
+ throw new BaseException("商品"+shopProduct.getProductName()+"已下架");
|
|
|
+ }
|
|
|
+ //冻结量
|
|
|
+ Integer freeze = shopProductSku.getFreeze();
|
|
|
+ //库存
|
|
|
+ Integer inventory = shopProductSku.getInventory();
|
|
|
+ //可用数量
|
|
|
+ int i = inventory - freeze;
|
|
|
+
|
|
|
+ if(i<dto.getQuantity()){
|
|
|
+ throw new BaseException(shopProduct.getProductName()+"库存不足");
|
|
|
+ }
|
|
|
+ //修改数量
|
|
|
+ shopProductSku.setFreeze(shopProductSku.getFreeze()+dto.getQuantity());
|
|
|
+ //库存数量
|
|
|
+ shopProductSku.setInventory(shopProductSku.getInventory()-dto.getQuantity());
|
|
|
+ //商品价格
|
|
|
+ BigDecimal multiply = shopProductSku.getPrice().multiply(new BigDecimal(dto.getQuantity()));
|
|
|
+ //总价
|
|
|
+ all=all.add(multiply);
|
|
|
+
|
|
|
+ AddOrderItemDto addOrderItemDto = new AddOrderItemDto();
|
|
|
+ addOrderItemDto.setProductId(shopProduct.getId().toString());
|
|
|
+ addOrderItemDto.setSkuId(shopProductSku.getSkuId().toString());
|
|
|
+ addOrderItemDto.setPrice(shopProductSku.getPrice());
|
|
|
+ addOrderItemDto.setQuantity(dto.getQuantity());
|
|
|
+ addOrderItemDto.setOrderId(orderNum+"");
|
|
|
+ //快照信息 ShopSnapshotVo
|
|
|
+
|
|
|
+ //addOrderItemDto.setSnapshot();
|
|
|
+
|
|
|
+ orderItems.add(addOrderItemDto);
|
|
|
+ }
|
|
|
+ updateBatchById(ls);
|
|
|
+
|
|
|
+ AddOrderDto order = new AddOrderDto();
|
|
|
+ order.setCountryId(params.getCountry());
|
|
|
+ order.setTotalAmount(all);
|
|
|
+ order.setStatus(OrderStateEnum.WAITING_FOR_PAYMENT.getState());
|
|
|
+ order.setAddressId(params.getAddressId());
|
|
|
+ order.setAddress(address.getDetailedAddress());
|
|
|
+ order.setGlobalCouponId(params.getGlobalCouponId());
|
|
|
+ order.setGlobalCouponId(country.getServiceChargeValue().toString());
|
|
|
+ order.setOrderNumber(orderNum+"");
|
|
|
+ order.setCurrency(currency.getCurrencySymbol());
|
|
|
+ order.setCurrencyId(currency.getId().toString());
|
|
|
+
|
|
|
+ orderAdapter.addShopOrder(order);
|
|
|
+ orderItemAdapter.addShopOrderItem(orderItems);
|
|
|
+ AddOrderLogDto addOrderLogDto = new AddOrderLogDto();
|
|
|
+ addOrderLogDto.setOrderId(orderNum+"");
|
|
|
+ addOrderLogDto.setDescription("下单成功");
|
|
|
+ addOrderLogDto.setStatus(OrderStateEnum.WAITING_FOR_PAYMENT.getState());
|
|
|
+ shopOrderLogAdapter.addOrderLog(addOrderLogDto);
|
|
|
+ }
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ throw new BaseException(e);
|
|
|
+ }
|
|
|
+ return "下单成功";
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取商品快照信息
|
|
|
+ public Map<String,ShopSnapshotVo> getSnapshot(Set<String> skuId) {
|
|
|
+ Map<String, List<ShopSkuSpecValueVo>> specs = shopProductSkuService.getSkuValuesById(skuId);
|
|
|
+ HashMap<String, ShopSnapshotVo> map = new HashMap<>();
|
|
|
+ specs.forEach((k,v)->{
|
|
|
+ ShopSnapshotVo shopSnapshotVo = new ShopSnapshotVo();
|
|
|
+ List<SpecValueVo> specValueVos = BeanUtil.copyToList(v, SpecValueVo.class);
|
|
|
+ shopSnapshotVo.setSnapshotSpec(specValueVos);
|
|
|
+ map.put(k,shopSnapshotVo);
|
|
|
+ });
|
|
|
+
|
|
|
|
|
|
-}
|
|
|
+
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|