add GaoProductStockBatchRequest
This commit is contained in:
@@ -101,8 +101,8 @@ public class GaoPackageConfigController {
|
|||||||
if (skuIdList.isEmpty()) {
|
if (skuIdList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Map<String, GaoProductSku> skuMap = skuIdList.stream()
|
Map<String, GaoProductSku> skuMap = skuService.listByIdList(skuIdList).stream()
|
||||||
.collect(java.util.stream.Collectors.toMap(item -> item, skuService::detail));
|
.collect(java.util.stream.Collectors.toMap(GaoProductSku::getId, item -> item));
|
||||||
for (GaoPackageConfig config : configList) {
|
for (GaoPackageConfig config : configList) {
|
||||||
for (GaoPackageConfigItem item : config.getItemList()) {
|
for (GaoPackageConfigItem item : config.getItemList()) {
|
||||||
item.setSku(skuMap.get(item.getSkuId()));
|
item.setSku(skuMap.get(item.getSkuId()));
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.imyeyu.api.modules.gao.entity.GaoProductStockRecord;
|
|||||||
import com.imyeyu.api.modules.gao.service.GaoProductStockService;
|
import com.imyeyu.api.modules.gao.service.GaoProductStockService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoProductStockRecordService;
|
import com.imyeyu.api.modules.gao.service.GaoProductStockRecordService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoStoreScopeService;
|
import com.imyeyu.api.modules.gao.service.GaoStoreScopeService;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoProductStockBatchRequest;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoProductStockChangeRequest;
|
import com.imyeyu.api.modules.gao.vo.GaoProductStockChangeRequest;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoProductStockManualRevokeRequest;
|
import com.imyeyu.api.modules.gao.vo.GaoProductStockManualRevokeRequest;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoProductStockPage;
|
import com.imyeyu.api.modules.gao.vo.GaoProductStockPage;
|
||||||
@@ -23,6 +24,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/// GAO 产品库存接口
|
/// GAO 产品库存接口
|
||||||
///
|
///
|
||||||
/// @author Codex
|
/// @author Codex
|
||||||
@@ -64,6 +67,16 @@ public class GaoProductStockController {
|
|||||||
return stockService.detail(storeScopeService.resolveStoreId(storeId), skuId);
|
return stockService.detail(storeScopeService.resolveStoreId(storeId), skuId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.PRODUCT_STOCK_READ)
|
||||||
|
@PostMapping("/batch-detail")
|
||||||
|
public List<GaoProductStock> batchDetail(@RequestBody GaoProductStockBatchRequest request) {
|
||||||
|
TimiException.required(request, "not found stock batch request");
|
||||||
|
request.setStoreId(storeScopeService.resolveStoreId(request.getStoreId()));
|
||||||
|
return stockService.batchDetail(request.getStoreId(), request.getSkuIdList());
|
||||||
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.PRODUCT_STOCK_CREATE)
|
@RequireGaoPermission(GaoPermissionCode.PRODUCT_STOCK_CREATE)
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ public interface GaoProductStockMapper extends BaseMapper<GaoProductStock, Strin
|
|||||||
/// 按门店和产品查询库存余额
|
/// 按门店和产品查询库存余额
|
||||||
GaoProductStock selectByStoreIdAndSkuId(@Param("storeId") String storeId, @Param("skuId") String skuId);
|
GaoProductStock selectByStoreIdAndSkuId(@Param("storeId") String storeId, @Param("skuId") String skuId);
|
||||||
|
|
||||||
|
/// 按门店和 SKU 批量查询库存余额
|
||||||
|
List<GaoProductStock> selectByStoreIdAndSkuIdList(@Param("storeId") String storeId, @Param("skuIdList") List<String> skuIdList);
|
||||||
|
|
||||||
/// 条件更新库存余额
|
/// 条件更新库存余额
|
||||||
int updateQuantity(@Param("id") String id, @Param("onHandDelta") java.math.BigDecimal onHandDelta, @Param("reservedDelta") java.math.BigDecimal reservedDelta, @Param("updatedBy") String updatedBy);
|
int updateQuantity(@Param("id") String id, @Param("onHandDelta") java.math.BigDecimal onHandDelta, @Param("reservedDelta") java.math.BigDecimal reservedDelta, @Param("updatedBy") String updatedBy);
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ public interface GaoProductStockService {
|
|||||||
/// 查询库存余额详情
|
/// 查询库存余额详情
|
||||||
GaoProductStock detail(String storeId, String skuId);
|
GaoProductStock detail(String storeId, String skuId);
|
||||||
|
|
||||||
|
/// 批量查询指定 SKU 库存余额
|
||||||
|
List<GaoProductStock> batchDetail(String storeId, List<String> skuIdList);
|
||||||
|
|
||||||
/// 期初入库
|
/// 期初入库
|
||||||
GaoProductStock initialIn(GaoProductStockChangeRequest request);
|
GaoProductStock initialIn(GaoProductStockChangeRequest request);
|
||||||
|
|
||||||
|
|||||||
+19
@@ -8,7 +8,9 @@ import com.imyeyu.api.modules.gao.entity.GaoProductCategory;
|
|||||||
import com.imyeyu.api.modules.gao.entity.GaoProductSpec;
|
import com.imyeyu.api.modules.gao.entity.GaoProductSpec;
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoProductSpecValue;
|
import com.imyeyu.api.modules.gao.entity.GaoProductSpecValue;
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoProductSku;
|
import com.imyeyu.api.modules.gao.entity.GaoProductSku;
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoProductStock;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoProductMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoProductMapper;
|
||||||
|
import com.imyeyu.api.modules.gao.mapper.GaoProductStockMapper;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoProductCategoryService;
|
import com.imyeyu.api.modules.gao.service.GaoProductCategoryService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoProductService;
|
import com.imyeyu.api.modules.gao.service.GaoProductService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoProductSkuService;
|
import com.imyeyu.api.modules.gao.service.GaoProductSkuService;
|
||||||
@@ -48,6 +50,7 @@ import java.util.stream.Collectors;
|
|||||||
public class GaoProductServiceImplement extends AbstractEntityService<GaoProduct, String> implements GaoProductService {
|
public class GaoProductServiceImplement extends AbstractEntityService<GaoProduct, String> implements GaoProductService {
|
||||||
|
|
||||||
private final GaoProductMapper mapper;
|
private final GaoProductMapper mapper;
|
||||||
|
private final GaoProductStockMapper stockMapper;
|
||||||
private final AttachmentService attachmentService;
|
private final AttachmentService attachmentService;
|
||||||
private final ObjectProvider<GaoProductCategoryService> categoryServiceProvider;
|
private final ObjectProvider<GaoProductCategoryService> categoryServiceProvider;
|
||||||
private final ObjectProvider<GaoProductSkuService> skuServiceProvider;
|
private final ObjectProvider<GaoProductSkuService> skuServiceProvider;
|
||||||
@@ -120,6 +123,9 @@ public class GaoProductServiceImplement extends AbstractEntityService<GaoProduct
|
|||||||
TimiException.required(request.getId(), "not found product.id");
|
TimiException.required(request.getId(), "not found product.id");
|
||||||
GaoProduct product = get(request.getId());
|
GaoProduct product = get(request.getId());
|
||||||
TimiException.required(product, "not found product");
|
TimiException.required(product, "not found product");
|
||||||
|
if (request.getProductType() == GaoProduct.ProductType.SERVICE && product.getProductType() != GaoProduct.ProductType.SERVICE) {
|
||||||
|
verifyNoReservedStock(product);
|
||||||
|
}
|
||||||
product.setCategoryId(request.getCategoryId());
|
product.setCategoryId(request.getCategoryId());
|
||||||
product.setCode(TimiJava.defaultIfNull(request.getCode(), product.getCode()));
|
product.setCode(TimiJava.defaultIfNull(request.getCode(), product.getCode()));
|
||||||
product.setName(TimiJava.defaultIfNull(request.getName(), product.getName()));
|
product.setName(TimiJava.defaultIfNull(request.getName(), product.getName()));
|
||||||
@@ -139,6 +145,19 @@ public class GaoProductServiceImplement extends AbstractEntityService<GaoProduct
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void verifyNoReservedStock(GaoProduct product) {
|
||||||
|
List<String> skuIdList = skuServiceProvider.getObject().listByProductId(product.getId()).stream()
|
||||||
|
.map(GaoProductSku::getId)
|
||||||
|
.filter(id -> id != null && !id.isBlank())
|
||||||
|
.toList();
|
||||||
|
if (skuIdList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean hasReservedStock = stockMapper.selectByStoreIdAndSkuIdList(product.getStoreId(), skuIdList).stream()
|
||||||
|
.anyMatch(stock -> stock.getReservedQuantity() != null && 0 < stock.getReservedQuantity().signum());
|
||||||
|
TimiException.requiredTrue(!hasReservedStock, "当前产品存在预占库存,不能切换为服务产品,请先完成或取消相关订单");
|
||||||
|
}
|
||||||
|
|
||||||
@OperationAudit(AuditOperation.GAO_PRODUCT_DISABLE)
|
@OperationAudit(AuditOperation.GAO_PRODUCT_DISABLE)
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+34
-2
@@ -68,7 +68,8 @@ public class GaoProductStockServiceImplement implements GaoProductStockService {
|
|||||||
List<GaoProductStock> list = stockMapper.selectByQuery(page);
|
List<GaoProductStock> list = stockMapper.selectByQuery(page);
|
||||||
Map<String, Attachment> photoMap = attachmentService.mapFirstImageByIdList(
|
Map<String, Attachment> photoMap = attachmentService.mapFirstImageByIdList(
|
||||||
Attachment.BizType.GAO_PRODUCT_SKU,
|
Attachment.BizType.GAO_PRODUCT_SKU,
|
||||||
list.stream().map(GaoProductStock::getSkuId).filter(id -> id != null && !id.isBlank()).toList()
|
list.stream().map(GaoProductStock::getSkuId).filter(id -> id != null && !id.isBlank()).toList(),
|
||||||
|
"PHOTO"
|
||||||
);
|
);
|
||||||
for (GaoProductStock stock : list) {
|
for (GaoProductStock stock : list) {
|
||||||
fillBalance(stock);
|
fillBalance(stock);
|
||||||
@@ -86,7 +87,17 @@ public class GaoProductStockServiceImplement implements GaoProductStockService {
|
|||||||
TimiException.required(page, "not found stock product page");
|
TimiException.required(page, "not found stock product page");
|
||||||
PageResult<GaoProductStockProductView> result = new PageResult<>();
|
PageResult<GaoProductStockProductView> result = new PageResult<>();
|
||||||
result.setTotal(stockMapper.countProductByQuery(page));
|
result.setTotal(stockMapper.countProductByQuery(page));
|
||||||
result.setList(stockMapper.selectProductByQuery(page));
|
List<GaoProductStockProductView> list = stockMapper.selectProductByQuery(page);
|
||||||
|
Map<String, Attachment> photoMap = attachmentService.mapFirstImageByIdList(
|
||||||
|
Attachment.BizType.GAO_PRODUCT,
|
||||||
|
list.stream().map(GaoProductStockProductView::getProductId).filter(id -> id != null && !id.isBlank()).toList(),
|
||||||
|
"PHOTO"
|
||||||
|
);
|
||||||
|
for (GaoProductStockProductView product : list) {
|
||||||
|
Attachment photo = photoMap.get(product.getProductId());
|
||||||
|
product.setAttachmentList(photo == null ? List.of() : List.of(photo));
|
||||||
|
}
|
||||||
|
result.setList(list);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +122,27 @@ public class GaoProductStockServiceImplement implements GaoProductStockService {
|
|||||||
return stock;
|
return stock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GaoProductStock> batchDetail(String storeId, List<String> skuIdList) {
|
||||||
|
TimiException.required(storeId, "not found storeId");
|
||||||
|
storeScopeService.checkStoreId(storeId);
|
||||||
|
if (skuIdList == null || skuIdList.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
List<String> normalizedSkuIdList = skuIdList.stream()
|
||||||
|
.filter(value -> value != null && !value.isBlank())
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
if (normalizedSkuIdList.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
List<GaoProductStock> result = stockMapper.selectByStoreIdAndSkuIdList(storeId, normalizedSkuIdList);
|
||||||
|
for (GaoProductStock stock : result) {
|
||||||
|
fillBalance(stock);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@OperationAudit(AuditOperation.GAO_PRODUCT_STOCK_INITIAL_IN)
|
@OperationAudit(AuditOperation.GAO_PRODUCT_STOCK_INITIAL_IN)
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/// GAO 产品库存批量查询请求
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-09-16
|
||||||
|
@Data
|
||||||
|
public class GaoProductStockBatchRequest {
|
||||||
|
|
||||||
|
/// 门店 ID
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
|
/// SKU ID 列表
|
||||||
|
private List<String> skuIdList;
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.imyeyu.api.modules.gao.vo;
|
package com.imyeyu.api.modules.gao.vo;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoProduct;
|
import com.imyeyu.api.modules.gao.entity.GaoProduct;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/// 产品库存第一层汇总视图
|
/// 产品库存第一层汇总视图
|
||||||
///
|
///
|
||||||
@@ -21,6 +23,9 @@ public class GaoProductStockProductView {
|
|||||||
/// 产品名称
|
/// 产品名称
|
||||||
private String productName;
|
private String productName;
|
||||||
|
|
||||||
|
/// 产品图片
|
||||||
|
private List<Attachment> attachmentList;
|
||||||
|
|
||||||
/// 产品类型
|
/// 产品类型
|
||||||
private GaoProduct.ProductType productType;
|
private GaoProduct.ProductType productType;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,25 @@
|
|||||||
SELECT * FROM `gao_product_stock`
|
SELECT * FROM `gao_product_stock`
|
||||||
WHERE `store_id` = #{storeId} AND `sku_id` = #{skuId}
|
WHERE `store_id` = #{storeId} AND `sku_id` = #{skuId}
|
||||||
</select>
|
</select>
|
||||||
|
<select id="selectByStoreIdAndSkuIdList" resultType="com.imyeyu.api.modules.gao.entity.GaoProductStock">
|
||||||
|
SELECT s.`id`,
|
||||||
|
k.`store_id`,
|
||||||
|
k.`id` AS `sku_id`,
|
||||||
|
COALESCE(s.`on_hand_quantity`, 0) AS `on_hand_quantity`,
|
||||||
|
COALESCE(s.`reserved_quantity`, 0) AS `reserved_quantity`,
|
||||||
|
s.`updated_by`,
|
||||||
|
s.`created_at`,
|
||||||
|
s.`updated_at`
|
||||||
|
FROM `gao_product_sku` k
|
||||||
|
JOIN `gao_product` p ON p.`id` = k.`product_id`
|
||||||
|
LEFT JOIN `gao_product_stock` s ON s.`sku_id` = k.`id` AND s.`store_id` = #{storeId}
|
||||||
|
WHERE k.`store_id` = #{storeId}
|
||||||
|
AND p.`deleted_at` IS NULL AND k.`deleted_at` IS NULL
|
||||||
|
AND k.`id` IN
|
||||||
|
<foreach collection="skuIdList" item="skuId" open="(" separator="," close=")">
|
||||||
|
#{skuId}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
<select id="countByQuery" resultType="long">
|
<select id="countByQuery" resultType="long">
|
||||||
SELECT COUNT(1)
|
SELECT COUNT(1)
|
||||||
FROM `gao_product_sku` k
|
FROM `gao_product_sku` k
|
||||||
|
|||||||
Reference in New Issue
Block a user