Commit d1745f27 authored by Tong Li's avatar Tong Li

MP

parent ea3cc142
...@@ -33,6 +33,8 @@ public class Material { ...@@ -33,6 +33,8 @@ public class Material {
*/ */
private double CurrentStock; private double CurrentStock;
private Long categoryId=1l;
/** /**
* 库存详情 * 库存详情
*/ */
......
...@@ -4,6 +4,8 @@ import com.aps.ApsApplication; ...@@ -4,6 +4,8 @@ import com.aps.ApsApplication;
import com.aps.macroplanner.data.DataValidator; import com.aps.macroplanner.data.DataValidator;
import com.aps.macroplanner.data.MacroPlannerDataConverter; import com.aps.macroplanner.data.MacroPlannerDataConverter;
import com.aps.macroplanner.data.TestDataBuilder; import com.aps.macroplanner.data.TestDataBuilder;
import com.aps.macroplanner.output.ResultWriter;
import com.aps.macroplanner.output.dto.OptimizationResult;
import com.google.ortools.Loader; import com.google.ortools.Loader;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
...@@ -77,6 +79,10 @@ public class MacroPlannerDataConverterRunner { ...@@ -77,6 +79,10 @@ public class MacroPlannerDataConverterRunner {
optimizer.buildModel(); optimizer.buildModel();
optimizer.solve(); optimizer.solve();
ResultWriter writer = new ResultWriter(optimizer.getModel(), optimizer.getData(), 1);
OptimizationResult result = writer.buildResult("Default");
boolean jsonPath = writer.saveResultToFile("Default", result);
System.out.println("===== MACROPLANNER DATA CONVERTER RUNNER END ====="); System.out.println("===== MACROPLANNER DATA CONVERTER RUNNER END =====");
} finally { } finally {
SpringApplication.exit(ctx); SpringApplication.exit(ctx);
......
...@@ -56,38 +56,41 @@ public class MultiLevelBomTestRunner { ...@@ -56,38 +56,41 @@ public class MultiLevelBomTestRunner {
// 通过 Spring 容器获取 service 实例 (static main 中 @Autowired 不会生效) // 通过 Spring 容器获取 service 实例 (static main 中 @Autowired 不会生效)
ApplicationContext ctx = SpringApplication.run(ApsApplication.class, args); ApplicationContext ctx = SpringApplication.run(ApsApplication.class, args);
try { try {
long startTime = System.currentTimeMillis();
// MultiLevelBomTestDataBuilder data=new MultiLevelBomTestDataBuilder(); MultiLevelBomTestDataBuilder data=new MultiLevelBomTestDataBuilder();
// data.init();
//
// MacroPlannerOptimizer optimizer = new MacroPlannerOptimizer(data);
// optimizer.buildModel();
// optimizer.solve("bom");
MpPispipResultPersistenceService service =
ctx.getBean(MpPispipResultPersistenceService.class);
int scale = 100;
BenchmarkDataBuilder data = BenchmarkDataBuilder.forScale(scale);
writeLog("===== TEST RUNNER START " + scale + "=====");
data.init(); data.init();
writeLog("Data loaded: " + data.getProducts().size() + " products, "
+ data.getOperations().size() + " operations");
long startTime = System.currentTimeMillis();
MacroPlannerOptimizer optimizer = new MacroPlannerOptimizer(data); MacroPlannerOptimizer optimizer = new MacroPlannerOptimizer(data);
optimizer.buildModel(); optimizer.buildModel();
optimizer.solve(String.valueOf(scale)); optimizer.solve("bom");
// 构建结果并调用 save 入库
ResultWriter writer = new ResultWriter(optimizer.getModel(), optimizer.getData(), startTime); ResultWriter writer = new ResultWriter(optimizer.getModel(), optimizer.getData(), startTime);
OptimizationResult result = writer.buildResult(String.valueOf(scale)); OptimizationResult result = writer.buildResult("bom");
boolean jsonPath = writer.saveResultToFile(String.valueOf(scale), result); boolean jsonPath = writer.saveResultToFile("bom", result);
writeLog("PISPIP result saved: "); // MpPispipResultPersistenceService service =
int saved = service.save(String.valueOf(scale), result); // ctx.getBean(MpPispipResultPersistenceService.class);
writeLog("PISPIP result saved: " + saved); //
// int scale = 2000;
// BenchmarkDataBuilder data = BenchmarkDataBuilder.forScale(scale);
// writeLog("===== TEST RUNNER START " + scale + "=====");
//
// data.init();
// writeLog("Data loaded: " + data.getProducts().size() + " products, "
// + data.getOperations().size() + " operations");
//
// long startTime = System.currentTimeMillis();
// MacroPlannerOptimizer optimizer = new MacroPlannerOptimizer(data);
// optimizer.buildModel();
// optimizer.solve(String.valueOf(scale));
//
// // 构建结果并调用 save 入库
// ResultWriter writer = new ResultWriter(optimizer.getModel(), optimizer.getData(), startTime);
// OptimizationResult result = writer.buildResult(String.valueOf(scale));
// boolean jsonPath = writer.saveResultToFile(String.valueOf(scale), result);
//
// writeLog("PISPIP result saved: ");
// int saved = service.save(String.valueOf(scale), result);
// writeLog("PISPIP result saved: " + saved);
writeLog("===== TEST RUNNER END ====="); writeLog("===== TEST RUNNER END =====");
} catch (Exception e) { } catch (Exception e) {
......
...@@ -24,6 +24,7 @@ import com.aps.mapper.StockMapper; ...@@ -24,6 +24,7 @@ import com.aps.mapper.StockMapper;
import com.aps.service.ApsTimeConfigService; import com.aps.service.ApsTimeConfigService;
import com.aps.service.LanuchService; import com.aps.service.LanuchService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -47,6 +48,7 @@ import java.util.Map; ...@@ -47,6 +48,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
...@@ -429,7 +431,7 @@ public class MacroPlannerDataConverter { ...@@ -429,7 +431,7 @@ public class MacroPlannerDataConverter {
material.setName(m.getName()); material.setName(m.getName());
material.setMaxProduction(m.getMaxProduction()); material.setMaxProduction(m.getMaxProduction());
material.setMinProduction(m.getMinProduction()); material.setMinProduction(m.getMinProduction());
material.setCategoryId(m.getCategoryId());
// 库存 // 库存
List<Stock> materialStocks = stocksByMaterialId.getOrDefault(m.getId(), Collections.emptyList()); List<Stock> materialStocks = stocksByMaterialId.getOrDefault(m.getId(), Collections.emptyList());
if (!materialStocks.isEmpty()) { if (!materialStocks.isEmpty()) {
...@@ -700,6 +702,7 @@ public class MacroPlannerDataConverter { ...@@ -700,6 +702,7 @@ public class MacroPlannerDataConverter {
for (Material m : ctx.materialByMaterialId.values()) { for (Material m : ctx.materialByMaterialId.values()) {
String name = pickName(m.getName(), m.getCode(), m.getId()); String name = pickName(m.getName(), m.getCode(), m.getId());
Product p = new Product(m.getCode(), name, m.getCode()); Product p = new Product(m.getCode(), name, m.getCode());
p.setCategoryId(m.getCategoryId());
products.add(p); products.add(p);
ctx.productByMaterialId.put(m.getId(), p); ctx.productByMaterialId.put(m.getId(), p);
} }
...@@ -842,6 +845,10 @@ public class MacroPlannerDataConverter { ...@@ -842,6 +845,10 @@ public class MacroPlannerDataConverter {
int hid = rd.getRoutingHeaderId().intValue(); int hid = rd.getRoutingHeaderId().intValue();
detailsByHeader.computeIfAbsent(hid, k -> new ArrayList<>()).add(rd); detailsByHeader.computeIfAbsent(hid, k -> new ArrayList<>()).add(rd);
} }
Map<Integer, PlanResource> prMap = ctx.planResources.stream()
.collect(Collectors.toMap(PlanResource::getId, Function.identity()));
Map<Integer, Equipinfo> equipMap = ctx.equipinfos.stream()
.collect(Collectors.toMap(Equipinfo::getId, Function.identity()));
detailsByHeader.values().forEach(list -> detailsByHeader.values().forEach(list ->
list.sort(Comparator.comparing(rd -> list.sort(Comparator.comparing(rd ->
rd.getTaskSeq() == null ? Long.MAX_VALUE : rd.getTaskSeq()))); rd.getTaskSeq() == null ? Long.MAX_VALUE : rd.getTaskSeq())));
...@@ -887,13 +894,23 @@ public class MacroPlannerDataConverter { ...@@ -887,13 +894,23 @@ public class MacroPlannerDataConverter {
unitOps = equips.stream() unitOps = equips.stream()
.filter(e -> e.getEquipId() != null) .filter(e -> e.getEquipId() != null)
.map(e -> { .map(e -> {
PlanResource res= prMap.get(e.getEquipId().intValue());
Integer shopid=0;
if(res!=null)
{
Equipinfo equip = equipMap.get(res.getReferenceId());
if(equip!=null) {
shopid=equip.getShopId();
}
}
String unitId = "EQUIP_" + e.getEquipId(); String unitId = "EQUIP_" + e.getEquipId();
String unitName = e.getName(); String unitName = e.getName();
double capCoeff = (e.getDuration() != null) ? e.getDuration().doubleValue()/3600/e.getOutputQuantity().doubleValue() : 1.0; double capCoeff = (e.getDuration() != null) ? e.getDuration().doubleValue()/3600/e.getOutputQuantity().doubleValue() : 1.0;
boolean lotSize = e.getOneBatchQuantity() != null boolean lotSize = e.getOneBatchQuantity() != null
&& e.getOneBatchQuantity().compareTo(BigDecimal.ZERO) > 0; && e.getOneBatchQuantity().compareTo(BigDecimal.ZERO) > 0;
double lotSizeVal = lotSize ? e.getOneBatchQuantity().doubleValue() : 0.0; double lotSizeVal = lotSize ? e.getOneBatchQuantity().doubleValue() : 0.0;
return new UnitOperation(unitId,unitName, capCoeff, lotSize, lotSizeVal, 1.0); return new UnitOperation(unitId,unitName, capCoeff, lotSize, lotSizeVal, 1.0,shopid);
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
} else { } else {
...@@ -902,7 +919,7 @@ public class MacroPlannerDataConverter { ...@@ -902,7 +919,7 @@ public class MacroPlannerDataConverter {
String unitName = (rd.getEquipTypeId() != null ? rd.getEquipType() : "DEFAULT"); String unitName = (rd.getEquipTypeId() != null ? rd.getEquipType() : "DEFAULT");
double capCoeff = (rd.getRuntime() != null) ? rd.getRuntime().doubleValue() : 1.0; double capCoeff = (rd.getRuntime() != null) ? rd.getRuntime().doubleValue() : 1.0;
unitOps = Arrays.asList(new UnitOperation(unitId,unitName, capCoeff, false, 0.0, 1.0)); unitOps = Arrays.asList(new UnitOperation(unitId,unitName, capCoeff, false, 0.0, 1.0,0));
} }
Operation op = new Operation( Operation op = new Operation(
...@@ -1014,7 +1031,7 @@ public class MacroPlannerDataConverter { ...@@ -1014,7 +1031,7 @@ public class MacroPlannerDataConverter {
"采购-" + pickName(m.getName(), m.getId()) "采购-" + pickName(m.getName(), m.getId())
+ (mp.getSupplyName() != null ? "-" + mp.getSupplyName() : ""), + (mp.getSupplyName() != null ? "-" + mp.getSupplyName() : ""),
Collections.singletonList( Collections.singletonList(
new UnitOperation(unitId,unitName, 0.5, false, 0.0, 1.0)), new UnitOperation(unitId,unitName, 0.5, false, 0.0, 1.0,0)),
new OperationOutput(p, sp), new OperationOutput(p, sp),
1.0, leadTimeDays); 1.0, leadTimeDays);
operations.add(procureOp); operations.add(procureOp);
...@@ -1029,7 +1046,7 @@ public class MacroPlannerDataConverter { ...@@ -1029,7 +1046,7 @@ public class MacroPlannerDataConverter {
"OP_PROCURE_" + m.getId(), "OP_PROCURE_" + m.getId(),
"采购-" + pickName(m.getName(), m.getId()), "采购-" + pickName(m.getName(), m.getId()),
Collections.singletonList( Collections.singletonList(
new UnitOperation(unitId,"通用供应商", 0.5, false, 0.0, 1.0)), new UnitOperation(unitId,"通用供应商", 0.5, false, 0.0, 1.0,0)),
new OperationOutput(p, sp), new OperationOutput(p, sp),
1.0, 0); 1.0, 0);
operations.add(procureOp); operations.add(procureOp);
...@@ -1143,9 +1160,12 @@ public class MacroPlannerDataConverter { ...@@ -1143,9 +1160,12 @@ public class MacroPlannerDataConverter {
// 收集所有 unitId (遍历每个 Operation 的每个 UnitOperation) // 收集所有 unitId (遍历每个 Operation 的每个 UnitOperation)
Map<String,String> unitIds = new HashMap<>() ; Map<String,String> unitIds = new HashMap<>() ;
Map<String,Integer> unitShipIds = new HashMap<>() ;
for (Operation op : operations) { for (Operation op : operations) {
for (UnitOperation uo : op.getUnitOperations()) { for (UnitOperation uo : op.getUnitOperations()) {
unitIds.put(uo.getUnitId(),uo.getUnitName()); unitIds.put(uo.getUnitId(),uo.getUnitName());
unitShipIds.put(uo.getUnitId(),uo.getShopId());
} }
} }
...@@ -1187,7 +1207,9 @@ public class MacroPlannerDataConverter { ...@@ -1187,7 +1207,9 @@ public class MacroPlannerDataConverter {
int workDays = calculateWorkDays(periodStart, periodEnd); int workDays = calculateWorkDays(periodStart, periodEnd);
periodMaxCapacity = DEFAULT_DAILY_HOURS * Math.max(1, workDays); periodMaxCapacity = DEFAULT_DAILY_HOURS * Math.max(1, workDays);
} }
unitPeriods.add(new UnitPeriod(unitId,unitName, p, 0.0, periodMaxCapacity, false)); Integer shopid= unitShipIds.get(unitId);
unitPeriods.add(new UnitPeriod(unitId,unitName, p, 0.0,
periodMaxCapacity, false,shopid));
} }
} }
log.info("构建 Period: {} (dimension={}, horizonEnd={}), UnitPeriod: {}", log.info("构建 Period: {} (dimension={}, horizonEnd={}), UnitPeriod: {}",
...@@ -1288,7 +1310,7 @@ public class MacroPlannerDataConverter { ...@@ -1288,7 +1310,7 @@ public class MacroPlannerDataConverter {
} else { } else {
// 无时间信息, 放入最后一个周期 // 无时间信息, 放入最后一个周期
salesDemands.add(new SalesDemand(p, sp, lastPeriod, qty, priority, salesDemands.add(new SalesDemand(p, sp, lastPeriod, qty, priority,
ado.getId(), ado.getCode(), pickName(ado.getMmcode(), p.getId()),ado.getEndtime()==null?ado.getDeliverytime().toLocalDate():ado.getEndtime().toLocalDate())); ado.getId(), ado.getCode(), pickName(ado.getMmcode(), p.getId()),ado.getEndtime()==null?ado.getDeliverytime().toLocalDate():ado.getEndtime().toLocalDate(),p.getCategoryId()));
continue; continue;
} }
...@@ -1310,7 +1332,7 @@ public class MacroPlannerDataConverter { ...@@ -1310,7 +1332,7 @@ public class MacroPlannerDataConverter {
if (overlapPeriods.isEmpty()) { if (overlapPeriods.isEmpty()) {
salesDemands.add(new SalesDemand(p, sp, lastPeriod, qty, priority, salesDemands.add(new SalesDemand(p, sp, lastPeriod, qty, priority,
ado.getId(), ado.getCode(), pickName(ado.getMmcode(), p.getId()),ado.getEndtime()==null?ado.getDeliverytime().toLocalDate():ado.getEndtime().toLocalDate())); ado.getId(), ado.getCode(), pickName(ado.getMmcode(), p.getId()),ado.getEndtime()==null?ado.getDeliverytime().toLocalDate():ado.getEndtime().toLocalDate(),p.getCategoryId()));
} else { } else {
// 按重叠天数比例拆分需求量: 每期四舍五入取整, 最后一期补差保证总和等于总数 // 按重叠天数比例拆分需求量: 每期四舍五入取整, 最后一期补差保证总和等于总数
int totalQty = (int) Math.round(qty); int totalQty = (int) Math.round(qty);
...@@ -1327,7 +1349,7 @@ public class MacroPlannerDataConverter { ...@@ -1327,7 +1349,7 @@ public class MacroPlannerDataConverter {
allocated += periodQty; allocated += periodQty;
} }
salesDemands.add(new SalesDemand(p, sp, per, periodQty, priority, salesDemands.add(new SalesDemand(p, sp, per, periodQty, priority,
ado.getId(), ado.getCode(), pickName(ado.getMmcode(), p.getId()),ado.getEndtime()==null?ado.getDeliverytime().toLocalDate():ado.getEndtime().toLocalDate())); ado.getId(), ado.getCode(), pickName(ado.getMmcode(), p.getId()),ado.getEndtime()==null?ado.getDeliverytime().toLocalDate():ado.getEndtime().toLocalDate(),p.getCategoryId()));
} }
} }
} }
......
...@@ -47,10 +47,14 @@ public class MultiLevelBomTestDataBuilder extends TestDataBuilder { ...@@ -47,10 +47,14 @@ public class MultiLevelBomTestDataBuilder extends TestDataBuilder {
// === 产品: 成品 P1, P2 + 半成品 S1 + 原材料 R1, R2 === // === 产品: 成品 P1, P2 + 半成品 S1 + 原材料 R1, R2 ===
Product prodP1 = new Product("P1", "成品P1"); Product prodP1 = new Product("P1", "成品P1");
prodP1.setCategoryId(1l);
// Product prodP2 = new Product("P2", "成品P2"); // Product prodP2 = new Product("P2", "成品P2");
Product prodS1 = new Product("S1", "半成品S1"); Product prodS1 = new Product("S1", "半成品S1");
prodS1.setCategoryId(12l);
Product prodR1 = new Product("R1", "原材料R1"); Product prodR1 = new Product("R1", "原材料R1");
prodR1.setCategoryId(3l);
Product prodR2 = new Product("R2", "原材料R2"); Product prodR2 = new Product("R2", "原材料R2");
prodR2.setCategoryId(4l);
products.addAll(Arrays.asList(prodP1, prodS1, prodR1, prodR2)); products.addAll(Arrays.asList(prodP1, prodS1, prodR1, prodR2));
// === 库存点: 每种产品一个库存点 === // === 库存点: 每种产品一个库存点 ===
...@@ -117,7 +121,7 @@ public class MultiLevelBomTestDataBuilder extends TestDataBuilder { ...@@ -117,7 +121,7 @@ public class MultiLevelBomTestDataBuilder extends TestDataBuilder {
// === 初始库存: 全部从 0 开始 === // === 初始库存: 全部从 0 开始 ===
initialInventories.add(new InitialInventory(prodP1, spP1, 0.0)); initialInventories.add(new InitialInventory(prodP1, spP1, 0.0));
// initialInventories.add(new InitialInventory(prodP2, spP2, 0.0)); // initialInventories.add(new InitialInventory(prodP2, spP2, 0.0));
initialInventories.add(new InitialInventory(prodS1, spSemi, 0.0)); initialInventories.add(new InitialInventory(prodS1, spSemi, 40.0));
initialInventories.add(new InitialInventory(prodR1, spR1, 0.0)); initialInventories.add(new InitialInventory(prodR1, spR1, 0.0));
initialInventories.add(new InitialInventory(prodR2, spR2, 0.0)); initialInventories.add(new InitialInventory(prodR2, spR2, 0.0));
......
...@@ -69,7 +69,7 @@ public class Operation { ...@@ -69,7 +69,7 @@ public class Operation {
boolean hasLotSize, double lotSize, double qtpfactor, boolean hasLotSize, double lotSize, double qtpfactor,
int leadTimeDays) { int leadTimeDays) {
this(id, name, this(id, name,
Arrays.asList(new UnitOperation(unitId,"", capacityCoeff, hasLotSize, lotSize, qtpfactor)), Arrays.asList(new UnitOperation(unitId,"", capacityCoeff, hasLotSize, lotSize, qtpfactor,0)),
output, relativeDuration, leadTimeDays); output, relativeDuration, leadTimeDays);
} }
......
...@@ -18,9 +18,16 @@ public class OperationOutput { ...@@ -18,9 +18,16 @@ public class OperationOutput {
private final Product product; // 产出产品 private final Product product; // 产出产品
private final StockingPoint stockingPoint; // 产出到哪个库存点 private final StockingPoint stockingPoint; // 产出到哪个库存点
public final double factor;
public OperationOutput(Product product, StockingPoint stockingPoint) { public OperationOutput(Product product, StockingPoint stockingPoint) {
this(product,stockingPoint,1);
}
public OperationOutput(Product product, StockingPoint stockingPoint,double factor) {
this.product = product; this.product = product;
this.stockingPoint = stockingPoint; this.stockingPoint = stockingPoint;
this.factor=factor;
} }
public Product getProduct() { return product; } public Product getProduct() { return product; }
...@@ -28,9 +35,14 @@ public class OperationOutput { ...@@ -28,9 +35,14 @@ public class OperationOutput {
/** 便捷方法: 产品 ID */ /** 便捷方法: 产品 ID */
public String getProductId() { return product.getId(); } public String getProductId() { return product.getId(); }
public String getProductCode() { return product.getCode(); }
/** 便捷方法: 库存点 ID */ /** 便捷方法: 库存点 ID */
public String getSpId() { return stockingPoint.getId(); } public String getSpId() { return stockingPoint.getId(); }
public String getSpName() { return stockingPoint.getName(); }
@Override @Override
public String toString() { public String toString() {
return product.getId() + "@" + stockingPoint.getId(); return product.getId() + "@" + stockingPoint.getId();
......
...@@ -8,6 +8,8 @@ public class Product { ...@@ -8,6 +8,8 @@ public class Product {
private final String name; private final String name;
private final String code; private final String code;
private Long categoryId;
public Product(String id, String name) { public Product(String id, String name) {
this(id, name, id); this(id, name, id);
} }
...@@ -22,6 +24,10 @@ public class Product { ...@@ -22,6 +24,10 @@ public class Product {
public String getName() { return name; } public String getName() { return name; }
public String getCode() { return code; } public String getCode() { return code; }
public Long getCategoryId() { return categoryId; }
public void setCategoryId(Long val) { categoryId=val; }
@Override @Override
public String toString() { public String toString() {
return name + "1(" + id + ")"; return name + "1(" + id + ")";
......
...@@ -18,6 +18,8 @@ public class SalesDemand { ...@@ -18,6 +18,8 @@ public class SalesDemand {
private final LocalDate demandOrderDate; private final LocalDate demandOrderDate;
private final Long categoryId;
public SalesDemand(Product product, StockingPoint stockingPoint, Period period, public SalesDemand(Product product, StockingPoint stockingPoint, Period period,
double quantity, double priority) { double quantity, double priority) {
this(product, stockingPoint, period, quantity, priority, null,null); this(product, stockingPoint, period, quantity, priority, null,null);
...@@ -25,12 +27,13 @@ public class SalesDemand { ...@@ -25,12 +27,13 @@ public class SalesDemand {
public SalesDemand(Product product, StockingPoint stockingPoint, Period period, public SalesDemand(Product product, StockingPoint stockingPoint, Period period,
double quantity, double priority, String demandOrderId,LocalDate demandOrderDate) { double quantity, double priority, String demandOrderId,LocalDate demandOrderDate) {
this(product, stockingPoint, period, quantity, priority, demandOrderId, null, null,demandOrderDate); this(product, stockingPoint, period, quantity, priority, demandOrderId, null, null,demandOrderDate,0l);
} }
public SalesDemand(Product product, StockingPoint stockingPoint, Period period, public SalesDemand(Product product, StockingPoint stockingPoint, Period period,
double quantity, double priority, String demandOrderId, double quantity, double priority, String demandOrderId,
String orderCode, String productCode,LocalDate demandOrderDate) { String orderCode, String productCode,LocalDate demandOrderDate,Long categoryId) {
this.product = product; this.product = product;
this.stockingPoint = stockingPoint; this.stockingPoint = stockingPoint;
this.period = period; this.period = period;
...@@ -40,6 +43,7 @@ public class SalesDemand { ...@@ -40,6 +43,7 @@ public class SalesDemand {
this.orderCode = orderCode; this.orderCode = orderCode;
this.productCode = productCode; this.productCode = productCode;
this.demandOrderDate=demandOrderDate; this.demandOrderDate=demandOrderDate;
this.categoryId= categoryId;
} }
public Product getProduct() { return product; } public Product getProduct() { return product; }
...@@ -50,7 +54,7 @@ public class SalesDemand { ...@@ -50,7 +54,7 @@ public class SalesDemand {
public String getDemandOrderId() { return demandOrderId; } public String getDemandOrderId() { return demandOrderId; }
public String getOrderCode() { return orderCode; } public String getOrderCode() { return orderCode; }
public String getProductCode() { return productCode; } public String getProductCode() { return productCode; }
public Long getCategoryId() { return categoryId; }
public LocalDate getDemandOrderDate() { return demandOrderDate; } public LocalDate getDemandOrderDate() { return demandOrderDate; }
public String getKey() { public String getKey() {
......
...@@ -17,14 +17,21 @@ public class UnitOperation { ...@@ -17,14 +17,21 @@ public class UnitOperation {
private final double lotSize; // 批次大小 private final double lotSize; // 批次大小
private final double qtpfactor; // QuantityToProcessFactor private final double qtpfactor; // QuantityToProcessFactor
private final Integer shopId;
public UnitOperation(String unitId,String unitName, double capacityCoeff, public UnitOperation(String unitId,String unitName, double capacityCoeff,
boolean hasLotSize, double lotSize, double qtpfactor) { boolean hasLotSize, double lotSize, double qtpfactor) {
this( unitId, unitName, capacityCoeff,
hasLotSize, lotSize, qtpfactor,0);
}
public UnitOperation(String unitId,String unitName, double capacityCoeff,
boolean hasLotSize, double lotSize, double qtpfactor, Integer shopId) {
this.unitId = unitId; this.unitId = unitId;
this.unitName=unitName; this.unitName=unitName;
this.capacityCoeff = capacityCoeff; this.capacityCoeff = capacityCoeff;
this.hasLotSize = hasLotSize; this.hasLotSize = hasLotSize;
this.lotSize = lotSize; this.lotSize = lotSize;
this.qtpfactor = qtpfactor; this.qtpfactor = qtpfactor;
this.shopId=shopId;
} }
public String getUnitId() { return unitId; } public String getUnitId() { return unitId; }
...@@ -35,6 +42,8 @@ public class UnitOperation { ...@@ -35,6 +42,8 @@ public class UnitOperation {
public double getLotSize() { return lotSize; } public double getLotSize() { return lotSize; }
public double getQtpfactor() { return qtpfactor; } public double getQtpfactor() { return qtpfactor; }
public Integer getShopId() { return shopId; }
@Override @Override
public String toString() { public String toString() {
return unitId + "(产能" + capacityCoeff + "h/件" + return unitId + "(产能" + capacityCoeff + "h/件" +
......
...@@ -15,9 +15,11 @@ public class UnitPeriod { ...@@ -15,9 +15,11 @@ public class UnitPeriod {
private final boolean hasMinCapacity; // 是否有最小产能约束 private final boolean hasMinCapacity; // 是否有最小产能约束
private final boolean unlimited; // 产能是否无上限 (如原材料供应商) private final boolean unlimited; // 产能是否无上限 (如原材料供应商)
private final Integer shopId;
/** 完整构造器 */ /** 完整构造器 */
public UnitPeriod(String unitId,String unitName, Period period, double minCapacity, double maxCapacity, public UnitPeriod(String unitId,String unitName, Period period, double minCapacity, double maxCapacity,
boolean hasMinCapacity, boolean unlimited) { boolean hasMinCapacity, boolean unlimited,Integer shopId) {
this.unitId = unitId; this.unitId = unitId;
this.unitName=unitName; this.unitName=unitName;
this.period = period; this.period = period;
...@@ -25,16 +27,19 @@ public class UnitPeriod { ...@@ -25,16 +27,19 @@ public class UnitPeriod {
this.maxCapacity = unlimited ? Double.MAX_VALUE : maxCapacity; this.maxCapacity = unlimited ? Double.MAX_VALUE : maxCapacity;
this.hasMinCapacity = hasMinCapacity; this.hasMinCapacity = hasMinCapacity;
this.unlimited = unlimited; this.unlimited = unlimited;
this.shopId=shopId;
} }
/** 有限产能构造器 (向后兼容) */
public UnitPeriod(String unitId,String unitName, Period period, double minCapacity, double maxCapacity, boolean hasMinCapacity) { public UnitPeriod(String unitId,String unitName, Period period, double minCapacity, double maxCapacity, boolean hasMinCapacity) {
this(unitId,unitName, period, minCapacity, maxCapacity, hasMinCapacity, false); this(unitId,unitName, period, minCapacity, maxCapacity, hasMinCapacity, false,0);
}
/** 有限产能构造器 (向后兼容) */
public UnitPeriod(String unitId,String unitName, Period period, double minCapacity, double maxCapacity, boolean hasMinCapacity,Integer shopId) {
this(unitId,unitName, period, minCapacity, maxCapacity, hasMinCapacity, false,shopId);
} }
/** 无限产能便捷构造器 */ /** 无限产能便捷构造器 */
public static UnitPeriod unlimited(String unitId,String unitName, Period period) { public static UnitPeriod unlimited(String unitId,String unitName, Period period) {
return new UnitPeriod(unitId,unitName, period, 0, 0, false, true); return new UnitPeriod(unitId,unitName, period, 0, 0, false, true,0);
} }
public String getUnitId() { return unitId; } public String getUnitId() { return unitId; }
...@@ -47,6 +52,8 @@ public class UnitPeriod { ...@@ -47,6 +52,8 @@ public class UnitPeriod {
public boolean hasMinCapacity() { return hasMinCapacity; } public boolean hasMinCapacity() { return hasMinCapacity; }
public boolean isUnlimited() { return unlimited; } public boolean isUnlimited() { return unlimited; }
public Integer getShopId() { return shopId; }
public String getKey() { public String getKey() {
return unitId + "_" + period.getIndex(); return unitId + "_" + period.getIndex();
} }
......
...@@ -27,9 +27,17 @@ public class OptimizationResult { ...@@ -27,9 +27,17 @@ public class OptimizationResult {
// ==================== 业务结果 ==================== // ==================== 业务结果 ====================
private final List<PeriodTaskResult> periodTasks = new ArrayList<>(); private final List<PeriodTaskResult> periodTasks = new ArrayList<>();
private final List<PeriodTaskResult.OutputInfo> periodTaskOutputs = new ArrayList<>();
private final List<SalesDemandResult> salesDemands = new ArrayList<>(); private final List<SalesDemandResult> salesDemands = new ArrayList<>();
private List<SalesDemandResult> saleDemandSummaries = new ArrayList<>();
private final List<PispipResult> pispips = new ArrayList<>(); private final List<PispipResult> pispips = new ArrayList<>();
private final List<PispipResult.PispipSummarieResult> pispipSummaries = new ArrayList<>();
// ==================== 产品生产网络 ==================== // ==================== 产品生产网络 ====================
private ProductNetworkResult productNetwork; private ProductNetworkResult productNetwork;
...@@ -38,6 +46,8 @@ public class OptimizationResult { ...@@ -38,6 +46,8 @@ public class OptimizationResult {
private List<UnitCapacityResult> unitCapacities; private List<UnitCapacityResult> unitCapacities;
private List<UnitCapacityResult.UnitPeriodDetail> unitPeriodDetails;
// ==================== 需求满足汇总 ==================== // ==================== 需求满足汇总 ====================
private List<DemandSummaryResult> demandSummary; private List<DemandSummaryResult> demandSummary;
...@@ -59,15 +69,30 @@ public class OptimizationResult { ...@@ -59,15 +69,30 @@ public class OptimizationResult {
public void setVersion(String v) { this.version = v; } public void setVersion(String v) { this.version = v; }
public List<PeriodTaskResult> getPeriodTasks() { return periodTasks; } public List<PeriodTaskResult> getPeriodTasks() { return periodTasks; }
public List<PeriodTaskResult.OutputInfo> getPeriodTaskOutputs() { return periodTaskOutputs; }
public List<SalesDemandResult> getSalesDemands() { return salesDemands; } public List<SalesDemandResult> getSalesDemands() { return salesDemands; }
public List<SalesDemandResult> getSaleSummarieDemands() { return saleDemandSummaries; }
public void setSaleSummarieDemands(List<SalesDemandResult> v) { saleDemandSummaries=v; }
public List<PispipResult> getPispips() { return pispips; } public List<PispipResult> getPispips() { return pispips; }
public List<PispipResult.PispipSummarieResult> getPispipSummaries() { return pispipSummaries; }
public ProductNetworkResult getProductNetwork() { return productNetwork; } public ProductNetworkResult getProductNetwork() { return productNetwork; }
public void setProductNetwork(ProductNetworkResult v) { this.productNetwork = v; } public void setProductNetwork(ProductNetworkResult v) { this.productNetwork = v; }
public List<UnitCapacityResult> getUnitCapacities() { return unitCapacities; } public List<UnitCapacityResult> getUnitCapacities() { return unitCapacities; }
public List<UnitCapacityResult.UnitPeriodDetail> getUnitPeriodDetails() { return unitPeriodDetails; }
public void setUnitCapacities(List<UnitCapacityResult> v) { this.unitCapacities = v; } public void setUnitCapacities(List<UnitCapacityResult> v) { this.unitCapacities = v; }
public void setUnitPeriodDetails(List<UnitCapacityResult.UnitPeriodDetail> v) { this.unitPeriodDetails = v; }
public List<DemandSummaryResult> getDemandSummary() { return demandSummary; } public List<DemandSummaryResult> getDemandSummary() { return demandSummary; }
public void setDemandSummary(List<DemandSummaryResult> v) { this.demandSummary = v; } public void setDemandSummary(List<DemandSummaryResult> v) { this.demandSummary = v; }
......
...@@ -17,6 +17,7 @@ public class PeriodTaskResult { ...@@ -17,6 +17,7 @@ public class PeriodTaskResult {
private String operationId; private String operationId;
private String operationName; private String operationName;
private String unitId; private String unitId;
private String unitName;
private int periodIndex; private int periodIndex;
private String periodStartDate; private String periodStartDate;
...@@ -40,11 +41,21 @@ public class PeriodTaskResult { ...@@ -40,11 +41,21 @@ public class PeriodTaskResult {
// ==================== 内嵌类 ==================== // ==================== 内嵌类 ====================
/** 产出信息 */ /** 产出信息 */
// public static class OutputInfo { @Data
// public String productId; public static class OutputInfo {
// public String spId; public String productId;
// public double factor; public String productCode;
// } public String spId;
public String spName;
public double factor;
private String dataKey;
private int periodIndex;
private String periodStartDate;
/** PTQty — 生产量 */
private double productionQty;
}
} }
\ No newline at end of file
...@@ -16,7 +16,7 @@ public class PispipResult { ...@@ -16,7 +16,7 @@ public class PispipResult {
private String productId; private String productId;
private String productCode; private String productCode;
private String spId; private String spId;
private Long categoryId;
private String spName; private String spName;
private int periodIndex; private int periodIndex;
private String periodStartDate; private String periodStartDate;
...@@ -83,6 +83,36 @@ public class PispipResult { ...@@ -83,6 +83,36 @@ public class PispipResult {
/** 每个工序的产出明细 */ /** 每个工序的产出明细 */
private final List<ProductionDetail> productionDetails = new ArrayList<>(); private final List<ProductionDetail> productionDetails = new ArrayList<>();
public static class PispipSummarieResult {
private String key;
private String productId;
private String productCode;
private String spId;
private String spName;
private Long categoryId;
public String getKey() { return key; }
public void setKey(String v) { this.key = v; }
public String getProductId() { return productId; }
public void setProductId(String v) { this.productId = v; }
public String getProductCode() { return productCode; }
public void setProductCode(String v) { this.productCode = v; }
public String getSpId() { return spId; }
public void setSpId(String v) { this.spId = v; }
public String getSpName() { return spName; }
public void setSpName(String v) { this.spName = v; }
public Long getCategoryId() { return categoryId; }
public void setCategoryId(Long v) { this.categoryId = v; }
}
// ==================== 内嵌类 ==================== // ==================== 内嵌类 ====================
/** 工序产出明细 */ /** 工序产出明细 */
......
package com.aps.macroplanner.output.dto; package com.aps.macroplanner.output.dto;
import lombok.Data;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
...@@ -8,6 +10,7 @@ import java.util.List; ...@@ -8,6 +10,7 @@ import java.util.List;
* *
* <p>每个销售需求在每个周期的满足量、缺口、优先级等。</p> * <p>每个销售需求在每个周期的满足量、缺口、优先级等。</p>
*/ */
@Data
public class SalesDemandResult { public class SalesDemandResult {
private String salesDemandId; private String salesDemandId;
...@@ -33,6 +36,8 @@ public class SalesDemandResult { ...@@ -33,6 +36,8 @@ public class SalesDemandResult {
/** 优先级 */ /** 优先级 */
private double priority; private double priority;
private Long categoryId;
/** 未完成原因分析 (仅当 unmetQty > 0 时有内容) */ /** 未完成原因分析 (仅当 unmetQty > 0 时有内容) */
private final List<String> unmetReasons = new ArrayList<>(); private final List<String> unmetReasons = new ArrayList<>();
/** 风险分析 (即使满足也可能存在的供应链风险) */ /** 风险分析 (即使满足也可能存在的供应链风险) */
......
...@@ -19,6 +19,9 @@ public class SupplyChainNode { ...@@ -19,6 +19,9 @@ public class SupplyChainNode {
/** 产品 ID */ /** 产品 ID */
private String productId; private String productId;
public String productCode;
/** 库存点 ID */ /** 库存点 ID */
private String spId; private String spId;
...@@ -148,6 +151,10 @@ public class SupplyChainNode { ...@@ -148,6 +151,10 @@ public class SupplyChainNode {
public String getProductId() { return productId; } public String getProductId() { return productId; }
public void setProductId(String v) { this.productId = v; } public void setProductId(String v) { this.productId = v; }
public String getProductCode() { return productCode; }
public void setProductCode(String v) { this.productCode = v; }
public String getSpId() { return spId; } public String getSpId() { return spId; }
public void setSpId(String v) { this.spId = v; } public void setSpId(String v) { this.spId = v; }
......
package com.aps.macroplanner.output.dto; package com.aps.macroplanner.output.dto;
import lombok.Data;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
...@@ -20,6 +22,7 @@ import java.util.Map; ...@@ -20,6 +22,7 @@ import java.util.Map;
* <tr><td>periodTasks</td><td>该设备的生产任务明细 (PeriodTaskResult[])</td></tr> * <tr><td>periodTasks</td><td>该设备的生产任务明细 (PeriodTaskResult[])</td></tr>
* </table> * </table>
*/ */
@Data
public class UnitCapacityResult { public class UnitCapacityResult {
/** 设备ID */ /** 设备ID */
...@@ -27,6 +30,8 @@ public class UnitCapacityResult { ...@@ -27,6 +30,8 @@ public class UnitCapacityResult {
private String unitName; private String unitName;
private Integer shopId;
/** 使用该设备的工序ID列表 */ /** 使用该设备的工序ID列表 */
private List<String> operationIds; private List<String> operationIds;
/** 全部周期最大可用产能合计 */ /** 全部周期最大可用产能合计 */
...@@ -44,13 +49,19 @@ public class UnitCapacityResult { ...@@ -44,13 +49,19 @@ public class UnitCapacityResult {
private double overallUtilization; private double overallUtilization;
/** 各周期明细 */ /** 各周期明细 */
private final List<UnitPeriodDetail> periodDetails = new ArrayList<>(); // private final List<UnitPeriodDetail> periodDetails = new ArrayList<>();
// ==================== 内嵌类 ==================== // ==================== 内嵌类 ====================
/** 单周期产能明细 */ /** 单周期产能明细 */
public static class UnitPeriodDetail { public static class UnitPeriodDetail {
/** 设备ID */
public String unitId;
public String unitName;
/** 周期索引 */ /** 周期索引 */
public int periodIndex; public int periodIndex;
/** 周期起始日期 */ /** 周期起始日期 */
...@@ -69,7 +80,7 @@ public class UnitCapacityResult { ...@@ -69,7 +80,7 @@ public class UnitCapacityResult {
public double production; public double production;
/** 该周期内在该设备上执行的工序明细 */ /** 该周期内在该设备上执行的工序明细 */
public final List<UnitTaskInfo> tasks = new ArrayList<>(); // public final List<UnitTaskInfo> tasks = new ArrayList<>();
} }
/** 设备上的工序级生产明细 */ /** 设备上的工序级生产明细 */
public static class UnitTaskInfo { public static class UnitTaskInfo {
...@@ -107,7 +118,7 @@ public class UnitCapacityResult { ...@@ -107,7 +118,7 @@ public class UnitCapacityResult {
public double getTotalProduction() { return totalProduction; } public double getTotalProduction() { return totalProduction; }
public void setTotalProduction(double v) { this.totalProduction = v; } public void setTotalProduction(double v) { this.totalProduction = v; }
public List<UnitPeriodDetail> getPeriodDetails() { return periodDetails; } //public List<UnitPeriodDetail> getPeriodDetails() { return periodDetails; }
public double getTotalOverloaded() { return totalOverloaded; } public double getTotalOverloaded() { return totalOverloaded; }
public void setTotalOverloaded(double v) { this.totalOverloaded = v; } public void setTotalOverloaded(double v) { this.totalOverloaded = v; }
......
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