完善主计划场景隔离与排产兼容

parent 0babbc59
package com.aps.config;
import com.aps.macroplanner.scene.MacroSceneDataPermissionHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(
new DataPermissionInterceptor(new MacroSceneDataPermissionHandler()));
return interceptor;
}
}
package com.aps.controller;
import com.aps.common.util.R;
import com.aps.entity.MacroSceneConfig;
import com.aps.macroplanner.scene.MacroSceneCreateRequest;
import com.aps.macroplanner.scene.MacroSceneService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/macroScene")
@Tag(name = "主计划场景管理", description = "主计划场景的创建、查询和删除")
@RequiredArgsConstructor
public class MacroSceneController {
private final MacroSceneService macroSceneService;
@PostMapping
@Operation(summary = "创建主计划场景", description = "从原始数据或已有主计划场景复制创建新场景")
public R<MacroSceneConfig> create(@RequestBody MacroSceneCreateRequest request) {
return R.ok(macroSceneService.createScene(request));
}
@GetMapping
@Operation(summary = "查询主计划场景列表")
public R<List<MacroSceneConfig>> list() {
return R.ok(macroSceneService.listScenes());
}
@GetMapping("/{sceneId}")
@Operation(summary = "查询主计划场景详情")
public R<MacroSceneConfig> get(@PathVariable String sceneId) {
return R.ok(macroSceneService.getScene(sceneId));
}
@DeleteMapping("/{sceneId}")
@Operation(summary = "删除主计划场景", description = "删除场景配置及该场景下复制的数据")
public R<Boolean> delete(@PathVariable String sceneId) {
macroSceneService.deleteScene(sceneId);
return R.ok(true);
}
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
......@@ -8,6 +13,7 @@ import lombok.Data;
@Data
public class ApsDemandOrder {
@TableId(value = "id", type = IdType.INPUT)
private String id;
private Long sourceType;
private String exp1;
......@@ -61,4 +67,6 @@ private Long lastmodifieruserid;
private Short isdeleted;
private LocalDateTime deletiontime;
private Long deleteruserid;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
......@@ -20,4 +21,7 @@ public class ApsTimeConfig {
/** 周期维度: DAY(天) / WEEK(周) / MONTH(月), 默认 DAY */
private String periodDimension;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.time.LocalDateTime;
......@@ -8,6 +13,7 @@ import java.time.LocalDateTime;
@Data
@TableName("MES.EQUIP_SHIFT_CAPACITY")
public class EquipShiftCapacity {
@TableId(value = "id", type = IdType.INPUT)
private Long id;
private Long creatorUserId;
private LocalDateTime creationTime;
......@@ -34,4 +40,6 @@ public class EquipShiftCapacity {
private String holidayTimePeriods;
private String specialTimePeriods;
private String validTimePeriods;
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import java.math.BigDecimal;
......@@ -22,7 +24,7 @@ public class Equipinfo implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@TableId(value = "id", type = IdType.INPUT)
private Integer id;
private Integer shopId;
......@@ -136,4 +138,7 @@ public class Equipinfo implements Serializable {
private BigDecimal maxDurationTime;
private BigDecimal jpExpecationTime;
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class ErpPurchaseOrder {
@TableId(value = "id", type = IdType.INPUT)
private Long id;
private LocalDateTime creationtime;
private Long creatoruserid;
......@@ -32,4 +38,6 @@ private Long manufacturerId;
private String manufacturerCode;
private String manufacturerName;
private LocalDateTime arrivalDate;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity.Gantt;
import com.aps.entity.basic.ShiftVO;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class ResourceSummaryVO {
private long id;
private String name;
private String type;
private Integer change;
private Integer split;
private long departmentId;
private String departmentName;
private String shopName;
private long shopId;
private String code;
private ShiftVO shift;
}
package com.aps.entity.Gantt;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
@Data
@Accessors(chain = true)
@Schema(name = "ScheduledOrderVO", description = "Scheduled order summary")
public class ScheduledOrderVO {
private String id;
private String productName;
private Integer productType;
private String productId;
private double quantity;
private String code;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
private LocalDateTime startDate;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
private LocalDateTime endDate;
private Long shopId;
private String shopName;
private String status;
private Integer headerId;
private String headerName;
private String orderCode;
}
\ No newline at end of file
package com.aps.entity.Gantt;
import lombok.Data;
/**
* 供给关系项
*/
@Data
public class SupplyRelationItem {
private String taskIdFrom;
private String taskIdTo;
private String fromTime;
private String toTime;
private String fromIdFrom;
private Integer toIdTo;
}
\ No newline at end of file
package com.aps.entity.Gantt;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 供给关系查询请求参数类
*/
@Data
public class SupplyRelationRequest {
private String id;
private String planId;
private String productId;
private Integer quantity;
private String start;
private String end;
private Integer setup;
private Integer teardown;
private Integer equipChange;
private Integer equipCooling;
private String equipName;
private Integer duration;
private Integer equipId;
private Integer shopId;
private Integer status;
private Integer detailId;
private Integer headerId;
private Integer seq;
private String seqName;
private Integer processingTime;
private Integer absolutePreparationTime;
private Boolean locked;
}
\ No newline at end of file
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("MP_SCENE_CONFIG")
@Schema(description = "主计划场景配置")
public class MacroSceneConfig {
@TableId(value = "SCENE_ID", type = IdType.INPUT)
@Schema(description = "场景 ID")
private String sceneId;
@Schema(description = "场景名称")
private String sceneName;
@Schema(description = "场景描述")
private String sceneDesc;
@Schema(description = "来源场景 ID")
private String sourceSceneId;
@Schema(description = "场景状态,例如 COPYING、READY")
private String sceneStatus;
@Schema(description = "创建人")
private String createUser;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "更新人")
private String updateUser;
@Schema(description = "更新时间")
private LocalDateTime updateTime;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
......@@ -25,6 +29,7 @@ public class MaterialInfo implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.INPUT)
private String id;
......@@ -402,4 +407,7 @@ public class MaterialInfo implements Serializable {
* 不可见性(外贸删除的物料)
*/
private Long invisable;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
......@@ -26,5 +31,8 @@ private String supplyCode;
private BigDecimal price;
private Integer purchaseCycle;
private Integer inspectionCycle;
@TableId(value = "id", type = IdType.INPUT)
private Long id;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
......@@ -10,6 +12,7 @@ import lombok.Data;
@Data
public class PlanResource {
@TableId(value = "id", type = IdType.INPUT)
private Integer id;
private String title;
private String code;
......@@ -38,4 +41,6 @@ private Long nrofunitsopen;
private Integer isstop;
private LocalDate stoptime;
private LocalDate stopendtime;
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class PurchaseReceipt {
@TableId(value = "id", type = IdType.INPUT)
private Long id;
private LocalDateTime creationtime;
private Long creatoruserid;
......@@ -48,4 +54,6 @@ private String nof;
private String scdwbm;
private String ylzd4;
private String ylzd5;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
......@@ -8,6 +13,7 @@ import java.time.LocalDateTime;
@Data
public class RoutingDetail {
@TableId(value = "id", type = IdType.INPUT)
private Long id;
private LocalDateTime creationTime;
private BigDecimal creatorUserId;
......@@ -61,4 +67,7 @@ public class RoutingDetail {
private BigDecimal incrementQty;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import java.time.LocalDateTime;
@Data
public class RoutingDetailConnect {
@TableId(value = "id", type = IdType.INPUT)
private Long id;
private LocalDateTime creationtime;
private Long creatoruserid;
......@@ -24,4 +30,6 @@ private String exp3;
private String exp4;
private Long routingHeaderId;
private String strId;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
......@@ -24,7 +26,7 @@ public class RoutingDetailEquip implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@TableId(value = "id", type = IdType.INPUT)
private Integer id;
/**
......@@ -138,4 +140,7 @@ public class RoutingDetailEquip implements Serializable {
* 准备时间
*/
private int setupTime;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
......@@ -24,7 +26,7 @@ public class RoutingHeader implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@TableId(value = "id", type = IdType.INPUT)
private Integer id;
private LocalDate creationTime;
......@@ -144,4 +146,7 @@ public class RoutingHeader implements Serializable {
private BigDecimal pcost;
private Integer invisable;
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class Routingsupporting {
@TableId(value = "id", type = IdType.INPUT)
private Long id;
private LocalDateTime creationtime;
private Long creatoruserid;
......@@ -35,4 +41,6 @@ private Long spentMeasureUnit;
private String spentMeasureUnitName;
private String strId;
private String drawNum;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class SjzPfWhStock {
@TableId(value = "id", type = IdType.INPUT)
private Long id;
private LocalDateTime creationtime;
private Long creatoruserid;
......@@ -41,4 +47,6 @@ private String jkdwmc;
private String ifsl;
private Long checkstatus;
private BigDecimal checkquantity;
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
package com.aps.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.FieldFill;
import lombok.Data;
import java.math.BigDecimal;
......@@ -8,6 +12,7 @@ import java.time.LocalDateTime;
@Data
public class Stock {
@TableId(value = "id", type = IdType.INPUT)
private Long id;
private LocalDateTime creationtime;
private Long creatoruserid;
......@@ -50,4 +55,7 @@ private String warehousingUnitName;
public double getAvailableInventory(){
return total-totalLock-usedInventory;
};
}
\ No newline at end of file
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
......@@ -2,6 +2,7 @@ package com.aps.macroplanner.data;
import com.aps.common.util.ParamValidator;
import com.aps.entity.*;
import com.aps.macroplanner.scene.MacroSceneContext;
import com.aps.entity.basic.Material;
import com.aps.entity.basic.MaterialSupply;
import com.aps.mapper.EquipShiftCapacityMapper;
......@@ -134,6 +135,10 @@ public class MacroPlannerDataConverter {
* @return 填充好的 TestDataBuilder, 可直接传给 MacroPlannerOptimizer
*/
public TestDataBuilder convert(String sceneId) {
return MacroSceneContext.execute(sceneId, () -> convertScoped(sceneId));
}
private TestDataBuilder convertScoped(String sceneId) {
log.info("开始转换场景数据到 macroplanner: sceneId={}", sceneId);
ConvertContext ctx = loadRawData(sceneId);
......@@ -161,9 +166,8 @@ public class MacroPlannerDataConverter {
// 0. 读取时间配置, 计算 horizonEnd
// endCount = 期数 (与 periodDimension 结合决定实际天数)
ApsTimeConfig timeConfig = apsTimeConfigService.getOne(new LambdaQueryWrapper<>());
ctx.baseTime = LocalDateTime.of(2026,9,28,0,0,0);
// ctx.baseTime = (timeConfig != null && timeConfig.getBaseTime() != null)
// ? timeConfig.getBaseTime() : LocalDateTime.now();
ctx.baseTime = (timeConfig != null && timeConfig.getBaseTime() != null)
? timeConfig.getBaseTime() : LocalDateTime.now();
ctx.periodDimension = "DAY";
if (timeConfig != null && timeConfig.getPeriodDimension() != null
......@@ -187,19 +191,10 @@ public class MacroPlannerDataConverter {
ctx.periodDimension, periodCount, ctx.baseTime, ctx.horizonEnd);
// 1. 需求订单 (ApsDemandOrder, 按 deliverytime 时间范围过滤)
// ctx.apsDemandOrders = apsDemandOrderMapper.selectList(
// new LambdaQueryWrapper<ApsDemandOrder>()
// .ge(ApsDemandOrder::getDeliverytime, ctx.baseTime)
// .lt(ApsDemandOrder::getDeliverytime, horizonEndDateTime));
ctx.apsDemandOrders = apsDemandOrderMapper.selectList(
ctx.apsDemandOrders = apsDemandOrderMapper.selectList(
new LambdaQueryWrapper<ApsDemandOrder>()
.ge(ApsDemandOrder::getDeliverytime, ctx.baseTime)
.eq(ApsDemandOrder::getCode,"XQDD_20260812_6")
.lt(ApsDemandOrder::getDeliverytime, horizonEndDateTime)
);
.lt(ApsDemandOrder::getDeliverytime, horizonEndDateTime));
log.info("加载需求订单: {} 条 (时间范围过滤)", ctx.apsDemandOrders.size());
......@@ -209,7 +204,7 @@ public class MacroPlannerDataConverter {
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toSet());
List<Integer> routingIds=null;
List<Integer> routingIds = Collections.emptyList();
// 3. 工艺路线头表
if (!materialIds.isEmpty()) {
ctx.routingHeaders = routingHeaderMapper.selectList(
......
package com.aps.macroplanner.scene;
import java.util.function.Supplier;
/** Holds the macro-planning scene selected for the current request or operation. */
public final class MacroSceneContext {
private static final ThreadLocal<String> CURRENT_SCENE = new ThreadLocal<>();
private MacroSceneContext() {
}
public static String getSceneId() {
return CURRENT_SCENE.get();
}
public static void setSceneId(String sceneId) {
String normalized = normalize(sceneId);
if (normalized == null) {
CURRENT_SCENE.remove();
} else {
CURRENT_SCENE.set(normalized);
}
}
public static void clear() {
CURRENT_SCENE.remove();
}
public static <T> T execute(String sceneId, Supplier<T> action) {
String previous = getSceneId();
try {
setSceneId(sceneId);
return action.get();
} finally {
setSceneId(previous);
}
}
public static void execute(String sceneId, Runnable action) {
execute(sceneId, () -> {
action.run();
return null;
});
}
private static String normalize(String sceneId) {
if (sceneId == null || sceneId.trim().isEmpty()) {
return null;
}
return sceneId.trim();
}
}
package com.aps.macroplanner.scene;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class MacroSceneCreateRequest {
@Schema(description = "场景名称", required = true, example = "主计划场景001")
private String sceneName;
@Schema(description = "场景描述", example = "场景描述")
private String sceneDesc;
@Schema(description = "来源场景 ID,不传表示从原始数据创建", nullable = true)
private String sourceSceneId;
@Schema(description = "用户 ID", required = true, example = "1111")
private String userId;
}
package com.aps.macroplanner.scene;
import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
public class MacroSceneDataPermissionHandler implements MultiDataPermissionHandler {
private static final Set<String> SCENE_TABLES = new HashSet<>(Arrays.asList(
"APS_DEMAND_ORDER",
"MATERIAL_INFO",
"ROUTING_HEADER",
"ROUTING_DETAIL",
"ROUTING_DETAIL_CONNECT",
"ROUTINGSUPPORTING",
"ROUTING_DETAIL_EQUIP",
"STOCK",
"MATERIAL_PURCHASE",
"ERP_PURCHASE_ORDER",
"PURCHASE_RECEIPT",
"SJZ_PF_WH_STOCK",
"PLAN_RESOURCE",
"EQUIPINFO",
"EQUIP_SHIFT_CAPACITY",
"APS_TIME_CONFIG"
));
@Override
public Expression getSqlSegment(Table table, Expression where, String mappedStatementId) {
if (!isSceneTable(table)) {
return null;
}
Column sceneColumn = new Column(columnPrefix(table) + ".MP_SCENE_ID");
String sceneId = MacroSceneContext.getSceneId();
if (sceneId == null) {
IsNullExpression isNull = new IsNullExpression();
isNull.setLeftExpression(sceneColumn);
return isNull;
}
return new EqualsTo(sceneColumn, new StringValue(sceneId));
}
private boolean isSceneTable(Table table) {
return table != null
&& table.getName() != null
&& SCENE_TABLES.contains(table.getName().toUpperCase(Locale.ROOT));
}
private String columnPrefix(Table table) {
if (table.getAlias() != null && table.getAlias().getName() != null) {
return table.getAlias().getName();
}
return table.getFullyQualifiedName();
}
}
package com.aps.macroplanner.scene;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
@Component
public class MacroSceneMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
String sceneId = MacroSceneContext.getSceneId();
if (sceneId != null && metaObject.hasSetter("mpSceneId")
&& getFieldValByName("mpSceneId", metaObject) == null) {
setFieldValByName("mpSceneId", sceneId, metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
// Scene ownership is immutable after insertion.
}
}
package com.aps.macroplanner.scene;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class MacroSceneRequestFilter extends OncePerRequestFilter {
public static final String HEADER_NAME = "X-MP-Scene-Id";
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String path = request.getRequestURI();
return path.startsWith("/lanuch")
|| path.startsWith("/schedule")
|| path.startsWith("/ganttest")
|| path.startsWith("/gantt")
|| path.startsWith("/Gantt");
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String sceneId = request.getHeader(HEADER_NAME);
if (sceneId == null || sceneId.trim().isEmpty()) {
sceneId = request.getParameter("mpSceneId");
}
if ((sceneId == null || sceneId.trim().isEmpty())
&& request.getRequestURI().startsWith("/macroResult")) {
sceneId = request.getParameter("sceneId");
}
try {
MacroSceneContext.setSceneId(sceneId);
filterChain.doFilter(request, response);
} finally {
MacroSceneContext.clear();
}
}
}
package com.aps.mapper;
import com.aps.entity.MacroSceneConfig;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface MacroSceneConfigMapper extends BaseMapper<MacroSceneConfig> {
}
package com.aps.mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface MacroSceneSequenceMapper {
@Select("SELECT SEQ_EQUIPINFOS.NEXTVAL FROM DUAL")
Integer nextEquipinfoId();
@Select("SELECT SEQ_EQUIPINFOS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Integer> nextEquipinfoIds(@Param("count") int count);
@Select("SELECT SEQ_PLAN_RESOURCES.NEXTVAL FROM DUAL")
Integer nextPlanResourceId();
@Select("SELECT SEQ_PLAN_RESOURCES.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Integer> nextPlanResourceIds(@Param("count") int count);
@Select("SELECT SEQ_ROUTING_HEADERS.NEXTVAL FROM DUAL")
Integer nextRoutingHeaderId();
@Select("SELECT SEQ_ROUTING_HEADERS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Integer> nextRoutingHeaderIds(@Param("count") int count);
@Select("SELECT SEQ_ROUTING_DETAILS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Long> nextRoutingDetailIds(@Param("count") int count);
@Select("SELECT SEQ_ROUTING_DETAILS.NEXTVAL FROM DUAL")
Long nextRoutingDetailId();
@Select("SELECT SEQ_ROUTINGSUPPORTINGS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Long> nextRoutingsupportingIds(@Param("count") int count);
@Select("SELECT SEQ_ROUTINGSUPPORTINGS.NEXTVAL FROM DUAL")
Long nextRoutingsupportingId();
@Select("SELECT SEQ_ROUTING_DETAIL_CONNECTS.NEXTVAL FROM DUAL")
Long nextRoutingDetailConnectId();
@Select("SELECT SEQ_ROUTING_DETAIL_CONNECTS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Long> nextRoutingDetailConnectIds(@Param("count") int count);
@Select("SELECT SEQ_ROUTING_DETAIL_EQUIPS.NEXTVAL FROM DUAL")
Integer nextRoutingDetailEquipId();
@Select("SELECT SEQ_ROUTING_DETAIL_EQUIPS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Integer> nextRoutingDetailEquipIds(@Param("count") int count);
@Select("SELECT SEQ_STOCKS.NEXTVAL FROM DUAL")
Long nextStockId();
@Select("SELECT SEQ_STOCKS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Long> nextStockIds(@Param("count") int count);
@Select("SELECT SEQ_MATERIAL_PURCHASES.NEXTVAL FROM DUAL")
Long nextMaterialPurchaseId();
@Select("SELECT SEQ_MATERIAL_PURCHASES.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Long> nextMaterialPurchaseIds(@Param("count") int count);
@Select("SELECT SEQ_ERP_PURCHASE_ORDERS.NEXTVAL FROM DUAL")
Long nextErpPurchaseOrderId();
@Select("SELECT SEQ_ERP_PURCHASE_ORDERS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Long> nextErpPurchaseOrderIds(@Param("count") int count);
@Select("SELECT SEQ_PURCHASE_RECEIPTS.NEXTVAL FROM DUAL")
Long nextPurchaseReceiptId();
@Select("SELECT SEQ_PURCHASE_RECEIPTS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Long> nextPurchaseReceiptIds(@Param("count") int count);
@Select("SELECT SEQ_SJZ_PF_WH_STOCKS.NEXTVAL FROM DUAL")
Long nextSjzPfWhStockId();
@Select("SELECT SEQ_SJZ_PF_WH_STOCKS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Long> nextSjzPfWhStockIds(@Param("count") int count);
@Select("SELECT SEQ_EQUIP_SHIFT_CAPACITYS.NEXTVAL FROM DUAL")
Long nextEquipShiftCapacityId();
@Select("SELECT SEQ_EQUIP_SHIFT_CAPACITYS.NEXTVAL FROM DUAL CONNECT BY LEVEL <= #{count}")
List<Long> nextEquipShiftCapacityIds(@Param("count") int count);
}
......@@ -814,6 +814,20 @@ public class LanuchServiceImpl implements LanuchService {
for (ProdLaunchOrder prodOrderMain : order) {
RoutingHeader routingHeader = routingHeaderMap.get(prodOrderMain.getRoutingId());
if (routingHeader == null) {
RoutingHeader fallbackRouting = resolveValidRoutingHeader(prodOrderMain);
if (fallbackRouting != null) {
log.warn("routing id {} is deleted, fallback to valid routing id {} by code {}",
prodOrderMain.getRoutingId(), fallbackRouting.getId(), prodOrderMain.getRoutingCode());
prodOrderMain.setRoutingId(fallbackRouting.getId());
routingHeader = fallbackRouting;
routingHeaderMap.put(fallbackRouting.getId(), fallbackRouting);
routingDetailsByHeaderId.put(fallbackRouting.getId().longValue(),
getRoutingDetails(fallbackRouting.getId()));
routingDetailEquipByHeaderId.put(fallbackRouting.getId().longValue(),
getRoutingDetailEquip(fallbackRouting.getId(), fallbackRouting.getCode()));
}
}
if (routingHeader == null) {
log.error("未找到对应工艺: {}", prodOrderMain.getRoutingId());
throw new RuntimeException("未找到对应工艺: " + prodOrderMain.getRoutingId());
......@@ -828,8 +842,9 @@ public class LanuchServiceImpl implements LanuchService {
List<RoutingDetailEquip> routingDetailEquip = routingDetailEquipByHeaderId.getOrDefault(
routingHeader.getId().longValue(),
Collections.emptyList());
final RoutingHeader currentRoutingHeader = routingHeader;
List<ProdProcessExec> processExecList = routingDetails.stream()
.map(detail -> createProcessExec(prodOrderMain, detail, sceneId, routingDetailEquip, routingHeader, equipTypeMap))
.map(detail -> createProcessExec(prodOrderMain, detail, sceneId, routingDetailEquip, currentRoutingHeader, equipTypeMap))
.collect(Collectors.toList());
allProcessExecList.addAll(processExecList);
......@@ -851,6 +866,21 @@ public class LanuchServiceImpl implements LanuchService {
log.info("完成{}个工单的工序转换",order.size());
}
private RoutingHeader resolveValidRoutingHeader(ProdLaunchOrder order) {
if (order == null || order.getRoutingCode() == null || order.getRoutingCode().trim().isEmpty()) {
return null;
}
LambdaQueryWrapper<RoutingHeader> wrapper = new LambdaQueryWrapper<RoutingHeader>()
.eq(RoutingHeader::getCode, order.getRoutingCode().trim())
.eq(RoutingHeader::getIsDeleted, 0);
if (order.getMaterialId() != null && !order.getMaterialId().trim().isEmpty()) {
wrapper.eq(RoutingHeader::getMaterialId, order.getMaterialId().trim());
}
return routingHeaderMapper.selectList(wrapper).stream()
.max(Comparator.comparing(RoutingHeader::getId))
.orElse(null);
}
/**
◦ 转换工单到工序执行表
......@@ -1611,8 +1641,9 @@ public class LanuchServiceImpl implements LanuchService {
Map<Integer, PlanResource> planResourceMap = list.stream()
.collect(Collectors.toMap(PlanResource::getId, Function.identity()));
Map<Integer, PlanResource> planResourceByReferenceIdMap = list.stream()
.filter(pr -> pr.getReferenceId() != null)
.collect(Collectors.toMap(PlanResource::getReferenceId, Function.identity()));
.filter(pr -> pr.getReferenceId() != null && "0".equals(pr.getType1()))
.collect(Collectors.toMap(PlanResource::getReferenceId, Function.identity(),
(left, right) -> left.getId() <= right.getId() ? left : right));
// 转换equipinfo为Map
Map<Integer, Equipinfo> equipinfoMap = equipinfo.stream()
......
......@@ -57,10 +57,12 @@
<result column="ISDELETED" property="isdeleted" />
<result column="DELETIONTIME" property="deletiontime" />
<result column="DELETERUSERID" property="deleteruserid" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
ID, SOURCE_TYPE, EXP1, EXP2, EXP3, EXP4, EXP5, EXP6, ZONEID, ZONE, CUSTOMERID, CUSTOMER, CODE, MMID, MMCODE, MMNAME, UNIT, QUANTITY, MEETQUANTITY, MEETGOAL, MEETRATE, PRICE, DELIVERYTIME, STOCKID, STOCK, PRIORITRY, SERIES, SERIES_ID, SERIES_NAME, ISINSERT, ISLOCK, PART, DELAY, SETTLE, ISCONSUME, REMARK, UNITID, BEGINTIME, ENDTIME, ROUTINGID, ROUTINGNAME, ROUTINGCODE, ROUTINGSTATUS, STATUS, SCHEDULESTATUS, IS_SCHEDULED, CREATIONTIME, CREATORUSERID, LASTMODIFICATIONTIME, LASTMODIFIERUSERID, ISDELETED, DELETIONTIME, DELETERUSERID
</sql>
......
......@@ -8,10 +8,12 @@
<result column="FREEZE_DATE" property="freezeDate" />
<result column="START_COUNT" property="startCount" />
<result column="END_COUNT" property="endCount" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
BASE_TIME, FREEZE_DATE, START_COUNT, END_COUNT
</sql>
......
......@@ -61,11 +61,13 @@
<result column="min_duration_time" property="minDurationTime" />
<result column="max_duration_time" property="maxDurationTime" />
<result column="jp_expecation_time" property="jpExpecationTime" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
id, shop_id, equip_id, equip_type, equip_name, equip_status, location, shaft_qty, capability_value, securityclassid, equip_ip, equipment_sc, operator_id, equip_version, equip_system, equip_pic, locationx, isimportant, filepath, equip_status_updatetime, hot, capacity, standard, usedepartment, installplace, mainnumber, manufacturer, enabledate, equip_winpwd, equip_winname, equip_port, status, property, creationtime, creatoruserid, lastmodificationtime, lastmodifieruserid, isdeleted, deleteruserid, deletiontime, head, runningstatus, system_info, ismdc, work_pattern, work_pattern_name, measure_unit_name, currency_type_name, capacity_type_name, measure_unit, currency_type, capacity_type, fequipid, min_time, min_duration_time, max_duration_time, jp_expecation_time
</sql>
</mapper>
\ No newline at end of file
</mapper>
......@@ -29,10 +29,12 @@
<result column="MANUFACTURER_CODE" property="manufacturerCode" />
<result column="MANUFACTURER_NAME" property="manufacturerName" />
<result column="ARRIVAL_DATE" property="arrivalDate" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
ID, CREATIONTIME, CREATORUSERID, LASTMODIFICATIONTIME, LASTMODIFIERUSERID, ISDELETED, DELETIONTIME, DELETERUSERID, PURCHASE_NO, MATERIAL_ID, MATERIAL_CODE, MATERIAL_NAME, WAREHOUSE_ID, WAREHOUSE_CODE, WAREHOUSE_NAME, PURCHASE_QTY, UNIT_ID, UNIT_NAME, PURCHASE_CYCLE, INSPECTION_CYCLE, PURCHASE_STATUS, MANUFACTURER_ID, MANUFACTURER_CODE, MANUFACTURER_NAME, ARRIVAL_DATE
</sql>
......
......@@ -101,11 +101,13 @@
<result column="min_production" property="minProduction" />
<result column="max_production" property="maxProduction" />
<result column="invisable" property="invisable" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
id, creationtime, creatoruserid, lastmodificationtime, lastmodifieruserid, isdeleted, deletiontime, deleteruserid, name, brand, specifications, batch, unit_price, min_num, tempcode, code, material_type_name, inspect_duration, purchase_duration, first_lot, tail_lot, standard_log, safe_stock_day, safe_stock_quantity, category_name, category_code, category_id, material_property, root_category_id, code_rule_id, code_rule_type, drawing, material_type, measure_unit, measure_unit_name, version, product_type, status, latest, iscreatesupplyrouting, iscreatecheckrouting, description, quintiq_ortems, isync, issend, measure_unit2, measure_unit_name2, linkmaterialid, measure_unit3, measure_unit_name3, zjltofjl1, supply_id, supply_name, supply_code, istrade, ser, iscommon, iscreatepoolrouting, variety, spec, category_id2, utility_material, special_product, bottle_type, bottle_type_str, max_inventory_day, max_inventory_quantity, min_inventory_day, min_inventory_quantity, minimum_supply, start_time, end_time, equip_id, bigpro, smallpro, isthree, is_minus, remark, match_bigpro_id, match_bigpro_code, match_smallpro_id, match_smallpro_code, full_name, is_include_store, is_average_four_week, stocksynctime, inventory_host_cost, beforeplanid, plannum, plancount, new_long_id, new_oldnumber, min_quantity, material_plan_type, min_production, max_production, invisable
</sql>
</mapper>
\ No newline at end of file
</mapper>
......@@ -32,11 +32,13 @@
<result column="isstop" property="isstop" />
<result column="stoptime" property="stoptime" />
<result column="stopendtime" property="stopendtime" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
id, title, code, type1, reference_id, depart_id, depart_title, isimportant, capability_value, creationtime, creatoruserid, lastmodificationtime, lastmodifieruserid, isdeleted, deletiontime, deleteruserid, cal_id, cal_name, holiday_cal_id, holiday_cal_name, reference_code, equip_type_id, equip_type, work_sched_id, nrofunitsopen, isstop, stoptime, stopendtime
</sql>
</mapper>
\ No newline at end of file
</mapper>
......@@ -45,10 +45,12 @@
<result column="SCDWBM" property="scdwbm" />
<result column="YLZD4" property="ylzd4" />
<result column="YLZD5" property="ylzd5" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
ID, CREATIONTIME, CREATORUSERID, LASTMODIFICATIONTIME, LASTMODIFIERUSERID, ISDELETED, DELETIONTIME, DELETERUSERID, WLBM, WLBB, ZJL_DW, ZJL_SL, FJL1_SL, SCPC, SCRQ, YXQZ, GYSBM, GYSMC, MBKF, JYBZ, ZT, SENDID, FJL1_DW, EXP1, EXP2, EXP3, EXP4, EXP5, EXP6, SUPPLYID, ORDERID, CHECKSTATUS, CHECKQUANTITY, RKSJ, RCBH, SCDW, MATERIALID, NOF, SCDWBM, YLZD4, YLZD5
</sql>
......
......@@ -22,10 +22,12 @@
<result column="EXP4" property="exp4" />
<result column="ROUTING_HEADER_ID" property="routingHeaderId" />
<result column="STR_ID" property="strId" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
ID, CREATIONTIME, CREATORUSERID, LASTMODIFICATIONTIME, LASTMODIFIERUSERID, ISDELETED, DELETIONTIME, DELETERUSERID, DESTOPERATIONID, SOURCEOPERATIONID, DESTOPERATION, SOURCEOPERATION, EXP1, EXP2, EXP3, EXP4, ROUTING_HEADER_ID, STR_ID
</sql>
......
......@@ -28,11 +28,13 @@
<result column="routing_header_id" property="routingHeaderId" />
<result column="one_batch_quantity" property="oneBatchQuantity" />
<result column="str_id" property="strId" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
id, creationtime, creatoruserid, lastmodificationtime, lastmodifieruserid, isdeleted, deletiontime, deleteruserid, type1, type_name, name, output_quantity, measure_unit, measure_unit_name, duration, exp1, exp2, exp3, exp4, routing_detail_id, equip_id, routing_header_id, one_batch_quantity, str_id
</sql>
</mapper>
\ No newline at end of file
</mapper>
......@@ -54,11 +54,13 @@
<result column="SINGLE_OUT_UNIT_NAME" property="singleOutUnitName" />
<result column="CONNECT_UNIT_ID" property="connectUnitId" />
<result column="CONNECT_UNIT_NAME" property="connectUnitName" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
ID, CREATION_TIME, CREATOR_USER_ID, LAST_MODIFICATION_TIME, LAST_MODIFIER_USER_ID, IS_DELETED, DELETER_USER_ID, DELETION_TIME, ROUTING_HEADER_ID, NAME, TASK_SEQ, RUNTIME, SETUP_TIME, EFFICIENCY_VALUE, SINGLE_OUT, IS_OUTSIDE, STATUS, REMARK, EXTEND, OUTSIDE_TIME, PERFORMANCE_HOURS, SCHEDULING_WORKING_HOURS, REAL_WORKING_HOURS, REAL_RUNTIME, PERFORMANCE_WORKING_HOURS, EQUIP_TYPE, EQUIP_TYPE_ID, CAN_INTERRUPT, PREVIOUS_START_TIME_BEGIN, CHANGE_LINE_TIME, PRE_DETAIL_ID, CONNECT_TYPE, CONNECT_PROPERTY, CONNECT_TYPE_NAME, CONNECT_PROPERTY_NAME, CONST_TIME,INCREMENT_QTY, BATCH_QTY, MIN_PRODUCTION_QTY, MAX_PRODUCTION_QTY, PRODUCTION_TAKT, PREPROCESSING_TIME, POSTPROCESSING_TIME, SPLIT_MIN_QTY, SPLIT_MAX_QTY, EQUIPMENT_CONNECTIVITY, SINGLE_OUT_UNIT_ID, SINGLE_OUT_UNIT_NAME, CONNECT_UNIT_ID, CONNECT_UNIT_NAME
</sql>
......
......@@ -64,11 +64,13 @@
<result column="material_plan_type" property="materialPlanType" />
<result column="pcost" property="pcost" />
<result column="invisable" property="invisable" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
id, creation_time, creator_user_id, last_modification_time, last_modifier_user_id, deleter_user_id, deletion_time, class_id, unicode, name, code, product_id, version, author, department_id, is_main, up_id, up_detail_id, routing_type, status, approval_status, remark, approval_status_remark, audit_user_id1, audit_user_id2, is_deleted, platesnum, is_effect, versionnotes, phase, versionid, is_send_ppm, file_id, product_name, department_name, drawing_no, product_bom_id, routing_changeorder_code, routing_changeheader_id, audit_user_id3, material_id, output_quantity, routing_type_name, lead_time, quintiq_ortems, iscreatecheckrouting, iscreateoutbom, issupportingstore, isync, routing_usetype, linkroutingid, effect_end, year, effect_begin, cost, erptag, createoutbomtime, material_plan_type, pcost, invisable
</sql>
</mapper>
\ No newline at end of file
</mapper>
......@@ -32,10 +32,12 @@
<result column="SPENT_MEASURE_UNIT_NAME" property="spentMeasureUnitName" />
<result column="STR_ID" property="strId" />
<result column="DRAW_NUM" property="drawNum" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
ID, CREATIONTIME, CREATORUSERID, LASTMODIFICATIONTIME, LASTMODIFIERUSERID, ISDELETED, DELETIONTIME, DELETERUSERID, ROUTING_HEADER_ID, ROUTING_DETAIL_ID, MATERIAL_ID, MATERIAL_TYPE, MATERIAL_NUMBER, MATERIAL_NAME, MATERIAL_VERSION, REMARK, STORE_ID, STORE_NAME, MAIN_QTY, SPENT_QTY, STR_MAIN_QTY, STR_SPENT_QTY, MAIN_MEASURE_UNIT, MAIN_MEASURE_UNIT_NAME, SPENT_MEASURE_UNIT, SPENT_MEASURE_UNIT_NAME, STR_ID, DRAW_NUM
</sql>
......
......@@ -38,10 +38,12 @@
<result column="IFSL" property="ifsl" />
<result column="CHECKSTATUS" property="checkstatus" />
<result column="CHECKQUANTITY" property="checkquantity" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
ID, CREATIONTIME, CREATORUSERID, LASTMODIFICATIONTIME, LASTMODIFIERUSERID, ISDELETED, DELETIONTIME, DELETERUSERID, WLBM, WLBB, ZJL_DW, ZJL_SL, FJL1_SL, SCPC, SCRQ, YXQZ, MBKF, ZT, SENDID, FJL1_DW, EXP1, EXP2, EXP3, EXP4, EXP5, EXP6, RKSJ, MATERIALID, JKDWBM, ROUTINGID, JKDWMC, IFSL, CHECKSTATUS, CHECKQUANTITY
</sql>
......
......@@ -34,10 +34,12 @@
<result column="SUPPLIER_NAME" property="supplierName" />
<result column="WAREHOUSING_UNIT_ID" property="warehousingUnitId" />
<result column="WAREHOUSING_UNIT_NAME" property="warehousingUnitName" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
MP_SCENE_ID,
ID, CREATIONTIME, CREATORUSERID, LASTMODIFICATIONTIME, LASTMODIFIERUSERID, ISDELETED, DELETIONTIME, DELETERUSERID, MATERIAL_ID, MATERIAL_CODE, MATERIAL_NAME, MATERIAL_VERSION, STORE_ID, STORE_CODE, STORE_NAME, TOTAL, MEASURE_UNIT, TOTAL_LOCK, COST, PRODUCTION_DATE, EXPIRY_DATE, WAREHOUSING_DATE, BATCH, CURRENCY_ID, CURRENCY_NAME, SUPPLIER_ID, SUPPLIER_CODE, SUPPLIER_NAME, WAREHOUSING_UNIT_ID, WAREHOUSING_UNIT_NAME
</sql>
......
package com.aps.demo;
import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Algorithm.GAScheduleResult;
import com.aps.entity.Algorithm.KpiMetrics;
import com.aps.entity.basic.Machine;
import com.aps.entity.basic.Order;
import com.aps.entity.basic.TimeSegment;
import com.aps.service.Algorithm.KpiCalculator;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* KpiCalculator类的单元测试
*/
public class KpiCalculatorTest {
private Chromosome chromosome;
private KpiCalculator kpiCalculator;
private LocalDateTime baseTime;
@Test
void testWithRealJsonFile() throws IOException {
// 从本地文件读取实际的染色体数据
String jsonFilePath = "result/chromosome_result_BED5A2136A45439CA18F08B5B953E1E5.json";
String jsonString = new String(Files.readAllBytes(Paths.get(jsonFilePath)));
// 使用FastJSON解析JSON字符串为Chromosome对象
Chromosome realChromosome = JSON.parseObject(jsonString, Chromosome.class);
// 使用实际的染色体数据创建KPI计算器
KpiCalculator realKpiCalculator = new KpiCalculator(realChromosome);
// 执行KPI计算
realKpiCalculator.calculatekpi();
// 验证计算后的KPI指标
assertNotNull(realChromosome.getKpiMetrics());
assertTrue(realChromosome.getKpiMetrics().size() > 0);
System.out.println("从真实JSON文件加载并计算KPI完成,共生成 " + realChromosome.getKpiMetrics().size() + " 个指标");
for (KpiMetrics kpi : realChromosome.getKpiMetrics()) {
System.out.println(kpi.getName() + ": " + kpi.getValue() + " - " + kpi.getTip());
}
System.out.println("wuqianyiwan="+5000/10000);
// 验证特定的KPI指标是否存在
List<KpiMetrics> kpiList = realChromosome.getKpiMetrics();
assertTrue(kpiList.stream().anyMatch(k -> k.getName().equals("最大设备利用率")));
assertTrue(kpiList.stream().anyMatch(k -> k.getName().equals("最小设备利用率")));
assertTrue(kpiList.stream().anyMatch(k -> k.getName().equals("订单按时完成率")));
assertTrue(kpiList.stream().anyMatch(k -> k.getName().equals("最大延迟")));
}
}
\ No newline at end of file
package com.aps.macroplanner.scene;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.schema.Table;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
class MacroSceneDataPermissionHandlerTest {
private final MacroSceneDataPermissionHandler handler =
new MacroSceneDataPermissionHandler();
@AfterEach
void clearContext() {
MacroSceneContext.clear();
}
@Test
void baselineQueriesOnlySeeRowsWithoutMacroScene() {
Table table = new Table("MATERIAL_INFO");
Expression expression = handler.getSqlSegment(table, null, "test.select");
assertEquals("MATERIAL_INFO.MP_SCENE_ID IS NULL", expression.toString());
}
@Test
void macroQueriesUseSelectedSceneAndTableAlias() {
MacroSceneContext.setSceneId("scene-001");
Table table = new Table("ROUTING_HEADER");
table.setAlias(new net.sf.jsqlparser.expression.Alias("rh"));
Expression expression = handler.getSqlSegment(table, null, "test.select");
assertEquals("rh.MP_SCENE_ID = \u0027scene-001\u0027", expression.toString());
}
@Test
void unrelatedTablesAreNotFiltered() {
Expression expression = handler.getSqlSegment(
new Table("PROD_SCENE_CONFIG"), null, "test.select");
assertNull(expression);
}
}
package com.aps.macroplanner.scene;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
class MacroSceneSqlInterceptorTest {
private final DataPermissionInterceptor interceptor =
new DataPermissionInterceptor(new MacroSceneDataPermissionHandler());
@AfterEach
void clearContext() {
MacroSceneContext.clear();
}
@Test
void injectsBaselineConditionIntoJoinQueries() {
String sql = interceptor.parserSingle(
"SELECT rh.ID FROM ROUTING_HEADER rh JOIN ROUTING_DETAIL rd "
+ "ON rd.ROUTING_HEADER_ID = rh.ID WHERE rh.STATUS = 1",
"test.select");
assertTrue(sql.contains("rh.MP_SCENE_ID IS NULL"));
assertTrue(sql.contains("rd.MP_SCENE_ID IS NULL"));
}
@Test
void injectsMacroConditionIntoUpdateAndDelete() {
MacroSceneContext.setSceneId("scene-002");
String updateSql = interceptor.parserSingle(
"UPDATE MATERIAL_INFO SET NAME = ? WHERE ID = ?", "test.update");
String deleteSql = interceptor.parserSingle(
"DELETE FROM STOCK WHERE ID = ?", "test.delete");
assertTrue(updateSql.contains("MATERIAL_INFO.MP_SCENE_ID = \u0027scene-002\u0027"));
assertTrue(deleteSql.contains("STOCK.MP_SCENE_ID = \u0027scene-002\u0027"));
}
}
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