|
|
@@ -1,6 +1,7 @@
|
|
|
package org.springblade.factory.api.controller;
|
|
|
|
|
|
|
|
|
+import cn.hutool.core.collection.CollectionUtil;
|
|
|
import com.alibaba.excel.EasyExcel;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
@@ -205,10 +206,8 @@ public class SalesForecastSummaryController {
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
@PostMapping("/importForecastData/{id}")
|
|
|
- @ApiOperation(value = "导入销售预测数据(不删除原有数据,跳过重复数据)")
|
|
|
+ @ApiOperation(value = "导入销售预测数据(先删除原有数据,再保存新数据)")
|
|
|
public R<List<PcBladeSalesForecastSummary>> importForecastData(@PathVariable("id") Long id, @RequestParam("file") MultipartFile file) {
|
|
|
|
|
|
// 1. 基础参数校验
|
|
|
@@ -216,12 +215,13 @@ public class SalesForecastSummaryController {
|
|
|
return R.fail("预测ID不能为空");
|
|
|
}
|
|
|
|
|
|
+ // 2. 校验主表数据是否存在(保留原有逻辑)
|
|
|
PcBladeSalesForecastMain pcBladeDealerForecast = forecastMainService.getById(id);
|
|
|
if (pcBladeDealerForecast == null) {
|
|
|
return R.fail("预测主数据不存在");
|
|
|
}
|
|
|
|
|
|
- // 2. 文件校验
|
|
|
+ // 3. 文件校验
|
|
|
if (file.isEmpty()) {
|
|
|
return R.fail("导入文件不能为空");
|
|
|
}
|
|
|
@@ -230,14 +230,14 @@ public class SalesForecastSummaryController {
|
|
|
return R.fail("仅支持.xlsx格式的Excel文件导入");
|
|
|
}
|
|
|
|
|
|
- // 3. 从主表获取年月
|
|
|
+ // 4. 从主表获取年月
|
|
|
Integer forecastYear = pcBladeDealerForecast.getYear();
|
|
|
Integer forecastMonth = pcBladeDealerForecast.getMonth();
|
|
|
if (forecastYear == null || forecastMonth == null) {
|
|
|
return R.fail("预测主数据的年月不能为空");
|
|
|
}
|
|
|
|
|
|
- // 4. 用户信息校验
|
|
|
+ // 5. 用户信息校验
|
|
|
Long userId = AuthUtil.getUserId();
|
|
|
if (userId == null) {
|
|
|
return R.fail("用户未登录");
|
|
|
@@ -248,55 +248,34 @@ public class SalesForecastSummaryController {
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
- // ========== 核心修改1:先读取Excel数据,提取物料编码 ==========
|
|
|
+ // ========== 核心修改:导入前先删除该forecast_main_id下的所有历史数据 ==========
|
|
|
+ boolean deleteSuccess = forecastService.physicallyDeleteByForecastMainId(id);
|
|
|
+ if (!deleteSuccess) {
|
|
|
+ // 这里可以根据业务选择:是抛出异常还是继续(建议继续,因为可能原本就没有数据)
|
|
|
+ // return R.fail("删除历史数据失败");
|
|
|
+ }
|
|
|
+
|
|
|
// 6. 同步读取Excel数据
|
|
|
List<SalesForecastImportDTO> dtoList = EasyExcel.read(file.getInputStream())
|
|
|
.head(SalesForecastImportDTO.class)
|
|
|
.sheet()
|
|
|
.doReadSync();
|
|
|
|
|
|
- // ========== 核心修改2:查询数据库中已存在的重复数据 ==========
|
|
|
- // 7. 提取Excel中的物料编码(去重)
|
|
|
- Set<String> itemCodeSet = new HashSet<>();
|
|
|
- for (SalesForecastImportDTO dto : dtoList) {
|
|
|
- if (dto.getItemCode() != null && !dto.getItemCode().trim().isEmpty()) {
|
|
|
- itemCodeSet.add(dto.getItemCode().trim());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 8. 查询数据库中已存在的组合数据(年份+月份+客户ID+物料编码)
|
|
|
- LambdaQueryWrapper<PcBladeSalesForecastSummary> existWrapper = new LambdaQueryWrapper<>();
|
|
|
- existWrapper.eq(PcBladeSalesForecastSummary::getYear, forecastYear)
|
|
|
- .eq(PcBladeSalesForecastSummary::getMonth, forecastMonth)
|
|
|
- .eq(PcBladeSalesForecastSummary::getCustomerId, user.getData().getCustomerId())
|
|
|
- .eq(PcBladeSalesForecastSummary::getForecastMainId, id)
|
|
|
- .in(!itemCodeSet.isEmpty(), PcBladeSalesForecastSummary::getItemCode, itemCodeSet);
|
|
|
- List<PcBladeSalesForecastSummary> existList = forecastService.list(existWrapper);
|
|
|
-
|
|
|
- // 9. 构建已存在的唯一Key集合(年份+月份+客户ID+物料编码)
|
|
|
- Set<String> existUniqueKeySet = new HashSet<>();
|
|
|
- for (PcBladeSalesForecastSummary exist : existList) {
|
|
|
- String uniqueKey = buildUniqueKey(exist.getYear(), exist.getMonth(), exist.getCustomerId(), exist.getItemCode());
|
|
|
- existUniqueKeySet.add(uniqueKey);
|
|
|
- }
|
|
|
-
|
|
|
- // ========== 原有逻辑保留,新增去重校验 ==========
|
|
|
- // 5. 定义列表存储导入数据
|
|
|
+ // 7. 定义列表存储导入数据
|
|
|
List<PcBladeSalesForecastSummary> saveList = new ArrayList<>();
|
|
|
// 用于记录Excel内重复的Key,避免同一Excel内重复
|
|
|
Set<String> excelUniqueKeySet = new HashSet<>();
|
|
|
|
|
|
- // 10. 提前查询经销商信息(避免循环内重复查询)
|
|
|
+ // 8. 提前查询经销商信息(避免循环内重复查询)
|
|
|
QueryWrapper<ViewCustomerSel> customerQueryWrapper = new QueryWrapper<>();
|
|
|
customerQueryWrapper.eq("customer_id", user.getData().getCustomerId());
|
|
|
List<ViewCustomerSel> customerList = zcrmViewCustomerSelService.list(customerQueryWrapper);
|
|
|
- if (customerList.isEmpty()) {
|
|
|
+ if (CollectionUtil.isEmpty(customerList)) {
|
|
|
return R.fail("经销商数据不存在");
|
|
|
}
|
|
|
ViewCustomerSel customerInfo = customerList.get(0);
|
|
|
|
|
|
- // 11. 遍历解析的数据,转换为入库实体(添加重复校验)
|
|
|
- int skipCount = 0; // 记录跳过的重复数据条数
|
|
|
+ // 9. 遍历解析的数据,转换为入库实体
|
|
|
for (SalesForecastImportDTO dto : dtoList) {
|
|
|
// 跳过空行
|
|
|
if (dto.getItemCode() == null && dto.getItemName() == null && dto.getForecastQuantity() == null) {
|
|
|
@@ -305,18 +284,11 @@ public class SalesForecastSummaryController {
|
|
|
|
|
|
// 处理物料编码
|
|
|
String itemCode = dto.getItemCode() == null ? "" : dto.getItemCode().trim();
|
|
|
- // 生成唯一Key(与数据库唯一索引字段对应)
|
|
|
+ // 生成唯一Key(用于Excel内去重)
|
|
|
String uniqueKey = buildUniqueKey(forecastYear, forecastMonth, user.getData().getCustomerId(), itemCode);
|
|
|
|
|
|
- // ========== 核心修改3:跳过重复数据 ==========
|
|
|
- // 跳过数据库中已存在的记录
|
|
|
- if (existUniqueKeySet.contains(uniqueKey)) {
|
|
|
- skipCount++;
|
|
|
- continue;
|
|
|
- }
|
|
|
// 跳过Excel内重复的记录
|
|
|
if (excelUniqueKeySet.contains(uniqueKey)) {
|
|
|
- skipCount++;
|
|
|
continue;
|
|
|
}
|
|
|
excelUniqueKeySet.add(uniqueKey);
|
|
|
@@ -342,7 +314,7 @@ public class SalesForecastSummaryController {
|
|
|
summary.setForecastQuantity(dto.getForecastQuantity() == null ? BigDecimal.ZERO : dto.getForecastQuantity());
|
|
|
|
|
|
// 补充物料ID/品牌ID
|
|
|
- if (StringUtils.isNotBlank(itemCode)) {
|
|
|
+ if (org.springframework.util.StringUtils.hasText(itemCode)) {
|
|
|
ViewWhqohSel stock = zcrmViewWhqohSelService.getOne(
|
|
|
new LambdaQueryWrapper<ViewWhqohSel>().eq(ViewWhqohSel::getItemCode, itemCode)
|
|
|
);
|
|
|
@@ -358,9 +330,9 @@ public class SalesForecastSummaryController {
|
|
|
saveList.add(summary);
|
|
|
}
|
|
|
|
|
|
- // 12. 批量保存数据(仅当有有效数据时保存)
|
|
|
+ // 10. 批量保存数据(仅当有有效数据时保存)
|
|
|
int importCount = 0;
|
|
|
- if (!saveList.isEmpty()) {
|
|
|
+ if (!CollectionUtil.isEmpty(saveList)) {
|
|
|
boolean saveSuccess = forecastService.saveBatch(saveList);
|
|
|
if (!saveSuccess) {
|
|
|
return R.fail("数据保存失败");
|
|
|
@@ -368,14 +340,14 @@ public class SalesForecastSummaryController {
|
|
|
importCount = saveList.size();
|
|
|
}
|
|
|
|
|
|
- // 13. 查询该forecast_main_id下的所有汇总明细数据并返回
|
|
|
+ // 11. 查询该forecast_main_id下的所有汇总明细数据并返回
|
|
|
LambdaQueryWrapper<PcBladeSalesForecastSummary> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
queryWrapper.eq(PcBladeSalesForecastSummary::getForecastMainId, id)
|
|
|
.orderByAsc(PcBladeSalesForecastSummary::getItemCode);
|
|
|
|
|
|
List<PcBladeSalesForecastSummary> lists = forecastService.list(queryWrapper);
|
|
|
|
|
|
- // 返回导入结果(包含导入数量和跳过数量)
|
|
|
+ // 返回导入结果(包含导入数量)
|
|
|
return R.data(lists);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
@@ -383,6 +355,7 @@ public class SalesForecastSummaryController {
|
|
|
return R.fail("导入失败:" + e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
/**
|
|
|
* 构建唯一Key(与数据库唯一索引uk_year_month_customer_item对应)
|
|
|
* @param year 年份
|