|
|
@@ -3,7 +3,9 @@ package com.etotem.cfc.service;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.etotem.cfc.entity.Product;
|
|
|
import com.etotem.cfc.entity.ProductSku;
|
|
|
+import com.etotem.cfc.entity.ProductSkuComboItem;
|
|
|
import com.etotem.cfc.mapper.ProductMapper;
|
|
|
+import com.etotem.cfc.mapper.ProductSkuComboItemMapper;
|
|
|
import com.etotem.cfc.mapper.ProductSkuMapper;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
@@ -27,16 +29,27 @@ public class ProductSkuService {
|
|
|
@Resource
|
|
|
private ProductMapper productMapper;
|
|
|
|
|
|
+ @Resource
|
|
|
+ private ProductSkuComboItemMapper comboItemMapper;
|
|
|
+
|
|
|
public List<ProductSku> listByProductId(Long productId) {
|
|
|
- return skuMapper.findByProductId(productId);
|
|
|
+ List<ProductSku> list = skuMapper.findByProductId(productId);
|
|
|
+ fillComboItems(list);
|
|
|
+ return list;
|
|
|
}
|
|
|
|
|
|
public List<ProductSku> listByProductIdAll(Long productId) {
|
|
|
- return skuMapper.findByProductIdAll(productId);
|
|
|
+ List<ProductSku> list = skuMapper.findByProductIdAll(productId);
|
|
|
+ fillComboItems(list);
|
|
|
+ return list;
|
|
|
}
|
|
|
|
|
|
public ProductSku getById(Long id) {
|
|
|
- return skuMapper.findById(id);
|
|
|
+ ProductSku sku = skuMapper.findById(id);
|
|
|
+ if (sku != null) {
|
|
|
+ fillComboItems(java.util.Collections.singletonList(sku));
|
|
|
+ }
|
|
|
+ return sku;
|
|
|
}
|
|
|
|
|
|
@Transactional
|
|
|
@@ -56,12 +69,18 @@ public class ProductSkuService {
|
|
|
if (sku.getSkuCode() == null || sku.getSkuCode().isEmpty()) {
|
|
|
sku.setSkuCode("SKU-" + sku.getProductId() + "-" + System.currentTimeMillis());
|
|
|
}
|
|
|
+ validateComboItems(sku.getComboItems());
|
|
|
skuMapper.insert(sku);
|
|
|
+ saveComboItems(sku.getId(), sku.getComboItems());
|
|
|
return sku;
|
|
|
}
|
|
|
|
|
|
@Transactional
|
|
|
public void update(ProductSku sku) {
|
|
|
+ validateComboItems(sku.getComboItems());
|
|
|
+ if (sku.getComboItems() != null && !sku.getComboItems().isEmpty()) {
|
|
|
+ sku.setLinkedProductId(null);
|
|
|
+ }
|
|
|
if (sku.getLinkedProductId() == null) {
|
|
|
// Legacy SKU: 需要 specs
|
|
|
if (sku.getSpecs() == null || sku.getSpecs().trim().isEmpty()) {
|
|
|
@@ -70,10 +89,18 @@ public class ProductSkuService {
|
|
|
}
|
|
|
sku.setUpdateTime(new Date());
|
|
|
skuMapper.updateById(sku);
|
|
|
+ saveComboItems(sku.getId(), sku.getComboItems());
|
|
|
+ if (sku.getLinkedProductId() == null) {
|
|
|
+ skuMapper.update(null, new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<ProductSku>()
|
|
|
+ .eq(ProductSku::getId, sku.getId())
|
|
|
+ .set(ProductSku::getLinkedProductId, null));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Transactional
|
|
|
public void delete(Long id) {
|
|
|
+ comboItemMapper.delete(new LambdaQueryWrapper<ProductSkuComboItem>()
|
|
|
+ .eq(ProductSkuComboItem::getSkuId, id));
|
|
|
skuMapper.deleteById(id);
|
|
|
}
|
|
|
|
|
|
@@ -208,4 +235,91 @@ public class ProductSkuService {
|
|
|
return s.replace("\\", "\\\\").replace("\"", "\\\"")
|
|
|
.replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
|
|
|
}
|
|
|
-}
|
|
|
+
|
|
|
+ private void saveComboItems(Long skuId, List<ProductSkuComboItem> items) {
|
|
|
+ if (items == null) return;
|
|
|
+ comboItemMapper.delete(new LambdaQueryWrapper<ProductSkuComboItem>()
|
|
|
+ .eq(ProductSkuComboItem::getSkuId, skuId));
|
|
|
+ if (items.isEmpty()) return;
|
|
|
+ for (ProductSkuComboItem item : items) {
|
|
|
+ item.setId(null);
|
|
|
+ item.setSkuId(skuId);
|
|
|
+ if (item.getQuantity() == null || item.getQuantity() < 1) item.setQuantity(1);
|
|
|
+ comboItemMapper.insert(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void validateComboItems(List<ProductSkuComboItem> items) {
|
|
|
+ if (items == null || items.isEmpty()) return;
|
|
|
+ for (ProductSkuComboItem item : items) {
|
|
|
+ if (item.getChildProductId() == null) throw new IllegalArgumentException("组合商品不能为空");
|
|
|
+ List<ProductSku> childSkus = skuMapper.findByProductId(item.getChildProductId());
|
|
|
+ boolean hasEnabledSku = childSkus != null
|
|
|
+ && childSkus.stream().anyMatch(s -> s.getEnabled() != null && s.getEnabled() == 1);
|
|
|
+ if (hasEnabledSku && item.getChildSkuId() == null) {
|
|
|
+ throw new IllegalArgumentException("组合商品存在 SKU,必须选择具体 SKU");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void fillComboItems(List<ProductSku> skus) {
|
|
|
+ if (skus == null || skus.isEmpty()) return;
|
|
|
+ List<Long> skuIds = skus.stream().map(ProductSku::getId)
|
|
|
+ .filter(java.util.Objects::nonNull).collect(java.util.stream.Collectors.toList());
|
|
|
+ if (skuIds.isEmpty()) return;
|
|
|
+ List<ProductSkuComboItem> all = comboItemMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<ProductSkuComboItem>().in(ProductSkuComboItem::getSkuId, skuIds));
|
|
|
+ if (all.isEmpty()) {
|
|
|
+ skus.forEach(s -> s.setComboItems(java.util.Collections.emptyList()));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ java.util.Set<Long> productIds = all.stream().map(ProductSkuComboItem::getChildProductId)
|
|
|
+ .filter(java.util.Objects::nonNull).collect(java.util.stream.Collectors.toSet());
|
|
|
+ java.util.Map<Long, Product> productMap = productIds.isEmpty() ? java.util.Collections.emptyMap()
|
|
|
+ : productMapper.selectBatchIds(productIds).stream()
|
|
|
+ .collect(java.util.stream.Collectors.toMap(Product::getId, p -> p, (a, b) -> a));
|
|
|
+ java.util.Set<Long> childSkuIds = all.stream().map(ProductSkuComboItem::getChildSkuId)
|
|
|
+ .filter(java.util.Objects::nonNull).collect(java.util.stream.Collectors.toSet());
|
|
|
+ java.util.Map<Long, ProductSku> childSkuMap = childSkuIds.isEmpty() ? java.util.Collections.emptyMap()
|
|
|
+ : skuMapper.selectBatchIds(childSkuIds).stream()
|
|
|
+ .collect(java.util.stream.Collectors.toMap(ProductSku::getId, s -> s, (a, b) -> a));
|
|
|
+ for (ProductSkuComboItem item : all) {
|
|
|
+ Product p = productMap.get(item.getChildProductId());
|
|
|
+ if (p != null) {
|
|
|
+ item.setChildProductName(p.getName());
|
|
|
+ item.setChildProductImage(p.getCoverImage());
|
|
|
+ item.setChildProductPrice(p.getPrice());
|
|
|
+ }
|
|
|
+ ProductSku cs = item.getChildSkuId() == null ? null : childSkuMap.get(item.getChildSkuId());
|
|
|
+ if (cs != null) item.setChildSkuSpecs(cs.getSpecs());
|
|
|
+ }
|
|
|
+ java.util.Map<Long, List<ProductSkuComboItem>> grouped = all.stream()
|
|
|
+ .collect(java.util.stream.Collectors.groupingBy(ProductSkuComboItem::getSkuId));
|
|
|
+ for (ProductSku sku : skus) {
|
|
|
+ sku.setComboItems(grouped.getOrDefault(sku.getId(), java.util.Collections.emptyList()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean hasComboItems(ProductSku sku) {
|
|
|
+ return sku != null && sku.getComboItems() != null && !sku.getComboItems().isEmpty();
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<ProductSkuComboItem> listComboItems(Long skuId) {
|
|
|
+ ProductSku tmp = new ProductSku();
|
|
|
+ tmp.setId(skuId);
|
|
|
+ fillComboItems(java.util.Collections.singletonList(tmp));
|
|
|
+ return tmp.getComboItems() == null ? java.util.Collections.emptyList() : tmp.getComboItems();
|
|
|
+ }
|
|
|
+
|
|
|
+ public String buildComboSummary(List<ProductSkuComboItem> items) {
|
|
|
+ if (items == null || items.isEmpty()) return "";
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ for (ProductSkuComboItem item : items) {
|
|
|
+ if (sb.length() > 0) sb.append(";");
|
|
|
+ String name = item.getChildProductName() != null ? item.getChildProductName()
|
|
|
+ : ("商品#" + item.getChildProductId());
|
|
|
+ sb.append(name).append("×").append(item.getQuantity() == null ? 1 : item.getQuantity());
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+}
|