feat: complete macro scene data copying

parent 18808dc2
......@@ -12,6 +12,7 @@ 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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
......@@ -47,6 +48,12 @@ public class MacroSceneController {
return R.ok(macroSceneService.listScenes());
}
@GetMapping("/current")
@Operation(summary = "根据用户查询当前主计划场景")
public R<MacroSceneConfig> current(@RequestParam String userId) {
return R.ok(macroSceneService.getSceneByUserId(userId));
}
@PostMapping("/select")
@Operation(summary = "选择当前主计划场景")
public R<Boolean> select(@RequestBody java.util.Map<String, String> request) {
......
......@@ -91,6 +91,8 @@ public class Equipinfo implements Serializable {
private String property;
private Integer equipProperty;
private LocalDate creationtime;
private Long creatoruserid;
......
......@@ -93,6 +93,14 @@ public class MaterialInfo implements Serializable {
private Integer purchaseDuration;
private Integer shelfLifeDays;
private Integer maturityPeriodDays;
private Short isTransferable;
private Short isExcluded;
private String firstLot;
private BigDecimal tailLot;
......@@ -215,6 +223,32 @@ public class MaterialInfo implements Serializable {
private String ser;
private String fixedMaterialId;
private String fixedMaterialName;
private String fixedMaterialCode;
private Short isByProduct;
@TableField("GROUPID")
private String groupId;
@TableField("GROUPNAME")
private String groupName;
@TableField("PARAMETERID")
private String parameterId;
@TableField("PARAMETERNAME")
private String parameterName;
private Long seriesId;
private String seriesName;
private Integer supplyType;
/**
* 是否共用?
*/
......
......@@ -23,17 +23,28 @@ public class RoutingDetail {
private BigDecimal deleterUserId;
private LocalDateTime deletionTime;
private Long routingHeaderId;
private Long classId;
private String name;
private String code;
private String description;
private String taskContent;
private Long taskSeq;
private BigDecimal runtime;
private BigDecimal setupTime;
private String strSetupTime;
private Short efficiencyValue;
private BigDecimal singleOut;
private Short isOutside;
private Short status;
private Long resourceId;
private Short resourceType;
private String resourceCode;
private String remark;
private String extend;
private Short outsideTime;
private BigDecimal transportTime;
private BigDecimal checkTime;
private Short checkFlag;
private Short performanceHours;
private Short schedulingWorkingHours;
private Short realWorkingHours;
......@@ -44,6 +55,22 @@ public class RoutingDetail {
private Long canInterrupt;
private Short previousStartTimeBegin;
private int changeLineTime;
private Long departmentId;
private Short isImportant;
private Long milestoneId;
private Long phaseId;
private Short isImportantResources;
private Short isParticipateIntime;
private String note;
private String fileId;
private Long measureUnit;
private String measureUnitName;
private BigDecimal afterProcessTime;
private Long isGeneral;
private Long canStartEarly;
private String tool;
private String usable;
private BigDecimal leadTime;
private Long preDetailId;
private Long connectType;
private Integer connectProperty;
......
......@@ -141,6 +141,14 @@ public class RoutingDetailEquip implements Serializable {
*/
private int setupTime;
private Short equipmentBearingType;
private BigDecimal equipmentBearingQty;
private Long outputUnitId;
private String outputUnitName;
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
private String mpSceneId;
}
......@@ -145,6 +145,22 @@ public class RoutingHeader implements Serializable {
private BigDecimal pcost;
private String specialFixedMaterialId;
private String specialFixedMaterialCode;
private String specialFixedMaterialName;
private String generalFixedMaterialId;
private String generalFixedMaterialCode;
private String generalFixedMaterialName;
private Long pcostUnitId;
private String pcostUnitName;
private Integer invisable;
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
......
......@@ -39,6 +39,9 @@ private Long mainMeasureUnit;
private String mainMeasureUnitName;
private Long spentMeasureUnit;
private String spentMeasureUnitName;
private Long supplyId;
private String supplyCode;
private String supplyName;
private String strId;
private String drawNum;
@TableField(value = "MP_SCENE_ID", fill = FieldFill.INSERT)
......
......@@ -30,6 +30,7 @@ private String storeCode;
private String storeName;
private double total;
private Integer measureUnit;
private String measureUnitName;
private double totalLock;
private BigDecimal cost;
private LocalDateTime productionDate;
......
......@@ -32,7 +32,30 @@ public class MacroSceneDataPermissionHandler implements MultiDataPermissionHandl
"EQUIPINFO",
"EQUIP_SHIFT_CAPACITY",
"APS_TIME_CONFIG",
"PLAN_PERIOD"
"PLAN_PERIOD",
"CATEGORY",
"STORE_ROOM_LOCATION",
"ROUTING_SUPPORTING_REPLACE",
"MES_DAILY_WORK_SCHED",
"MES_HOLIDAY",
"SPECIAL_CALENDAR",
"CLASS_CAPACITY",
"EQUIP_MAINTAIN_TASK",
"TOOL_RESOURCE",
"PRODUCT_INFO",
"DISCRETE_PARAMETER_GROUP",
"EQUIP_CONNECT",
"MFG_RESOURCE_STOCK",
"SERIES_CONFIG",
"STRATEGY_RULE",
"UNIT_MANAGEMENT",
"APS_FORCAST",
"APS_ORDER",
"IN_PROCESS_ORDER",
"ZJH_SCHEDULE_PLAN_ORDER_RESULT",
"CUSTOMER",
"SALES_AREA",
"SUPPLY"
));
@Override
......
......@@ -29,7 +29,11 @@ import java.sql.Types;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Set;
import java.util.List;
import java.util.Map;
import java.util.LinkedHashMap;
......@@ -48,6 +52,52 @@ public class MacroSceneService {
private static final int JDBC_BATCH_SIZE = 2000;
private static final int JSON_REMAP_BATCH_SIZE = 500;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final List<String> AUXILIARY_SCENE_TABLES = Arrays.asList(
"CATEGORY",
"STORE_ROOM_LOCATION",
"ROUTING_SUPPORTING_REPLACE",
"MES_DAILY_WORK_SCHED",
"MES_HOLIDAY",
"SPECIAL_CALENDAR",
"CLASS_CAPACITY",
"EQUIP_MAINTAIN_TASK",
"TOOL_RESOURCE",
"PRODUCT_INFO",
"DISCRETE_PARAMETER_GROUP",
"EQUIP_CONNECT",
"MFG_RESOURCE_STOCK",
"SERIES_CONFIG",
"STRATEGY_RULE",
"UNIT_MANAGEMENT",
"APS_FORCAST",
"APS_ORDER",
"IN_PROCESS_ORDER",
"ZJH_SCHEDULE_PLAN_ORDER_RESULT",
"CUSTOMER",
"SALES_AREA",
"SUPPLY"
);
private static final Map<String, String> AUXILIARY_SCENE_SEQUENCES = new HashMap<>();
static {
AUXILIARY_SCENE_SEQUENCES.put("CATEGORY", "SEQ_CATEGORYS");
AUXILIARY_SCENE_SEQUENCES.put("SUPPLY", "SEQ_SUPPLYS");
AUXILIARY_SCENE_SEQUENCES.put("STORE_ROOM_LOCATION", "SEQ_STORE_ROOM_LOCATIONS");
AUXILIARY_SCENE_SEQUENCES.put("ROUTING_SUPPORTING_REPLACE", "SEQ_ROUTING_SUPPORTING_REPLACES");
AUXILIARY_SCENE_SEQUENCES.put("MES_DAILY_WORK_SCHED", "SEQ_MES_DAILY_WORK_SCHEDS");
AUXILIARY_SCENE_SEQUENCES.put("MES_HOLIDAY", "SEQ_MES_HOLIDAYS");
AUXILIARY_SCENE_SEQUENCES.put("SPECIAL_CALENDAR", "SEQ_SPECIAL_CALENDARS");
AUXILIARY_SCENE_SEQUENCES.put("CLASS_CAPACITY", "SEQ_CLASS_CAPACITYS");
AUXILIARY_SCENE_SEQUENCES.put("EQUIP_MAINTAIN_TASK", "SEQ_EQUIP_MAINTAIN_TASKS");
AUXILIARY_SCENE_SEQUENCES.put("TOOL_RESOURCE", "SEQ_TOOL_RESOURCES");
AUXILIARY_SCENE_SEQUENCES.put("PRODUCT_INFO", "SEQ_PRODUCT_INFOS");
AUXILIARY_SCENE_SEQUENCES.put("MFG_RESOURCE_STOCK", "SEQ_MFG_RESOURCE_STOCKS");
AUXILIARY_SCENE_SEQUENCES.put("SERIES_CONFIG", "SEQ_SERIES_CONFIGS");
AUXILIARY_SCENE_SEQUENCES.put("STRATEGY_RULE", "SEQ_STRATEGY_RULES");
AUXILIARY_SCENE_SEQUENCES.put("UNIT_MANAGEMENT", "SEQ_UNIT_MANAGEMENTS");
AUXILIARY_SCENE_SEQUENCES.put("CUSTOMER", "SEQ_CUSTOMERS");
AUXILIARY_SCENE_SEQUENCES.put("SALES_AREA", "SEQ_SALES_AREAS");
}
private final DataSource dataSource;
private final MacroSceneMode sceneMode;
......@@ -86,6 +136,32 @@ public class MacroSceneService {
return sceneConfigMapper.selectById(requireText(sceneId, "sceneId"));
}
public MacroSceneConfig getSceneByUserId(String userId) {
String normalizedUserId = requireText(userId, "userId");
MacroSceneSelectionService.validateUserId(normalizedUserId);
if (sceneMode.isDefaultOnly()) {
return sceneMode.defaultScene();
}
for (MacroSceneConfig scene : sceneConfigMapper.selectList(null)) {
if (containsSelectedUser(scene.getSelectedUserIds(), normalizedUserId)) {
return scene;
}
}
return null;
}
private boolean containsSelectedUser(String selectedUserIds, String userId) {
if (selectedUserIds == null || selectedUserIds.trim().isEmpty()) {
return false;
}
for (String selectedUserId : selectedUserIds.split(",")) {
if (userId.equals(selectedUserId.trim())) {
return true;
}
}
return false;
}
public void selectScene(String sceneId, String userId) {
if (sceneMode.isDefaultOnly()) {
sceneMode.resolve(sceneId);
......@@ -130,7 +206,10 @@ public class MacroSceneService {
sceneConfigMapper.insert(config);
try {
// 新建空场景只保存场景配置;只有指定来源场景时才复制业务数据。
if (sourceSceneId != null) {
cloneSceneData(sourceSceneId, sceneId);
}
String selectedUsers = selectionService.completeAndSelect(sceneId, userId);
config.setSceneStatus("READY");
config.setUpdateTime(LocalDateTime.now());
......@@ -167,6 +246,7 @@ public class MacroSceneService {
private void cleanupSceneData(String sceneId) {
cleanupPispipResults(sceneId);
cleanupAuxiliarySceneTables(sceneId);
MacroSceneContext.execute(sceneId, () -> {
apsDemandOrderMapper.delete(null);
routingDetailEquipMapper.delete(null);
......@@ -201,16 +281,14 @@ public class MacroSceneService {
Map<Integer, Integer> resourceIds = copyPlanResources(sourceSceneId, targetSceneId, equipIds);
MaterialCopyResult materialCopy = copyMaterials(sourceSceneId, targetSceneId, equipIds, resourceIds);
Map<String, String> materialIds = materialCopy.idMap;
RoutingHeaderCopyResult routingCopy = copyRoutingHeaders(sourceSceneId, targetSceneId);
Map<Integer, Integer> routingIds = routingCopy.idMap;
RoutingDetailCopyResult detailCopy = copyRoutingDetails(sourceSceneId, targetSceneId, routingIds);
Map<Long, Long> detailIds = detailCopy.idMap;
Map<Integer, Integer> routingIds = copyRoutingHeaders(sourceSceneId, targetSceneId);
Map<Long, Long> detailIds = copyRoutingDetails(sourceSceneId, targetSceneId, routingIds);
copyRoutingsupporting(sourceSceneId, targetSceneId, materialIds, routingIds, detailIds);
copyRoutingConnections(sourceSceneId, targetSceneId, routingIds, detailIds);
copyRoutingEquipment(sourceSceneId, targetSceneId, routingIds, detailIds, resourceIds);
restoreRoutingDetailPredecessor(targetSceneId, detailCopy.sourceRows, detailIds);
restoreRoutingHeaderRelations(targetSceneId, routingCopy.sourceRows, routingIds, detailIds);
restoreRoutingHeaderRelations(targetSceneId);
restoreRoutingDetailPredecessor(targetSceneId);
restoreMaterialMatchRelations(targetSceneId, materialCopy.sourceRows, materialIds);
copyDemandOrders(sourceSceneId, targetSceneId, materialIds, routingIds);
copyStocksAndSupplies(sourceSceneId, targetSceneId, materialIds, routingIds);
......@@ -218,6 +296,296 @@ public class MacroSceneService {
copySimpleRows(sourceSceneId, targetSceneId, apsTimeConfigMapper, ApsTimeConfig.class, null);
copySimpleRows(sourceSceneId, targetSceneId, planPeriodMapper, PlanPeriod.class,
row -> row.setId(UUID.randomUUID().toString()));
copyAuxiliarySceneTables(sourceSceneId, targetSceneId);
remapAuxiliaryReferences(targetSceneId, materialIds, routingIds, equipIds);
}
/**
* Copies scene-enabled tables that do not have a project entity/mapper yet.
* Primary keys are regenerated where the database exposes a sequence; the
* remaining key types use a database-generated value or a collision-free
* numeric range for the new rows.
*/
private void copyAuxiliarySceneTables(String source, String target) {
for (String table : AUXILIARY_SCENE_TABLES) {
if ("CATEGORY".equals(table) || "SUPPLY".equals(table)) continue;
copyAuxiliarySceneTable(table, source, target);
}
Map<Integer, Integer> categoryIds = copyReferenceDictionary("CATEGORY", source, target);
Map<Integer, Integer> supplyIds = copyReferenceDictionary("SUPPLY", source, target);
remapAuxiliaryColumns(target, categoryIds, true,
"CATEGORY:UPID", "MATERIAL_INFO:CATEGORY_ID,ROOT_CATEGORY_ID");
remapAuxiliaryColumns(target, supplyIds, true,
"MATERIAL_PURCHASE:SUPPLY_ID", "PURCHASE_RECEIPT:SUPPLYID", "ROUTINGSUPPORTING:SUPPLY_ID");
Map<String, String> textSupplyIds = new HashMap<>();
supplyIds.forEach((oldId, newId) -> textSupplyIds.put(oldId.toString(), newId.toString()));
remapAuxiliaryColumns(target, textSupplyIds, false, "MATERIAL_INFO:SUPPLY_ID");
}
private Map<Integer, Integer> copyReferenceDictionary(String table, String source, String target) {
Connection connection = DataSourceUtils.getConnection(dataSource);
Map<Integer, Integer> idMap = new LinkedHashMap<>();
try {
List<String> columns = loadUserColumns(connection, table);
if (!containsIgnoreCase(columns, "MP_SCENE_ID")) {
throw new IllegalStateException("Missing MP_SCENE_ID: " + table);
}
String predicate = "NVL(ISDELETED, 0) = 0 AND "
+ (source == null ? "MP_SCENE_ID IS NULL" : "MP_SCENE_ID = ?");
String sequence = AUXILIARY_SCENE_SEQUENCES.get(table);
try (PreparedStatement keys = connection.prepareStatement(
"SELECT ID, " + sequence + ".NEXTVAL FROM " + table + " WHERE " + predicate)) {
keys.setFetchSize(JDBC_BATCH_SIZE);
if (source != null) keys.setString(1, source);
try (ResultSet rows = keys.executeQuery()) {
while (rows.next()) idMap.put(Math.toIntExact(rows.getLong(1)), Math.toIntExact(rows.getLong(2)));
}
}
List<String> insertColumns = new ArrayList<>();
List<String> selectValues = new ArrayList<>();
insertColumns.add("ID");
insertColumns.add("MP_SCENE_ID");
selectValues.add("?");
selectValues.add("?");
for (String column : columns) {
if ("ID".equalsIgnoreCase(column) || "MP_SCENE_ID".equalsIgnoreCase(column)) continue;
insertColumns.add(quoteIdentifier(column));
selectValues.add(quoteIdentifier(column));
}
String sql = "INSERT INTO " + table + " (" + String.join(",", insertColumns) + ") SELECT "
+ String.join(",", selectValues) + " FROM " + table + " WHERE ID = ? AND " + predicate;
try (PreparedStatement insert = connection.prepareStatement(sql)) {
int pending = 0;
for (Map.Entry<Integer, Integer> entry : idMap.entrySet()) {
insert.setInt(1, entry.getValue());
insert.setString(2, target);
insert.setInt(3, entry.getKey());
if (source != null) insert.setString(4, source);
insert.addBatch();
if (++pending == JDBC_BATCH_SIZE) {
insert.executeBatch();
insert.clearBatch();
pending = 0;
}
}
if (pending > 0) insert.executeBatch();
}
log.info("Macro scene dictionary copy: target={}, rows={}", table, idMap.size());
return idMap;
} catch (SQLException e) {
throw new IllegalStateException("Failed to copy scene dictionary " + table, e);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
}
private void copyAuxiliarySceneTable(String table, String source, String target) {
Connection connection = DataSourceUtils.getConnection(dataSource);
try {
List<String> columns = loadUserColumns(connection, table);
if (columns.isEmpty() || !containsIgnoreCase(columns, "MP_SCENE_ID")) {
throw new IllegalStateException("Auxiliary scene table missing MP_SCENE_ID: " + table);
}
Set<String> columnSet = new HashSet<>();
for (String column : columns) columnSet.add(column.toUpperCase(Locale.ROOT));
PrimaryKeyInfo primaryKey = loadPrimaryKey(connection, table);
String sequence = AUXILIARY_SCENE_SEQUENCES.get(table);
List<String> insertColumns = new ArrayList<>();
List<String> selectValues = new ArrayList<>();
for (String column : columns) {
if ("MP_SCENE_ID".equalsIgnoreCase(column)) continue;
insertColumns.add(quoteIdentifier(column));
if (primaryKey.isSingleColumn(column) && sequence != null) {
selectValues.add(sequence + ".NEXTVAL");
} else if (primaryKey.isSingleNumericColumn(column)) {
selectValues.add("(SELECT NVL(MAX(" + quoteIdentifier(column) + "), 0) FROM " + table
+ ") + ROW_NUMBER() OVER (ORDER BY src.ROWID)");
} else if (primaryKey.isSingleTextColumn(column)) {
selectValues.add("RAWTOHEX(SYS_GUID())");
} else {
selectValues.add("src." + quoteIdentifier(column));
}
}
insertColumns.add(quoteIdentifier("MP_SCENE_ID"));
selectValues.add("?");
String sourcePredicate = source == null
? "src." + quoteIdentifier("MP_SCENE_ID") + " IS NULL"
: "src." + quoteIdentifier("MP_SCENE_ID") + " = ?";
if (columnSet.contains("ISDELETED")) {
sourcePredicate += " AND NVL(src." + quoteIdentifier("ISDELETED") + ", 0) = 0";
}
if (columnSet.contains("IS_DELETED")) {
sourcePredicate += " AND NVL(src." + quoteIdentifier("IS_DELETED") + ", 0) = 0";
}
String sql = "INSERT INTO " + table + " (" + String.join(", ", insertColumns) + ") SELECT "
+ String.join(", ", selectValues) + " FROM " + table + " src WHERE " + sourcePredicate;
try (PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, target);
if (source != null) statement.setString(2, source);
int copiedRows = statement.executeUpdate();
log.info("Macro scene database copy: target={}, rows={}", table, copiedRows);
}
} catch (SQLException ex) {
throw new IllegalStateException("Failed to copy auxiliary scene table " + table, ex);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
}
private void cleanupAuxiliarySceneTables(String sceneId) {
List<String> reverse = new ArrayList<>(AUXILIARY_SCENE_TABLES);
Collections.reverse(reverse);
for (String table : reverse) {
jdbcTemplate.update("DELETE FROM " + table + " WHERE MP_SCENE_ID = ?", sceneId);
}
}
private void remapAuxiliaryReferences(String sceneId, Map<String, String> materialIds,
Map<Integer, Integer> routingIds, Map<Integer, Integer> equipIds) {
remapAuxiliaryColumns(sceneId, materialIds, false,
"PRODUCT_INFO:MATERIAL_ID,MAIN_MATERIAL_ID",
"CLASS_CAPACITY:MATERIALID",
"ROUTING_SUPPORTING_REPLACE:MATERIALID,TARGETMATERIALID",
"MFG_RESOURCE_STOCK:MATERIAL_ID",
"APS_ORDER:MMID",
"IN_PROCESS_ORDER:MMID");
remapAuxiliaryColumns(sceneId, routingIds, true,
"APS_ORDER:ROUTINGID",
"IN_PROCESS_ORDER:ROUTINGID");
remapAuxiliaryColumns(sceneId, equipIds, true,
"EQUIP_CONNECT:EQUIPID,GUIDEEQUIPID",
"EQUIP_MAINTAIN_TASK:EQUIP_ID");
}
private void remapAuxiliaryColumns(String sceneId, Map<?, ?> idMap, boolean numeric, String... targets) {
if (idMap.isEmpty()) return;
String dataType = numeric ? "NUMBER" : "VARCHAR2(128)";
Connection connection = DataSourceUtils.getConnection(dataSource);
try {
for (String target : targets) {
String[] parts = target.split(":");
String table = parts[0];
for (String column : parts[1].split(",")) {
List<Map<String, Object>> entries = new ArrayList<>();
try (PreparedStatement keys = connection.prepareStatement("SELECT DISTINCT " + column
+ " FROM " + table + " WHERE MP_SCENE_ID = ? AND " + column + " IS NOT NULL")) {
keys.setString(1, sceneId);
try (ResultSet rows = keys.executeQuery()) {
while (rows.next()) {
Object oldId = numeric ? rows.getInt(1) : rows.getString(1);
Object newId = idMap.get(oldId);
if (newId == null) continue;
Map<String, Object> pair = new HashMap<>();
pair.put("oldId", oldId);
pair.put("newId", newId);
entries.add(pair);
}
}
}
if (entries.isEmpty()) continue;
String sql = "MERGE INTO " + table + " dst USING (SELECT src.ID row_id, ids.NEW_ID "
+ "FROM " + table + " src JOIN JSON_TABLE(?, '$[*]' COLUMNS ("
+ "OLD_ID " + dataType + " PATH '$.oldId', NEW_ID " + dataType + " PATH '$.newId')) ids "
+ "ON (src." + column + " = ids.OLD_ID) WHERE src.MP_SCENE_ID = ?) mapped "
+ "ON (dst.ID = mapped.row_id AND dst.MP_SCENE_ID = ?) "
+ "WHEN MATCHED THEN UPDATE SET dst." + column + " = mapped.NEW_ID";
try (PreparedStatement statement = connection.prepareStatement(sql)) {
int updatedRows = 0;
for (int offset = 0; offset < entries.size(); offset += JSON_REMAP_BATCH_SIZE) {
String json = OBJECT_MAPPER.writeValueAsString(
entries.subList(offset, Math.min(offset + JSON_REMAP_BATCH_SIZE, entries.size())));
Clob clob = connection.createClob();
try {
clob.setString(1, json);
statement.setClob(1, clob);
statement.setString(2, sceneId);
statement.setString(3, sceneId);
updatedRows += statement.executeUpdate();
} finally {
clob.free();
}
}
log.info("Macro scene reference remap: target={}.{}, rows={}", table, column, updatedRows);
}
}
}
} catch (JsonProcessingException e) {
throw new IllegalStateException("Failed to serialize scene ID mapping", e);
} catch (SQLException e) {
throw new IllegalStateException("Failed to remap auxiliary scene references", e);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
}
private List<String> loadUserColumns(Connection connection, String table) throws SQLException {
List<String> columns = new ArrayList<>();
try (PreparedStatement statement = connection.prepareStatement(
"SELECT COLUMN_NAME FROM USER_TAB_COLUMNS WHERE TABLE_NAME = ? ORDER BY COLUMN_ID")) {
statement.setString(1, table);
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) columns.add(resultSet.getString(1));
}
}
return columns;
}
private PrimaryKeyInfo loadPrimaryKey(Connection connection, String table) throws SQLException {
PrimaryKeyInfo info = new PrimaryKeyInfo();
try (PreparedStatement statement = connection.prepareStatement(
"SELECT c.COLUMN_NAME, tc.DATA_TYPE FROM USER_CONS_COLUMNS c "
+ "JOIN USER_CONSTRAINTS u ON u.CONSTRAINT_NAME = c.CONSTRAINT_NAME "
+ "JOIN USER_TAB_COLUMNS tc ON tc.TABLE_NAME = c.TABLE_NAME AND tc.COLUMN_NAME = c.COLUMN_NAME "
+ "WHERE u.CONSTRAINT_TYPE = 'P' AND c.TABLE_NAME = ? ORDER BY c.POSITION")) {
statement.setString(1, table);
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
info.columns.add(resultSet.getString(1));
info.types.add(resultSet.getString(2));
}
}
}
// Some legacy tables declare an ID column but have no database primary-key constraint.
if (info.columns.isEmpty()) {
try (PreparedStatement statement = connection.prepareStatement(
"SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS WHERE TABLE_NAME = ? AND COLUMN_NAME = 'ID'")) {
statement.setString(1, table);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
info.columns.add(resultSet.getString(1));
info.types.add(resultSet.getString(2));
}
}
}
}
return info;
}
private boolean containsIgnoreCase(List<String> values, String expected) {
for (String value : values) if (expected.equalsIgnoreCase(value)) return true;
return false;
}
private String quoteIdentifier(String identifier) {
return "\"" + identifier.replace("\"", "\"\"") + "\"";
}
private static final class PrimaryKeyInfo {
private final List<String> columns = new ArrayList<>();
private final List<String> types = new ArrayList<>();
private boolean isSingleColumn(String column) {
return columns.size() == 1 && columns.get(0).equalsIgnoreCase(column);
}
private boolean isSingleNumericColumn(String column) {
return isSingleColumn(column) && "NUMBER".equalsIgnoreCase(types.get(0));
}
private boolean isSingleTextColumn(String column) {
return isSingleColumn(column) && ("NVARCHAR2".equalsIgnoreCase(types.get(0))
|| "VARCHAR2".equalsIgnoreCase(types.get(0)) || "CHAR".equalsIgnoreCase(types.get(0)));
}
}
private Map<Integer, Integer> copyEquipinfo(String source, String target) {
......@@ -265,11 +633,9 @@ public class MacroSceneService {
return new MaterialCopyResult(idMap, sourceRows);
}
private RoutingHeaderCopyResult copyRoutingHeaders(String source, String target) {
List<RoutingHeaderReference> sourceRows = loadRoutingHeaderReferences(source);
private Map<Integer, Integer> copyRoutingHeaders(String source, String target) {
copyRoutingHeadersInDatabase(source, target);
Map<Integer, Integer> idMap = loadRoutingHeaderIdMap(target);
return new RoutingHeaderCopyResult(idMap, sourceRows);
return loadRoutingHeaderIdMap(target);
}
private void copyMaterialsInDatabase(String source, String target,
......@@ -444,67 +810,6 @@ public class MacroSceneService {
}
}
private List<RoutingHeaderReference> loadRoutingHeaderReferences(String source) {
String predicate = source == null ? "MP_SCENE_ID IS NULL" : "MP_SCENE_ID = ?";
String sql = "SELECT ID, LINKROUTINGID, ROUTING_CHANGEHEADER_ID, UP_ID, UP_DETAIL_ID "
+ "FROM ROUTING_HEADER WHERE " + predicate;
List<RoutingHeaderReference> rows = new ArrayList<>();
Connection connection = DataSourceUtils.getConnection(dataSource);
try (PreparedStatement statement = connection.prepareStatement(sql)) {
if (source != null) {
statement.setString(1, source);
}
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
rows.add(new RoutingHeaderReference(resultSet.getInt("ID"),
getNullableInteger(resultSet, "LINKROUTINGID"),
getNullableInteger(resultSet, "ROUTING_CHANGEHEADER_ID"),
getNullableInteger(resultSet, "UP_ID"),
getNullableInteger(resultSet, "UP_DETAIL_ID")));
}
}
log.info("Macro scene reference rows: target=RoutingHeader, rows={}", rows.size());
return rows;
} catch (SQLException ex) {
throw new IllegalStateException("Failed to load RoutingHeader references", ex);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
}
private List<RoutingDetailReference> loadRoutingDetailReferences(String source) {
String predicate = source == null ? "MP_SCENE_ID IS NULL" : "MP_SCENE_ID = ?";
String sql = "SELECT ID, PRE_DETAIL_ID FROM ROUTING_DETAIL WHERE IS_DELETED = 0 AND " + predicate;
List<RoutingDetailReference> rows = new ArrayList<>();
Connection connection = DataSourceUtils.getConnection(dataSource);
try (PreparedStatement statement = connection.prepareStatement(sql)) {
if (source != null) {
statement.setString(1, source);
}
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
rows.add(new RoutingDetailReference(resultSet.getLong("ID"),
getNullableLong(resultSet, "PRE_DETAIL_ID")));
}
}
log.info("Macro scene reference rows: target=RoutingDetail, rows={}", rows.size());
return rows;
} catch (SQLException ex) {
throw new IllegalStateException("Failed to load RoutingDetail references", ex);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
}
private Integer getNullableInteger(ResultSet resultSet, String column) throws SQLException {
int value = resultSet.getInt(column);
return resultSet.wasNull() ? null : value;
}
private Long getNullableLong(ResultSet resultSet, String column) throws SQLException {
long value = resultSet.getLong(column);
return resultSet.wasNull() ? null : value;
}
private void remapRoutingHierarchy(String source, String target,
Map<Integer, Integer> routingIds,
......@@ -514,7 +819,7 @@ public class MacroSceneService {
jdbcBatchUpdateRoutingHierarchy(target, sourceRows, routingIds, detailIds);
}
private RoutingDetailCopyResult copyRoutingDetails(String source, String target,
private Map<Long, Long> copyRoutingDetails(String source, String target,
Map<Integer, Integer> routingIds) {
TableInfo tableInfo = TableInfoHelper.getTableInfo(RoutingDetail.class);
if (tableInfo == null) {
......@@ -565,9 +870,7 @@ public class MacroSceneService {
DataSourceUtils.releaseConnection(connection, dataSource);
}
Map<Long, Long> idMap = loadRoutingDetailIdMap(target, tableInfo.getTableName());
List<RoutingDetailReference> sourceRows = loadRoutingDetailReferences(source);
return new RoutingDetailCopyResult(idMap, sourceRows);
return loadRoutingDetailIdMap(target, tableInfo.getTableName());
}
private Map<Long, Long> loadRoutingDetailIdMap(String sceneId, String tableName) {
......@@ -589,43 +892,14 @@ public class MacroSceneService {
}
}
private void restoreRoutingDetailPredecessor(String target,
List<RoutingDetailReference> sourceRows,
Map<Long, Long> detailIds) {
String sql = "MERGE INTO ROUTING_DETAIL target_detail USING ("
+ "SELECT mapped.TARGET_ID, mapped.PRE_ID FROM JSON_TABLE(?, '$[*]' COLUMNS ("
+ "TARGET_ID NUMBER PATH '$.targetId', PRE_ID NUMBER PATH '$.preId')) mapped) source_map "
+ "ON (target_detail.ID = source_map.TARGET_ID AND target_detail.MP_SCENE_ID = ?) "
+ "WHEN MATCHED THEN UPDATE SET target_detail.PRE_DETAIL_ID = source_map.PRE_ID";
Connection connection = DataSourceUtils.getConnection(dataSource);
try (PreparedStatement statement = connection.prepareStatement(sql)) {
List<Map<String, Object>> batch = new ArrayList<>(JSON_REMAP_BATCH_SIZE);
int updatedRows = 0;
for (RoutingDetailReference row : sourceRows) {
Long copiedId = detailIds.get(row.id);
if (copiedId == null) {
continue;
}
Long copiedPredecessorId = row.preDetailId == null
? null : detailIds.get(row.preDetailId);
Map<String, Object> mapping = new LinkedHashMap<>();
mapping.put("targetId", copiedId);
mapping.put("preId", copiedPredecessorId);
batch.add(mapping);
if (batch.size() == JSON_REMAP_BATCH_SIZE) {
updatedRows += executeJsonMerge(statement, target, batch);
batch.clear();
}
}
if (!batch.isEmpty()) {
updatedRows += executeJsonMerge(statement, target, batch);
}
log.info("Macro scene JSON remap: target=RoutingDetailPredecessor, rows={}", updatedRows);
} catch (SQLException ex) {
throw new IllegalStateException("Failed to restore RoutingDetail predecessor", ex);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
private void restoreRoutingDetailPredecessor(String target) {
// PRE_DETAIL_ID holds the source row ID until all other copies have used the mapping.
String sql = "UPDATE ROUTING_DETAIL dst SET PRE_DETAIL_ID = ("
+ "SELECT mapped.ID FROM ROUTING_DETAIL src LEFT JOIN ROUTING_DETAIL mapped "
+ "ON mapped.MP_SCENE_ID = ? AND mapped.PRE_DETAIL_ID = src.PRE_DETAIL_ID "
+ "WHERE src.ID = dst.PRE_DETAIL_ID) WHERE dst.MP_SCENE_ID = ?";
int updatedRows = jdbcTemplate.update(sql, target, target);
log.info("Macro scene indexed remap: target=RoutingDetailPredecessor, rows={}", updatedRows);
}
private void restoreMaterialMatchRelations(String target, List<MaterialReference> sourceRows,
......@@ -672,50 +946,21 @@ public class MacroSceneService {
}
}
private void restoreRoutingHeaderRelations(String target, List<RoutingHeaderReference> sourceRows,
Map<Integer, Integer> routingIds,
Map<Long, Long> detailIds) {
String sql = "MERGE INTO ROUTING_HEADER target_header USING ("
+ "SELECT mapped.TARGET_ID, mapped.LINK_ID, mapped.CHANGE_ID, mapped.UP_ID, mapped.UP_DETAIL_ID "
+ "FROM JSON_TABLE(?, '$[*]' COLUMNS ("
+ "TARGET_ID NUMBER PATH '$.targetId', LINK_ID NUMBER PATH '$.linkId', "
+ "CHANGE_ID NUMBER PATH '$.changeId', UP_ID NUMBER PATH '$.upId', "
+ "UP_DETAIL_ID NUMBER PATH '$.upDetailId')) mapped) source_map "
+ "ON (target_header.ID = source_map.TARGET_ID AND target_header.MP_SCENE_ID = ?) "
+ "WHEN MATCHED THEN UPDATE SET target_header.LINKROUTINGID = source_map.LINK_ID, "
+ "target_header.ROUTING_CHANGEHEADER_ID = source_map.CHANGE_ID, "
+ "target_header.UP_ID = source_map.UP_ID, target_header.UP_DETAIL_ID = source_map.UP_DETAIL_ID";
Connection connection = DataSourceUtils.getConnection(dataSource);
try (PreparedStatement statement = connection.prepareStatement(sql)) {
List<Map<String, Object>> batch = new ArrayList<>(JSON_REMAP_BATCH_SIZE);
int updatedRows = 0;
for (RoutingHeaderReference row : sourceRows) {
Integer copiedId = routingIds.get(row.id);
if (copiedId == null) {
continue;
}
Map<String, Object> mapping = new LinkedHashMap<>();
mapping.put("targetId", copiedId);
mapping.put("linkId", remap(row.linkRoutingId, routingIds));
mapping.put("changeId", remap(row.routingChangeHeaderId, routingIds));
mapping.put("upId", remap(row.upId, routingIds));
mapping.put("upDetailId", row.upDetailId == null
? null : detailIds.get(row.upDetailId.longValue()));
batch.add(mapping);
if (batch.size() == JSON_REMAP_BATCH_SIZE) {
updatedRows += executeJsonMerge(statement, target, batch);
batch.clear();
}
}
if (!batch.isEmpty()) {
updatedRows += executeJsonMerge(statement, target, batch);
}
log.info("Macro scene JSON remap: target=RoutingHeaderRelations, rows={}", updatedRows);
} catch (SQLException ex) {
throw new IllegalStateException("Failed to restore RoutingHeader relations", ex);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
private void restoreRoutingHeaderRelations(String target) {
// UP_DETAIL_ID holds the source header ID; remap before the detail marker is replaced.
String sql = "UPDATE ROUTING_HEADER dst SET (LINKROUTINGID, ROUTING_CHANGEHEADER_ID, "
+ "UP_ID, UP_DETAIL_ID) = (SELECT "
+ "NVL((SELECT mapped.ID FROM ROUTING_HEADER mapped WHERE mapped.MP_SCENE_ID = ? "
+ "AND mapped.UP_DETAIL_ID = src.LINKROUTINGID), src.LINKROUTINGID), "
+ "NVL((SELECT mapped.ID FROM ROUTING_HEADER mapped WHERE mapped.MP_SCENE_ID = ? "
+ "AND mapped.UP_DETAIL_ID = src.ROUTING_CHANGEHEADER_ID), src.ROUTING_CHANGEHEADER_ID), "
+ "NVL((SELECT mapped.ID FROM ROUTING_HEADER mapped WHERE mapped.MP_SCENE_ID = ? "
+ "AND mapped.UP_DETAIL_ID = src.UP_ID), src.UP_ID), "
+ "(SELECT mapped.ID FROM ROUTING_DETAIL mapped WHERE mapped.MP_SCENE_ID = ? "
+ "AND mapped.PRE_DETAIL_ID = src.UP_DETAIL_ID) "
+ "FROM ROUTING_HEADER src WHERE src.ID = dst.UP_DETAIL_ID) WHERE dst.MP_SCENE_ID = ?";
int updatedRows = jdbcTemplate.update(sql, target, target, target, target, target);
log.info("Macro scene indexed remap: target=RoutingHeaderRelations, rows={}", updatedRows);
}
private int executeJsonMerge(PreparedStatement statement, String target,
......@@ -1389,25 +1634,6 @@ public class MacroSceneService {
}
}
private static final class RoutingDetailCopyResult {
private final Map<Long, Long> idMap;
private final List<RoutingDetailReference> sourceRows;
private RoutingDetailCopyResult(Map<Long, Long> idMap, List<RoutingDetailReference> sourceRows) {
this.idMap = idMap;
this.sourceRows = sourceRows;
}
}
private static final class RoutingHeaderCopyResult {
private final Map<Integer, Integer> idMap;
private final List<RoutingHeaderReference> sourceRows;
private RoutingHeaderCopyResult(Map<Integer, Integer> idMap, List<RoutingHeaderReference> sourceRows) {
this.idMap = idMap;
this.sourceRows = sourceRows;
}
}
private static final class MaterialReference {
private final String id;
......@@ -1424,33 +1650,6 @@ public class MacroSceneService {
}
}
private static final class RoutingHeaderReference {
private final Integer id;
private final Integer linkRoutingId;
private final Integer routingChangeHeaderId;
private final Integer upId;
private final Integer upDetailId;
private RoutingHeaderReference(Integer id, Integer linkRoutingId,
Integer routingChangeHeaderId, Integer upId,
Integer upDetailId) {
this.id = id;
this.linkRoutingId = linkRoutingId;
this.routingChangeHeaderId = routingChangeHeaderId;
this.upId = upId;
this.upDetailId = upDetailId;
}
}
private static final class RoutingDetailReference {
private final Long id;
private final Long preDetailId;
private RoutingDetailReference(Long id, Long preDetailId) {
this.id = id;
this.preDetailId = preDetailId;
}
}
private void requireGeneratedId(Object id, String table) {
if (id == null) {
......
-- Run manually on databases where SERIES_CONFIG still has the old unique constraint.
-- DDL commits implicitly; back up and check conflicting rows before execution.
DECLARE
v_columns VARCHAR2(4000);
BEGIN
SELECT LISTAGG(cc.COLUMN_NAME, ',') WITHIN GROUP (ORDER BY cc.POSITION)
INTO v_columns
FROM USER_CONSTRAINTS c
JOIN USER_CONS_COLUMNS cc ON cc.CONSTRAINT_NAME = c.CONSTRAINT_NAME
WHERE c.TABLE_NAME = 'SERIES_CONFIG'
AND c.CONSTRAINT_NAME = 'UK_SERIES_NAME';
IF v_columns IS NULL OR v_columns <> 'SERIES_NAME,ISDELETED,DELETIONTIME,MP_SCENE_ID' THEN
IF v_columns IS NOT NULL THEN
EXECUTE IMMEDIATE 'ALTER TABLE SERIES_CONFIG DROP CONSTRAINT UK_SERIES_NAME';
END IF;
EXECUTE IMMEDIATE 'ALTER TABLE SERIES_CONFIG ADD CONSTRAINT UK_SERIES_NAME '
|| 'UNIQUE (SERIES_NAME, ISDELETED, DELETIONTIME, MP_SCENE_ID)';
END IF;
END;
/
-- Add scene isolation to SUPPLY before enabling SUPPLY scene copying.
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = 'SUPPLY'
AND COLUMN_NAME = 'MP_SCENE_ID';
IF v_count = 0 THEN
EXECUTE IMMEDIATE 'ALTER TABLE SUPPLY ADD (MP_SCENE_ID NVARCHAR2(64))';
END IF;
END;
/
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count
FROM USER_INDEXES
WHERE INDEX_NAME = 'IDX_SUPPLY_MP_SCENE';
IF v_count = 0 THEN
EXECUTE IMMEDIATE 'CREATE INDEX IDX_SUPPLY_MP_SCENE ON SUPPLY (MP_SCENE_ID)';
END IF;
END;
/
......@@ -37,6 +37,7 @@
<result column="equip_port" property="equipPort" />
<result column="status" property="status" />
<result column="property" property="property" />
<result column="equip_property" property="equipProperty" />
<result column="creationtime" property="creationtime" />
<result column="creatoruserid" property="creatoruserid" />
<result column="lastmodificationtime" property="lastmodificationtime" />
......@@ -67,7 +68,7 @@
<!-- 通用查询结果列 -->
<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
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, equip_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>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aps.mapper.KpiCategoryItemMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aps.entity.KpiCategoryItem">
<id column="ID" property="id" />
<result column="CATEGORY_ID" property="categoryId" />
<result column="KPI_CODE" property="kpiCode" />
<result column="KPI_NAME" property="kpiName" />
<result column="WEIGHT" property="weight" />
<result column="SORT" property="sort" />
<result column="IS_DELETED" property="isDeleted" />
<result column="CREATION_TIME" property="creationTime" />
<result column="CREATOR_USER_ID" property="creatorUserId" />
<result column="LAST_MODIFICATION_TIME" property="lastModificationTime" />
<result column="LAST_MODIFIER_USER_ID" property="lastModifierUserId" />
<result column="DELETION_TIME" property="deletionTime" />
<result column="DELETER_USER_ID" property="deleterUserId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
ID, CATEGORY_ID, KPI_CODE, KPI_NAME, WEIGHT, SORT, IS_DELETED, CREATION_TIME, CREATOR_USER_ID, LAST_MODIFICATION_TIME, LAST_MODIFIER_USER_ID, DELETION_TIME, DELETER_USER_ID
</sql>
</mapper>
......@@ -23,6 +23,10 @@
<result column="material_type_name" property="materialTypeName" />
<result column="inspect_duration" property="inspectDuration" />
<result column="purchase_duration" property="purchaseDuration" />
<result column="shelf_life_days" property="shelfLifeDays" />
<result column="maturity_period_days" property="maturityPeriodDays" />
<result column="is_transferable" property="isTransferable" />
<result column="is_excluded" property="isExcluded" />
<result column="first_lot" property="firstLot" />
<result column="tail_lot" property="tailLot" />
<result column="standard_log" property="standardLog" />
......@@ -60,6 +64,17 @@
<result column="supply_code" property="supplyCode" />
<result column="istrade" property="istrade" />
<result column="ser" property="ser" />
<result column="fixed_material_id" property="fixedMaterialId" />
<result column="fixed_material_name" property="fixedMaterialName" />
<result column="fixed_material_code" property="fixedMaterialCode" />
<result column="is_by_product" property="isByProduct" />
<result column="GROUPID" property="groupId" />
<result column="GROUPNAME" property="groupName" />
<result column="PARAMETERID" property="parameterId" />
<result column="PARAMETERNAME" property="parameterName" />
<result column="series_id" property="seriesId" />
<result column="series_name" property="seriesName" />
<result column="supply_type" property="supplyType" />
<result column="iscommon" property="iscommon" />
<result column="iscreatepoolrouting" property="iscreatepoolrouting" />
<result column="variety" property="variety" />
......@@ -107,7 +122,7 @@
<!-- 通用查询结果列 -->
<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
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, shelf_life_days, maturity_period_days, is_transferable, is_excluded, 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, fixed_material_id, fixed_material_name, fixed_material_code, is_by_product, GROUPID, GROUPNAME, PARAMETERID, PARAMETERNAME, series_id, series_name, supply_type, 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>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aps.mapper.PlanPeriodMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aps.entity.PlanPeriod">
<id column="ID" property="id" />
<result column="CREATIONTIME" property="creationtime" />
<result column="CREATORUSERID" property="creatoruserid" />
<result column="LASTMODIFICATIONTIME" property="lastmodificationtime" />
<result column="LASTMODIFIERUSERID" property="lastmodifieruserid" />
<result column="ISDELETED" property="isdeleted" />
<result column="DELETIONTIME" property="deletiontime" />
<result column="DELETERUSERID" property="deleteruserid" />
<result column="EXP1" property="exp1" />
<result column="EXP2" property="exp2" />
<result column="EXP3" property="exp3" />
<result column="EXP4" property="exp4" />
<result column="EXP5" property="exp5" />
<result column="EXP6" property="exp6" />
<result column="NAME" property="name" />
<result column="TIMEUNITID" property="timeunitid" />
<result column="TIMEUNIT" property="timeunit" />
<result column="HISTORY" property="history" />
<result column="FUTURE" property="future" />
<result column="BEGIN" property="begin" />
<result column="END" property="end" />
<result column="ISPLAN" property="isplan" />
<result column="ISVISABLE" property="isvisable" />
<result column="TOP" property="top" />
<result column="BASETIME" property="basetime" />
<result column="ENABLED" property="enabled" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
ID, CREATIONTIME, CREATORUSERID, LASTMODIFICATIONTIME, LASTMODIFIERUSERID, ISDELETED, DELETIONTIME, DELETERUSERID, EXP1, EXP2, EXP3, EXP4, EXP5, EXP6, NAME, TIMEUNITID, TIMEUNIT, HISTORY, FUTURE, BEGIN, END, ISPLAN, ISVISABLE, TOP, BASETIME, ENABLED, MP_SCENE_ID
</sql>
</mapper>
......@@ -28,13 +28,19 @@
<result column="routing_header_id" property="routingHeaderId" />
<result column="one_batch_quantity" property="oneBatchQuantity" />
<result column="str_id" property="strId" />
<result column="efficiency_value" property="efficiencyValue" />
<result column="setup_time" property="setupTime" />
<result column="equipment_bearing_type" property="equipmentBearingType" />
<result column="equipment_bearing_qty" property="equipmentBearingQty" />
<result column="output_unit_id" property="outputUnitId" />
<result column="output_unit_name" property="outputUnitName" />
<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
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, efficiency_value, setup_time, equipment_bearing_type, equipment_bearing_qty, output_unit_id, output_unit_name
</sql>
</mapper>
......@@ -13,17 +13,28 @@
<result column="DELETER_USER_ID" property="deleterUserId" />
<result column="DELETION_TIME" property="deletionTime" />
<result column="ROUTING_HEADER_ID" property="routingHeaderId" />
<result column="CLASS_ID" property="classId" />
<result column="NAME" property="name" />
<result column="CODE" property="code" />
<result column="DESCRIPTION" property="description" />
<result column="TASK_CONTENT" property="taskContent" />
<result column="TASK_SEQ" property="taskSeq" />
<result column="RUNTIME" property="runtime" />
<result column="SETUP_TIME" property="setupTime" />
<result column="STR_SETUP_TIME" property="strSetupTime" />
<result column="EFFICIENCY_VALUE" property="efficiencyValue" />
<result column="SINGLE_OUT" property="singleOut" />
<result column="IS_OUTSIDE" property="isOutside" />
<result column="STATUS" property="status" />
<result column="RESOURCE_ID" property="resourceId" />
<result column="RESOURCE_TYPE" property="resourceType" />
<result column="RESOURCE_CODE" property="resourceCode" />
<result column="REMARK" property="remark" />
<result column="EXTEND" property="extend" />
<result column="OUTSIDE_TIME" property="outsideTime" />
<result column="TRANSPORT_TIME" property="transportTime" />
<result column="CHECK_TIME" property="checkTime" />
<result column="CHECK_FLAG" property="checkFlag" />
<result column="PERFORMANCE_HOURS" property="performanceHours" />
<result column="SCHEDULING_WORKING_HOURS" property="schedulingWorkingHours" />
<result column="REAL_WORKING_HOURS" property="realWorkingHours" />
......@@ -34,6 +45,22 @@
<result column="CAN_INTERRUPT" property="canInterrupt" />
<result column="PREVIOUS_START_TIME_BEGIN" property="previousStartTimeBegin" />
<result column="CHANGE_LINE_TIME" property="changeLineTime" />
<result column="DEPARTMENT_ID" property="departmentId" />
<result column="IS_IMPORTANT" property="isImportant" />
<result column="MILESTONE_ID" property="milestoneId" />
<result column="PHASE_ID" property="phaseId" />
<result column="IS_IMPORTANT_RESOURCES" property="isImportantResources" />
<result column="IS_PARTICIPATE_INTIME" property="isParticipateIntime" />
<result column="NOTE" property="note" />
<result column="FILE_ID" property="fileId" />
<result column="MEASURE_UNIT" property="measureUnit" />
<result column="MEASURE_UNIT_NAME" property="measureUnitName" />
<result column="AFTER_PROCESS_TIME" property="afterProcessTime" />
<result column="IS_GENERAL" property="isGeneral" />
<result column="CAN_START_EARLY" property="canStartEarly" />
<result column="TOOL" property="tool" />
<result column="USABLE" property="usable" />
<result column="LEAD_TIME" property="leadTime" />
<result column="PRE_DETAIL_ID" property="preDetailId" />
<result column="CONNECT_TYPE" property="connectType" />
<result column="CONNECT_PROPERTY" property="connectProperty" />
......@@ -61,7 +88,7 @@
<!-- 通用查询结果列 -->
<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
ID, CREATION_TIME, CREATOR_USER_ID, LAST_MODIFICATION_TIME, LAST_MODIFIER_USER_ID, IS_DELETED, DELETER_USER_ID, DELETION_TIME, ROUTING_HEADER_ID, CLASS_ID, NAME, CODE, DESCRIPTION, TASK_CONTENT, TASK_SEQ, RUNTIME, SETUP_TIME, STR_SETUP_TIME, EFFICIENCY_VALUE, SINGLE_OUT, IS_OUTSIDE, STATUS, RESOURCE_ID, RESOURCE_TYPE, RESOURCE_CODE, REMARK, EXTEND, OUTSIDE_TIME, TRANSPORT_TIME, CHECK_TIME, CHECK_FLAG, 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, DEPARTMENT_ID, IS_IMPORTANT, MILESTONE_ID, PHASE_ID, IS_IMPORTANT_RESOURCES, IS_PARTICIPATE_INTIME, NOTE, FILE_ID, MEASURE_UNIT, MEASURE_UNIT_NAME, AFTER_PROCESS_TIME, IS_GENERAL, CAN_START_EARLY, TOOL, USABLE, LEAD_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>
</mapper>
......@@ -63,6 +63,14 @@
<result column="createoutbomtime" property="createoutbomtime" />
<result column="material_plan_type" property="materialPlanType" />
<result column="pcost" property="pcost" />
<result column="special_fixed_material_id" property="specialFixedMaterialId" />
<result column="special_fixed_material_code" property="specialFixedMaterialCode" />
<result column="special_fixed_material_name" property="specialFixedMaterialName" />
<result column="general_fixed_material_id" property="generalFixedMaterialId" />
<result column="general_fixed_material_code" property="generalFixedMaterialCode" />
<result column="general_fixed_material_name" property="generalFixedMaterialName" />
<result column="pcost_unit_id" property="pcostUnitId" />
<result column="pcost_unit_name" property="pcostUnitName" />
<result column="invisable" property="invisable" />
<result column="MP_SCENE_ID" property="mpSceneId" />
</resultMap>
......@@ -70,7 +78,7 @@
<!-- 通用查询结果列 -->
<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
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, special_fixed_material_id, special_fixed_material_code, special_fixed_material_name, general_fixed_material_id, general_fixed_material_code, general_fixed_material_name, pcost_unit_id, pcost_unit_name, invisable
</sql>
</mapper>
......@@ -30,6 +30,9 @@
<result column="MAIN_MEASURE_UNIT_NAME" property="mainMeasureUnitName" />
<result column="SPENT_MEASURE_UNIT" property="spentMeasureUnit" />
<result column="SPENT_MEASURE_UNIT_NAME" property="spentMeasureUnitName" />
<result column="SUPPLY_ID" property="supplyId" />
<result column="SUPPLY_CODE" property="supplyCode" />
<result column="SUPPLY_NAME" property="supplyName" />
<result column="STR_ID" property="strId" />
<result column="DRAW_NUM" property="drawNum" />
<result column="MP_SCENE_ID" property="mpSceneId" />
......@@ -38,7 +41,7 @@
<!-- 通用查询结果列 -->
<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
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, SUPPLY_ID, SUPPLY_CODE, SUPPLY_NAME, STR_ID, DRAW_NUM
</sql>
</mapper>
......@@ -21,6 +21,7 @@
<result column="STORE_NAME" property="storeName" />
<result column="TOTAL" property="total" />
<result column="MEASURE_UNIT" property="measureUnit" />
<result column="MEASURE_UNIT_NAME" property="measureUnitName" />
<result column="TOTAL_LOCK" property="totalLock" />
<result column="COST" property="cost" />
<result column="PRODUCTION_DATE" property="productionDate" />
......@@ -40,7 +41,7 @@
<!-- 通用查询结果列 -->
<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
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, MEASURE_UNIT_NAME, 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>
</mapper>
package com.aps.demo;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
public class ImportProductRestTest {
@Test
public void importProduct() throws Exception {
String host = System.getProperty("quintiq.import.host", "localhost");
String port = System.getProperty("quintiq.import.port", "1234");
String url = "http://" + host + ":" + port + "/ImportProduct";
String requestBody = "{"
+ "\"Product\":["
+ "{"
+ "\"ProductId\":\"TEST_PRODUCT_001\","
+ "\"IsDelete\":false,"
+ "\"IsDiscrete\":true,"
+ "\"Name\":\"TEST_PRODUCT_001\","
+ "\"PieceWeight\":1.0,"
+ "\"Type\":\"TEST\","
+ "\"UoM\":\"pc\","
+ "\"ProductInStockingPoint\":["
+ "{"
+ "\"StockingPointId\":\"SLAB\","
+ "\"IsDelete\":false"
+ "}"
+ "]"
+ "}"
+ "]"
+ "}";
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("POST");
connection.setConnectTimeout(5000);
connection.setReadTimeout(15000);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
byte[] bytes = requestBody.getBytes(StandardCharsets.UTF_8);
connection.setFixedLengthStreamingMode(bytes.length);
try (OutputStream outputStream = connection.getOutputStream()) {
outputStream.write(bytes);
}
int statusCode = connection.getResponseCode();
String responseBody = readBody(connection, statusCode);
System.out.println("POST " + url);
System.out.println("HTTP " + statusCode);
System.out.println(responseBody);
if (statusCode < 200 || statusCode >= 300) {
throw new IllegalStateException("ImportProduct failed, HTTP " + statusCode + ": " + responseBody);
}
}
private String readBody(HttpURLConnection connection, int statusCode) throws Exception {
InputStream inputStream = statusCode >= 400 ? connection.getErrorStream() : connection.getInputStream();
if (inputStream == null) {
return "";
}
try (InputStream in = inputStream; ByteArrayOutputStream out = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
return new String(out.toByteArray(), StandardCharsets.UTF_8);
}
}
}
package com.aps.macroplanner.scene;
import com.aps.entity.MacroSceneConfig;
import com.aps.mapper.MacroSceneConfigMapper;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
class MacroSceneMultiModeTest {
@Test
void productionModeAllowsManagementAndPreservesSceneId() {
MacroSceneMode mode = new MacroSceneMode();
assertFalse(mode.isDefaultOnly());
assertDoesNotThrow(mode::requireSceneManagement);
assertEquals("scene-001", mode.resolve(" scene-001 "));
assertThrows(IllegalArgumentException.class, () -> mode.resolve(null));
assertNull(new MacroSceneMode(true).resolve("default"));
}
@Test
void listsRealScenesWithoutVirtualDefault() {
MacroSceneService service = mock(MacroSceneService.class, CALLS_REAL_METHODS);
MacroSceneConfigMapper mapper = mock(MacroSceneConfigMapper.class);
ReflectionTestUtils.setField(service, "sceneMode", new MacroSceneMode());
ReflectionTestUtils.setField(service, "sceneConfigMapper", mapper);
MacroSceneConfig scene = new MacroSceneConfig();
scene.setSceneId("scene-001");
when(mapper.selectList(null)).thenReturn(Collections.singletonList(scene));
assertSame(scene, service.listScenes().get(0));
when(mapper.selectList(null)).thenReturn(Collections.emptyList());
assertTrue(service.listScenes().isEmpty());
}
}
package com.aps.macroplanner.scene;
import com.aps.controller.PlanPeriodController;
import com.aps.entity.MacroSceneConfig;
import com.aps.entity.PlanPeriod;
import com.aps.mapper.PlanPeriodMapper;
import com.aps.service.PlanPeriodService;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
class PlanPeriodSceneTest {
@AfterEach
void clearContext() { MacroSceneContext.clear(); }
@Test
void createUsesSelectedSceneAndIgnoresPayloadOwnership() {
PlanPeriodService service = mock(PlanPeriodService.class);
MacroSceneService scenes = mock(MacroSceneService.class);
MacroSceneConfig config = new MacroSceneConfig();
config.setSceneId("scene-a");
config.setSceneStatus("READY");
when(scenes.getScene("scene-a")).thenReturn(config);
when(service.save(any())).thenAnswer(invocation -> {
assertEquals("scene-a", MacroSceneContext.getSceneId());
return true;
});
PlanPeriod period = new PlanPeriod();
period.setId("old-id");
period.setMpSceneId("wrong-scene");
new PlanPeriodController(service, scenes).create("scene-a", period);
assertEquals("scene-a", period.getMpSceneId());
assertNotEquals("old-id", period.getId());
assertEquals(Long.valueOf(0), period.getIsdeleted());
assertNull(MacroSceneContext.getSceneId());
}
@Test
void originalReadUsesNullScopeAndActiveFilter() {
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), "test"), PlanPeriod.class);
PlanPeriodService service = mock(PlanPeriodService.class);
when(service.list(any(Wrapper.class))).thenAnswer(invocation -> {
assertNull(MacroSceneContext.getSceneId());
Wrapper<?> query = invocation.getArgument(0);
assertTrue(query.getSqlSegment().toUpperCase().contains("ISDELETED"));
return Collections.emptyList();
});
assertTrue(new PlanPeriodController(service, mock(MacroSceneService.class)).list(null).getData().isEmpty());
verify(service).list(any(Wrapper.class));
}
@Test
void insertionFillAndCopyFilterIncludePlanPeriod() {
PlanPeriod period = new PlanPeriod();
MacroSceneContext.setSceneId("scene-b");
new MacroSceneMetaObjectHandler().insertFill(SystemMetaObject.forObject(period));
assertEquals("scene-b", period.getMpSceneId());
MacroSceneService scenes = mock(MacroSceneService.class, CALLS_REAL_METHODS);
PlanPeriodMapper mapper = mock(PlanPeriodMapper.class);
ReflectionTestUtils.setField(scenes, "planPeriodMapper", mapper);
assertEquals("ISDELETED", ReflectionTestUtils.invokeMethod(scenes, "deletedColumn", mapper));
}
}
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