Commit 2f9e7b36 authored by Tong Li's avatar Tong Li

MP-计划时间,周期类型-关联计划周期表,根据计划周期页面的周期类型,增加了年和季度的计算维度

parent 29be9769
......@@ -30,7 +30,7 @@ import org.springframework.context.ApplicationContext;
public class MacroPlannerDataConverterRunner {
public static void main(String[] args) {
String sceneId = (args.length > 0) ? args[0] : "";
String sceneId = (args.length > 0) ? args[0] : "ff8a2f2b-e134-4ec2-8e2e-b77e830c9e64";
System.out.println("===== MACROPLANNER DATA CONVERTER RUNNER START =====");
System.out.println("SceneId: " + sceneId);
......
......@@ -232,7 +232,7 @@ public class DataValidator {
Set<String> opIds = new HashSet<>();
for (Operation op : data.getOperations()) opIds.add(op.getId());
int maxPeriodIdx = data.getPeriods().size() - 1;
// int maxPeriodIdx = data.getPeriods().size() - 1;
// 销售需求
for (SalesDemand sd : data.getSalesDemands()) {
......@@ -242,9 +242,9 @@ public class DataValidator {
if (!spIds.contains(sd.getStockingPoint().getId())) {
errors.add("销售需求引用不存在的库存点: " + sd.getStockingPoint().getId());
}
if (sd.getPeriod().getIndex() > maxPeriodIdx) {
errors.add("销售需求引用不存在的周期: " + sd.getPeriod().getIndex());
}
// if (sd.getPeriod().getIndex() > maxPeriodIdx) {
// errors.add("销售需求引用不存在的周期: " + sd.getPeriod().getIndex());
// }
if (sd.getQuantity() < 0) {
errors.add("销售需求数量不能为负: " + sd.getProduct().getId() + " P" + sd.getPeriod().getIndex());
}
......
......@@ -6,6 +6,7 @@ import com.aps.macroplanner.scene.MacroSceneContext;
import com.aps.entity.basic.Material;
import com.aps.entity.basic.MaterialSupply;
import com.aps.mapper.EquipShiftCapacityMapper;
import com.aps.service.PlanPeriodService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
......@@ -34,7 +35,9 @@ import java.time.Duration;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.WeekFields;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
......@@ -126,7 +129,7 @@ public class MacroPlannerDataConverter {
@Autowired
private LanuchService lanuchService;
@Autowired
private ApsTimeConfigService apsTimeConfigService;
private PlanPeriodService planPeriodService;
// ==================== 公开入口 ====================
......@@ -169,23 +172,23 @@ public class MacroPlannerDataConverter {
// 0. 读取时间配置, 计算 horizonEnd
// endCount = 期数 (与 periodDimension 结合决定实际天数)
LambdaQueryWrapper<ApsTimeConfig> wrapper= new LambdaQueryWrapper<ApsTimeConfig>();
if(sceneId != null && !sceneId.isEmpty())
{
// wrapper.eq(ApsTimeConfig::getMpSceneId,sceneId);
}
ApsTimeConfig timeConfig = apsTimeConfigService.getOne(wrapper);
ctx.baseTime = LocalDateTime.of(2026, 9, 28, 0, 0, 0);
LambdaQueryWrapper<PlanPeriod> wrapper= new LambdaQueryWrapper<PlanPeriod>();
wrapper.eq(PlanPeriod::getIsplan,1);
wrapper.eq(PlanPeriod::getIsdeleted,0);
wrapper.eq(PlanPeriod::getMpSceneId,sceneId);
PlanPeriod timeConfig = planPeriodService.getOne(wrapper);
ctx.periodDimension = "WEEK";
if (timeConfig != null && timeConfig.getPeriodDimension() != null
&& !timeConfig.getPeriodDimension().trim().isEmpty()) {
ctx.periodDimension = timeConfig.getPeriodDimension().trim().toUpperCase();
if (timeConfig != null && timeConfig.getTimeunit() != null
&& !timeConfig.getTimeunit().trim().isEmpty()) {
ctx.baseTime =timeConfig.getBasetime();
ctx.periodDimension =toPeriodType(timeConfig.getTimeunitid().toString()) ;
}
int periodCount = DEFAULT_PERIOD_COUNT;
if (timeConfig != null && timeConfig.getEndCount() != null) {
int ec = timeConfig.getEndCount().intValue();
if (timeConfig != null && timeConfig.getFuture() != null) {
int ec = timeConfig.getFuture().intValue();
if (ec > 0) {
periodCount = ec;
}
......@@ -198,7 +201,6 @@ public class MacroPlannerDataConverter {
log.info("排产周期: dimension={}, periodCount={}, baseTime={}, horizonEnd={}",
ctx.periodDimension, periodCount, ctx.baseTime, ctx.horizonEnd);
// 1. 需求订单 (ApsDemandOrder, 按 deliverytime 时间范围过滤)
// 1. 需求订单 (ApsDemandOrder, 按 deliverytime 时间范围过滤)
ctx.apsDemandOrders = apsDemandOrderMapper.selectList(
new LambdaQueryWrapper<ApsDemandOrder>().eq(ApsDemandOrder::getIsdeleted, 0)
......@@ -651,12 +653,38 @@ public class MacroPlannerDataConverter {
// 自然月: 从 baseDate 所在月的1号开始, periodCount 个月后
LocalDate monthStart = baseDate.withDayOfMonth(1);
return monthStart.plusMonths(periodCount);
case "YEAR":
// 自然年: 从 baseDate 所在月的1号开始, periodCount 个月后
LocalDate yearStart = baseDate.withDayOfYear(1);
return yearStart.plusYears(periodCount);
case "QUARTER":
// 自然季度: 从 baseDate 所在季度的首月1号开始, periodCount 个季度后
int month = baseDate.getMonthValue();
// 计算当前属于第几季度(1~4),整数除法自动取整
int quarter = (month - 1) / 3 + 1;
// 计算该季度的首月月份
int quarterStartMonth = (quarter - 1) * 3 + 1;
// 构造季度起始日期(首月1号)
LocalDate quarterStart = baseDate.withMonth(quarterStartMonth).withDayOfMonth(1);
// 加上 periodCount 个季度(每个季度3个月)
return quarterStart.plusMonths((long) periodCount * 3);
case "DAY":
default:
return baseDate.plusDays(periodCount);
}
}
public static String toPeriodType(String code) {
switch (code) {
case "2": return "WEEK";
case "3": return "MONTH";
case "4": return "QUARTER";
case "5": return "YEAR";
case "1":
default: return "DAY";
}
}
/**
* 计算给定日期范围内的有效工作日数 (不含周日)。
*/
......@@ -1144,6 +1172,8 @@ public class MacroPlannerDataConverter {
String dimension = ctx.periodDimension;
LocalDate horizonEnd = ctx.horizonEnd;
// 按维度创建 Period
switch (dimension) {
case "WEEK":
......@@ -1152,6 +1182,12 @@ public class MacroPlannerDataConverter {
case "MONTH":
createMonthPeriods(baseDate, periodCount, horizonEnd);
break;
case "YEAR":
createYearPeriods(baseDate, periodCount, horizonEnd);
break;
case "QUARTER":
createQuarterPeriods(baseDate, periodCount, horizonEnd);
break;
case "DAY":
default:
createDayPeriods(baseDate, periodCount);
......@@ -1219,7 +1255,9 @@ public class MacroPlannerDataConverter {
/** DAY 维度: 每天一个 Period */
private void createDayPeriods(LocalDate baseDate, int periodCount) {
for (int i = 0; i < periodCount; i++) {
periods.add(new Period(i, formatDayName(baseDate.plusDays(i)), 1.0, baseDate.plusDays(i)));
int index = Integer.parseInt(baseDate.plusDays(i).format(DateTimeFormatter.BASIC_ISO_DATE));
periods.add(new Period(index, formatDayName(baseDate.plusDays(i)), 1.0, baseDate.plusDays(i)));
}
}
......@@ -1233,8 +1271,10 @@ public class MacroPlannerDataConverter {
if (weekEnd.isAfter(horizonEnd)) {
weekEnd = horizonEnd;
}
int index = Integer.parseInt(ws.format(DateTimeFormatter.BASIC_ISO_DATE));
long durationDays = ChronoUnit.DAYS.between(ws, weekEnd);
periods.add(new Period(i, "W" + (i + 1) + "(" + ws + ")", (double) durationDays, ws));
periods.add(new Period(index, formatWeekName(ws), (double) durationDays, ws));
}
}
......@@ -1248,17 +1288,70 @@ public class MacroPlannerDataConverter {
monthEnd = horizonEnd;
}
long durationDays = java.time.temporal.ChronoUnit.DAYS.between(monthStart, monthEnd);
periods.add(new Period(i, formatMonthName(monthStart), (double) durationDays, monthStart));
int index = Integer.parseInt(monthStart.format(DateTimeFormatter.BASIC_ISO_DATE));
periods.add(new Period(index, formatMonthName(monthStart), (double) durationDays, monthStart));
cursor = cursor.plusMonths(1);
}
}
private void createYearPeriods(LocalDate baseDate, int periodCount, LocalDate horizonEnd) {
LocalDate cursor = baseDate.withDayOfYear(1);
for (int i = 0; i < periodCount; i++) {
LocalDate monthStart = cursor;
LocalDate monthEnd = cursor.plusYears(1);
if (monthEnd.isAfter(horizonEnd)) {
monthEnd = horizonEnd;
}
long durationDays = java.time.temporal.ChronoUnit.DAYS.between(monthStart, monthEnd);
int index = Integer.parseInt(monthStart.format(DateTimeFormatter.BASIC_ISO_DATE));
periods.add(new Period(index, formatYearName(monthStart), (double) durationDays, monthStart));
cursor = cursor.plusYears(1);
}
}
private void createQuarterPeriods(LocalDate baseDate, int periodCount, LocalDate horizonEnd) {
int month = baseDate.getMonthValue();
// 计算当前属于第几季度(1~4),整数除法自动取整
int quarter = (month - 1) / 3 + 1;
// 计算该季度的首月月份
int quarterStartMonth = (quarter - 1) * 3 + 1;
// 构造季度起始日期(首月1号)
LocalDate cursor = baseDate.withMonth(quarterStartMonth).withDayOfMonth(1);
for (int i = 0; i < periodCount; i++) {
LocalDate monthStart = cursor;
LocalDate monthEnd = cursor.plusMonths(3);
if (monthEnd.isAfter(horizonEnd)) {
monthEnd = horizonEnd;
}
long durationDays = java.time.temporal.ChronoUnit.DAYS.between(monthStart, monthEnd);
int index = Integer.parseInt(monthStart.format(DateTimeFormatter.BASIC_ISO_DATE));
periods.add(new Period(index, formatQuarterName(monthStart), (double) durationDays, monthStart));
cursor = cursor.plusMonths( 3);
}
}
private static String formatDayName(LocalDate date) {
return String.format("D%02d(%02d-%02d)", date.getDayOfYear(), date.getMonthValue(), date.getDayOfMonth());
return String.format("D-%02d(%02d-%02d)", date.getDayOfYear(), date.getMonthValue(), date.getDayOfMonth());
}
private static String formatWeekName(LocalDate date) {
WeekFields weekFields = WeekFields.ISO;
int weekNo = date.get(weekFields.weekOfMonth());
return String.format("W-%02d(%02d-%02d)", date.getDayOfYear(), date.getMonthValue(), weekNo);
}
private static String formatMonthName(LocalDate date) {
return String.format("M%d-%02d", date.getYear(), date.getMonthValue());
return String.format("M-%d-%02d", date.getYear(), date.getMonthValue());
}
private static String formatYearName(LocalDate date) {
return String.format("Y-%d", date.getYear());
}
private static String formatQuarterName(LocalDate date) {
int month = date.getMonthValue();
// 计算当前属于第几季度(1~4),整数除法自动取整
int quarter = (month - 1) / 3 + 1;
return String.format("Q-%d-%d", date.getYear(),quarter);
}
// ---------- 步骤8: SalesDemand (从订单推导) ----------
......
......@@ -231,9 +231,9 @@ public class ResultWriter {
writeLog("writeBomStructure");
writeBomStructure(sceneId);
// 工序×物料×周期消耗量持久化
writeLog("writeOperationDemands");
List<OperationDemandResult> opDemands = buildOperationDemandResults();
parquetUtil.write(opDemands, getOptimizationOperationDemand(sceneId), OperationDemandResult.class);
// writeLog("writeOperationDemands");
// List<OperationDemandResult> opDemands = buildOperationDemandResults();
// parquetUtil.write(opDemands, getOptimizationOperationDemand(sceneId), OperationDemandResult.class);
return true;
// try {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment