pd导入,excel模版

This commit is contained in:
zjf committed 2025-08-25 17:17:55 +08:00
1 parent 0776aa415f
commit fa2734ca89
5 files changed
+161 -57

No files matched your search

@@ -44,6 +44,8 @@ import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@@ -73,6 +75,8 @@ public class SmErpSpuController {
private final SmErpInventoryRecordsService smErpInventoryRecordsService;
private final SmErpTasteStockService smErpTasteStockService;
/**
* 分页查询
@@ -419,4 +423,55 @@ public class SmErpSpuController {
return R.ok();
}
/**
* 更新迁移脚本
* @return
*/
@GetMapping("/123456789")
@Transactional
public R qy() {
List<SmErpUnitEntity> list = smErpUnitService.list();
List<SmErpUnitEntity> erpUnitEntities = list.stream().filter(supermarketUnitEntity -> supermarketUnitEntity.getTasteId() == null).collect(Collectors.toList());
for (SmErpUnitEntity item:erpUnitEntities
) {
String tasteName = item.getTasteName();
if (StringUtils.isNotBlank(tasteName)){
//需要查询当前item下面有多少口味商品,然后在查询商品的当前库存/口味数量,平均赋予口味库存数量
LambdaQueryWrapper<SmErpUnitEntity> smErpUnitEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
smErpUnitEntityLambdaQueryWrapper.eq(SmErpUnitEntity::getSpuId,item.getSpuId());
List<SmErpUnitEntity> list1 = smErpUnitService.list(smErpUnitEntityLambdaQueryWrapper);
int tasteCount = list1.size();
LambdaQueryWrapper<SmErpStockEntity> smErpStockEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
smErpStockEntityLambdaQueryWrapper.eq(SmErpStockEntity::getErpSpuId,item.getSpuId());
SmErpStockEntity one = smErpStockService.getOne(smErpStockEntityLambdaQueryWrapper);
double tasteStock = one.getCurrentStock()/tasteCount;
tasteStock = BigDecimal.valueOf(tasteStock).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
SmErpTasteStockEntity smErpTasteEntity = new SmErpTasteStockEntity();
smErpTasteEntity.setStock(tasteStock);
smErpTasteEntity.setTasteName(tasteName);
//查询口味是否存在,存在就用存在的id,不存在就创建
LambdaQueryWrapper<SmErpTasteStockEntity> smErpTasteEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
smErpTasteEntityLambdaQueryWrapper.eq(SmErpTasteStockEntity::getTasteName, tasteName);
smErpTasteEntityLambdaQueryWrapper.eq(SmErpTasteStockEntity::getSpuId, item.getSpuId());
SmErpTasteStockEntity smErpTasteStockEntity = smErpTasteStockService.getOne(smErpTasteEntityLambdaQueryWrapper);
if (smErpTasteStockEntity == null) {
smErpTasteEntity.setSpuId(item.getSpuId());
smErpTasteStockService.save(smErpTasteEntity);
//不存在使用创建的id
item.setTasteId(smErpTasteEntity.getId());
smErpUnitService.updateById(item);
} else {
//存在,就更新item的tasteId
item.setTasteId(smErpTasteStockEntity.getId());
smErpUnitService.updateById(item);
}
}
}
return R.ok();
}
}
@@ -92,3 +92,4 @@ public class SmErpSpuImportPDNewDto {
// @ExcelProperty("品牌")
// private String brand; // 品牌
}
@@ -119,6 +119,32 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
@Autowired
private TaskStoreService taskStoreService;
// 兼容多种日期格式: yyyy-MM-dd, yyyy/M/d, yyyy.M.d
private static LocalDate parseFlexibleLocalDate(String text) {
if (text == null) return null;
String t = text.trim();
java.time.format.DateTimeFormatter[] formats = new java.time.format.DateTimeFormatter[] {
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"),
java.time.format.DateTimeFormatter.ofPattern("yyyy/M/d"),
java.time.format.DateTimeFormatter.ofPattern("yyyy/M/dd"),
java.time.format.DateTimeFormatter.ofPattern("yyyy/MM/d"),
java.time.format.DateTimeFormatter.ofPattern("yyyy/MM/dd"),
java.time.format.DateTimeFormatter.ofPattern("yyyy.M.d"),
java.time.format.DateTimeFormatter.ofPattern("yyyy.MM.dd")
};
for (java.time.format.DateTimeFormatter f : formats) {
try {
return LocalDate.parse(t, f);
} catch (Exception ignored) {}
}
// fallback: 尝试替换非数字分隔符为'-'
try {
String norm = t.replace('/', '-').replace('.', '-');
return LocalDate.parse(norm);
} catch (Exception ignored) {}
return null;
}
@Override
@Transactional
public R saveSpu(SmErpSpuEntity supermarketSpu) {
@@ -2162,50 +2188,32 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
Map<String, List<SmErpSpuImportPDNewDto>> spuGroupMap = smErpSpuImportPDNewDtos.stream()
.collect(Collectors.groupingBy(SmErpSpuImportPDNewDto::getProductCode));
// 计算从盘点日期到当前的零售销量,用于计算实际剩余库存
Map<Long, Double> spuSalesMap = new HashMap<>();
// 计算从最早盘点日期到当前的所有零售出库记录,供逐条过滤(包含今天)
LocalDate currentDate = LocalDate.now();
// 收集所有盘点日期,用于计算销量
Set<String> allPdDates = smErpSpuImportPDNewDtos.stream()
LocalDate minPdDate = smErpSpuImportPDNewDtos.stream()
.map(SmErpSpuImportPDNewDto::getPdDate)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toSet());
for (String pdDateStr : allPdDates) {
try {
LocalDate pdDate = LocalDate.parse(pdDateStr);
// 查询从盘点日期到当前日期的零售出库记录
LambdaQueryWrapper<SmErpInventoryRecordsEntity> retailWrapper = new LambdaQueryWrapper<>();
retailWrapper.eq(SmErpInventoryRecordsEntity::getInventoryType, "5"); // LSCK 零售出库
retailWrapper.ge(SmErpInventoryRecordsEntity::getInventoryDate, pdDate);
retailWrapper.le(SmErpInventoryRecordsEntity::getInventoryDate, currentDate);
List<SmErpInventoryRecordsEntity> retailRecords = smErpInventoryRecordsService.list(retailWrapper);
// 收集所有零售记录的ID
List<Long> retailRecordIds = retailRecords.stream()
.map(SmErpInventoryRecordsEntity::getId)
.collect(Collectors.toList());
// 查询零售出库明细
if (!retailRecordIds.isEmpty()) {
LambdaQueryWrapper<SmErpInventoryRecordsItemEntity> itemWrapper = new LambdaQueryWrapper<>();
itemWrapper.in(SmErpInventoryRecordsItemEntity::getInventoryId, retailRecordIds);
List<SmErpInventoryRecordsItemEntity> retailItems = smErpInventoryRecordsItemService.list(itemWrapper);
// 按商品ID汇总销量
for (SmErpInventoryRecordsItemEntity item : retailItems) {
Long spuId = item.getErpSpuId();
Double quantity = item.getQuantity();
spuSalesMap.merge(spuId, quantity, Double::sum);
}
}
} catch (Exception e) {
// 日期解析失败,跳过该条记录
continue;
}
.map(SmErpSpuServiceImpl::parseFlexibleLocalDate)
.filter(Objects::nonNull)
.min(LocalDate::compareTo)
.orElse(currentDate);
LambdaQueryWrapper<SmErpInventoryRecordsEntity> retailWrapperAll = new LambdaQueryWrapper<>();
retailWrapperAll.eq(SmErpInventoryRecordsEntity::getInventoryType, "5");
retailWrapperAll.ge(SmErpInventoryRecordsEntity::getInventoryDate, minPdDate);
retailWrapperAll.le(SmErpInventoryRecordsEntity::getInventoryDate, currentDate);
List<SmErpInventoryRecordsEntity> allRetailRecords = smErpInventoryRecordsService.list(retailWrapperAll);
Map<Long, LocalDate> recordIdToDate = allRetailRecords.stream()
.collect(Collectors.toMap(SmErpInventoryRecordsEntity::getId, SmErpInventoryRecordsEntity::getInventoryDate));
Map<Long, List<SmErpInventoryRecordsItemEntity>> spuToItemsMap = new HashMap<>();
if (!allRetailRecords.isEmpty()) {
List<Long> allRetailRecordIds = allRetailRecords.stream().map(SmErpInventoryRecordsEntity::getId).collect(Collectors.toList());
LambdaQueryWrapper<SmErpInventoryRecordsItemEntity> allItemsWrapper = new LambdaQueryWrapper<>();
allItemsWrapper.in(SmErpInventoryRecordsItemEntity::getInventoryId, allRetailRecordIds);
List<SmErpInventoryRecordsItemEntity> allRetailItems = smErpInventoryRecordsItemService.list(allItemsWrapper);
spuToItemsMap = allRetailItems.stream().collect(Collectors.groupingBy(SmErpInventoryRecordsItemEntity::getErpSpuId));
}
// 按商品分组处理
@@ -2217,7 +2225,8 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
SmErpSpuEntity spu = null;
List<SmErpUnitEntity> units = new ArrayList<>();
Map<String, Double> tasteStockMap = new HashMap<>(); // 口味库存映射
Double totalSpuStock = 0.0; // 商品总库存
Double totalSpuAccount = 0.0; // 账面合计
Double totalSpuReal = 0.0; // 真实合计(扣销量)
// 第一轮:处理商品主数据和包装单位
for (SmErpSpuImportPDNewDto dto : spuDtos) {
@@ -2428,17 +2437,56 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
}
}
// 6. 计算包装单位的实际库存(盘点库存 × 内装数)
Double unitActualStock = dto.getPdStock() * dto.getPackageNum();
// 7. 更新口味库存(如果有口味)
if (tasteId != null) {
// 累加同一口味的库存
tasteStockMap.merge(dto.getTaste(), unitActualStock, Double::sum);
// 6. 账面数量(盘点 × 内装)
Double accountNumber = (dto.getPdStock() == null ? 0.0 : dto.getPdStock()) *
(dto.getPackageNum() == null ? 1.0 : dto.getPackageNum());
// 7. 计算从pdDate到今天(含)的销量(按SPU)
Double salesQuantity = 0.0;
if (StringUtils.isNotBlank(dto.getPdDate())) {
try {
LocalDate pdDate = parseFlexibleLocalDate(dto.getPdDate());
if (pdDate == null) { throw new IllegalArgumentException("bad date"); }
List<SmErpInventoryRecordsItemEntity> spuItems = spuToItemsMap.getOrDefault(spu.getId(), Collections.emptyList());
for (SmErpInventoryRecordsItemEntity it : spuItems) {
LocalDate d = recordIdToDate.get(it.getInventoryId());
if (d != null && (d.isEqual(pdDate) || d.isAfter(pdDate))) {
salesQuantity += (it.getQuantity() == null ? 0.0 : it.getQuantity());
}
}
} catch (Exception ignore) {}
}
// 8. 累加到商品总库存
totalSpuStock += unitActualStock;
// 8. 真实库存 = 账面 - 销量
Double realRemainingStock = accountNumber - salesQuantity;
// 9. 累计
if (tasteId != null) {
tasteStockMap.merge(dto.getTaste(), realRemainingStock, Double::sum);
}
totalSpuAccount += accountNumber;
totalSpuReal += realRemainingStock;
// 10. 盘点明细
PDItemSaveDTO item = new PDItemSaveDTO();
item.setErpSpuId(spu.getId());
item.setUnitId(unit.getId());
item.setAccountNumber(accountNumber);
item.setRealNumber(realRemainingStock);
Double purchasePrice = dto.getPurchasePrice() != null ? dto.getPurchasePrice() : 0.0;
Double retailPrice = dto.getRetailPrice() != null ? dto.getRetailPrice() : purchasePrice;
item.setUnitPrice((int) Math.round(purchasePrice * 100));
item.setRealPrice((int) Math.round(retailPrice * 100));
Double diff = realRemainingStock - accountNumber;
if (diff > 0) { item.setProfit(diff); item.setLoss(0.0); item.setOrderType(OrderTypeEnum.RK.getType()); }
else if (diff < 0) { item.setProfit(0.0); item.setLoss(Math.abs(diff)); item.setOrderType(OrderTypeEnum.CK.getType()); }
else { item.setProfit(0.0); item.setLoss(0.0); item.setOrderType(OrderTypeEnum.No.getType()); }
item.setQuantity(Math.abs(diff));
// 备注:盘点日期与销量扣减说明
String remark = "盘点日期:" + (dto.getPdDate() == null ? "" : dto.getPdDate()) +
", 销量合计:" + BigDecimal.valueOf(salesQuantity).setScale(2, RoundingMode.HALF_UP);
item.setRemark(remark);
pdItemList.add(item);
} catch (Exception e) {
errorList.add(createErrorInfo(spuDtos.indexOf(dto) + 1, dto.getProductCode(),
@@ -2466,7 +2514,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
}
}
// 更新商品总库存
// 更新商品总库存:期初=账面合计,当前=真实合计(已扣销量)
LambdaQueryWrapper<SmErpStockEntity> existingStockWrapper = new LambdaQueryWrapper<>();
existingStockWrapper.eq(SmErpStockEntity::getErpSpuId, spu.getId());
SmErpStockEntity existingStock = smErpStockService.getOne(existingStockWrapper);
@@ -2474,16 +2522,16 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
if (existingStock != null) {
existingStock.setInventoryUpperLimit(1000); // 默认值
existingStock.setInventoryLowerLimit(10); // 默认值
existingStock.setBaseStock(totalSpuStock);
existingStock.setCurrentStock(totalSpuStock);
existingStock.setBaseStock(totalSpuAccount);
existingStock.setCurrentStock(totalSpuReal);
smErpStockService.updateById(existingStock);
} else {
SmErpStockEntity stock = new SmErpStockEntity();
stock.setErpSpuId(spu.getId());
stock.setInventoryUpperLimit(1000);
stock.setInventoryLowerLimit(10);
stock.setBaseStock(totalSpuStock);
stock.setCurrentStock(totalSpuStock);
stock.setBaseStock(totalSpuAccount);
stock.setCurrentStock(totalSpuReal);
smErpStockService.save(stock);
}