Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
H
HYH.APSJ
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
佟礼
HYH.APSJ
Commits
b0e9cc4a
Commit
b0e9cc4a
authored
Sep 07, 2026
by
DESKTOP-VKRD9QF\Administration
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完善主计划场景隔离与排产兼容
parent
0babbc59
Show whitespace changes
Inline
Side-by-side
Showing
51 changed files
with
2600 additions
and
38 deletions
+2600
-38
MybatisPlusConfig.java
src/main/java/com/aps/config/MybatisPlusConfig.java
+19
-0
MacroSceneController.java
src/main/java/com/aps/controller/MacroSceneController.java
+52
-0
ApsDemandOrder.java
src/main/java/com/aps/entity/ApsDemandOrder.java
+9
-1
ApsTimeConfig.java
src/main/java/com/aps/entity/ApsTimeConfig.java
+5
-1
EquipShiftCapacity.java
src/main/java/com/aps/entity/EquipShiftCapacity.java
+8
-0
Equipinfo.java
src/main/java/com/aps/entity/Equipinfo.java
+6
-1
ErpPurchaseOrder.java
src/main/java/com/aps/entity/ErpPurchaseOrder.java
+9
-1
ResourceSummaryVO.java
src/main/java/com/aps/entity/Gantt/ResourceSummaryVO.java
+21
-0
ScheduledOrderVO.java
src/main/java/com/aps/entity/Gantt/ScheduledOrderVO.java
+34
-0
SupplyRelationItem.java
src/main/java/com/aps/entity/Gantt/SupplyRelationItem.java
+16
-0
SupplyRelationRequest.java
...main/java/com/aps/entity/Gantt/SupplyRelationRequest.java
+34
-0
MacroSceneConfig.java
src/main/java/com/aps/entity/MacroSceneConfig.java
+35
-0
MaterialInfo.java
src/main/java/com/aps/entity/MaterialInfo.java
+9
-1
MaterialPurchase.java
src/main/java/com/aps/entity/MaterialPurchase.java
+9
-1
PlanResource.java
src/main/java/com/aps/entity/PlanResource.java
+5
-0
PurchaseReceipt.java
src/main/java/com/aps/entity/PurchaseReceipt.java
+9
-1
RoutingDetail.java
src/main/java/com/aps/entity/RoutingDetail.java
+10
-1
RoutingDetailConnect.java
src/main/java/com/aps/entity/RoutingDetailConnect.java
+9
-1
RoutingDetailEquip.java
src/main/java/com/aps/entity/RoutingDetailEquip.java
+7
-2
RoutingHeader.java
src/main/java/com/aps/entity/RoutingHeader.java
+6
-1
Routingsupporting.java
src/main/java/com/aps/entity/Routingsupporting.java
+9
-1
SjzPfWhStock.java
src/main/java/com/aps/entity/SjzPfWhStock.java
+9
-1
Stock.java
src/main/java/com/aps/entity/Stock.java
+9
-1
MacroPlannerDataConverter.java
.../com/aps/macroplanner/data/MacroPlannerDataConverter.java
+10
-15
MacroSceneContext.java
...in/java/com/aps/macroplanner/scene/MacroSceneContext.java
+53
-0
MacroSceneCreateRequest.java
...a/com/aps/macroplanner/scene/MacroSceneCreateRequest.java
+19
-0
MacroSceneDataPermissionHandler.java
...s/macroplanner/scene/MacroSceneDataPermissionHandler.java
+65
-0
MacroSceneMetaObjectHandler.java
...m/aps/macroplanner/scene/MacroSceneMetaObjectHandler.java
+23
-0
MacroSceneRequestFilter.java
...a/com/aps/macroplanner/scene/MacroSceneRequestFilter.java
+45
-0
MacroSceneService.java
...in/java/com/aps/macroplanner/scene/MacroSceneService.java
+1436
-0
MacroSceneConfigMapper.java
src/main/java/com/aps/mapper/MacroSceneConfigMapper.java
+7
-0
MacroSceneSequenceMapper.java
src/main/java/com/aps/mapper/MacroSceneSequenceMapper.java
+77
-0
LanuchServiceImpl.java
src/main/java/com/aps/service/impl/LanuchServiceImpl.java
+34
-3
SceneInheritanceService.java
...ava/com/aps/service/schedule/SceneInheritanceService.java
+304
-0
ApsDemandOrderMapper.xml
src/main/resources/mapper/ApsDemandOrderMapper.xml
+2
-0
ApsTimeConfigMapper.xml
src/main/resources/mapper/ApsTimeConfigMapper.xml
+2
-0
EquipinfoMapper.xml
src/main/resources/mapper/EquipinfoMapper.xml
+3
-1
ErpPurchaseOrderMapper.xml
src/main/resources/mapper/ErpPurchaseOrderMapper.xml
+2
-0
MaterialInfoMapper.xml
src/main/resources/mapper/MaterialInfoMapper.xml
+3
-1
PlanResourceMapper.xml
src/main/resources/mapper/PlanResourceMapper.xml
+3
-1
PurchaseReceiptMapper.xml
src/main/resources/mapper/PurchaseReceiptMapper.xml
+2
-0
RoutingDetailConnectMapper.xml
src/main/resources/mapper/RoutingDetailConnectMapper.xml
+2
-0
RoutingDetailEquipMapper.xml
src/main/resources/mapper/RoutingDetailEquipMapper.xml
+3
-1
RoutingDetailMapper.xml
src/main/resources/mapper/RoutingDetailMapper.xml
+2
-0
RoutingHeaderMapper.xml
src/main/resources/mapper/RoutingHeaderMapper.xml
+3
-1
RoutingsupportingMapper.xml
src/main/resources/mapper/RoutingsupportingMapper.xml
+2
-0
SjzPfWhStockMapper.xml
src/main/resources/mapper/SjzPfWhStockMapper.xml
+2
-0
StockMapper.xml
src/main/resources/mapper/StockMapper.xml
+2
-0
KpiCalculatorTest.java
src/test/java/com/aps/demo/KpiCalculatorTest.java
+65
-0
MacroSceneDataPermissionHandlerTest.java
...croplanner/scene/MacroSceneDataPermissionHandlerTest.java
+48
-0
MacroSceneSqlInterceptorTest.java
.../aps/macroplanner/scene/MacroSceneSqlInterceptorTest.java
+42
-0
No files found.
src/main/java/com/aps/config/MybatisPlusConfig.java
0 → 100644
View file @
b0e9cc4a
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
;
}
}
src/main/java/com/aps/controller/MacroSceneController.java
0 → 100644
View file @
b0e9cc4a
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
);
}
}
src/main/java/com/aps/entity/ApsDemandOrder.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/ApsTimeConfig.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/EquipShiftCapacity.java
View file @
b0e9cc4a
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
;
}
src/main/java/com/aps/entity/Equipinfo.java
View file @
b0e9cc4a
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
;
}
src/main/java/com/aps/entity/ErpPurchaseOrder.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/Gantt/ResourceSummaryVO.java
0 → 100644
View file @
b0e9cc4a
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
;
}
src/main/java/com/aps/entity/Gantt/ScheduledOrderVO.java
0 → 100644
View file @
b0e9cc4a
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
src/main/java/com/aps/entity/Gantt/SupplyRelationItem.java
0 → 100644
View file @
b0e9cc4a
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
src/main/java/com/aps/entity/Gantt/SupplyRelationRequest.java
0 → 100644
View file @
b0e9cc4a
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
src/main/java/com/aps/entity/MacroSceneConfig.java
0 → 100644
View file @
b0e9cc4a
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
;
}
src/main/java/com/aps/entity/MaterialInfo.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/MaterialPurchase.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/PlanResource.java
View file @
b0e9cc4a
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
;
}
src/main/java/com/aps/entity/PurchaseReceipt.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/RoutingDetail.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/RoutingDetailConnect.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/RoutingDetailEquip.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/RoutingHeader.java
View file @
b0e9cc4a
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
;
}
src/main/java/com/aps/entity/Routingsupporting.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/SjzPfWhStock.java
View file @
b0e9cc4a
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
;
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/entity/Stock.java
View file @
b0e9cc4a
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
;
};
@TableField
(
value
=
"MP_SCENE_ID"
,
fill
=
FieldFill
.
INSERT
)
private
String
mpSceneId
;
}
src/main/java/com/aps/macroplanner/data/MacroPlannerDataConverter.java
View file @
b0e9cc4a
...
...
@@ -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
(
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
(
...
...
src/main/java/com/aps/macroplanner/scene/MacroSceneContext.java
0 → 100644
View file @
b0e9cc4a
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
();
}
}
src/main/java/com/aps/macroplanner/scene/MacroSceneCreateRequest.java
0 → 100644
View file @
b0e9cc4a
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
;
}
src/main/java/com/aps/macroplanner/scene/MacroSceneDataPermissionHandler.java
0 → 100644
View file @
b0e9cc4a
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
();
}
}
src/main/java/com/aps/macroplanner/scene/MacroSceneMetaObjectHandler.java
0 → 100644
View file @
b0e9cc4a
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.
}
}
src/main/java/com/aps/macroplanner/scene/MacroSceneRequestFilter.java
0 → 100644
View file @
b0e9cc4a
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
();
}
}
}
src/main/java/com/aps/macroplanner/scene/MacroSceneService.java
0 → 100644
View file @
b0e9cc4a
package
com
.
aps
.
macroplanner
.
scene
;
import
com.aps.entity.*
;
import
com.aps.mapper.*
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
com.baomidou.mybatisplus.core.metadata.TableFieldInfo
;
import
com.baomidou.mybatisplus.core.metadata.TableInfo
;
import
com.baomidou.mybatisplus.core.metadata.TableInfoHelper
;
import
lombok.RequiredArgsConstructor
;
import
org.springframework.beans.BeanUtils
;
import
org.springframework.beans.BeanWrapperImpl
;
import
org.springframework.jdbc.datasource.DataSourceUtils
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
lombok.extern.slf4j.Slf4j
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
javax.sql.DataSource
;
import
java.sql.Clob
;
import
java.sql.Connection
;
import
java.sql.DatabaseMetaData
;
import
java.sql.PreparedStatement
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.Types
;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.LinkedHashMap
;
import
java.util.UUID
;
import
java.util.function.Consumer
;
import
java.util.function.BiConsumer
;
import
java.util.function.Function
;
import
java.util.Locale
;
@Service
@RequiredArgsConstructor
@Slf4j
public
class
MacroSceneService
{
private
static
final
int
SCENE_COPY_PAGE_SIZE
=
2000
;
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
final
DataSource
dataSource
;
private
final
MacroSceneConfigMapper
sceneConfigMapper
;
private
final
MacroSceneSequenceMapper
sequenceMapper
;
private
final
ApsDemandOrderMapper
apsDemandOrderMapper
;
private
final
MaterialInfoMapper
materialInfoMapper
;
private
final
RoutingHeaderMapper
routingHeaderMapper
;
private
final
RoutingDetailMapper
routingDetailMapper
;
private
final
RoutingDetailConnectMapper
routingDetailConnectMapper
;
private
final
RoutingsupportingMapper
routingsupportingMapper
;
private
final
RoutingDetailEquipMapper
routingDetailEquipMapper
;
private
final
StockMapper
stockMapper
;
private
final
MaterialPurchaseMapper
materialPurchaseMapper
;
private
final
ErpPurchaseOrderMapper
erpPurchaseOrderMapper
;
private
final
PurchaseReceiptMapper
purchaseReceiptMapper
;
private
final
SjzPfWhStockMapper
sjzPfWhStockMapper
;
private
final
PlanResourceMapper
planResourceMapper
;
private
final
EquipinfoMapper
equipinfoMapper
;
private
final
EquipShiftCapacityMapper
equipShiftCapacityMapper
;
private
final
ApsTimeConfigMapper
apsTimeConfigMapper
;
public
List
<
MacroSceneConfig
>
listScenes
()
{
return
sceneConfigMapper
.
selectList
(
null
);
}
public
MacroSceneConfig
getScene
(
String
sceneId
)
{
return
sceneConfigMapper
.
selectById
(
requireText
(
sceneId
,
"sceneId"
));
}
public
synchronized
MacroSceneConfig
createScene
(
MacroSceneCreateRequest
request
)
{
long
createStartNanos
=
System
.
nanoTime
();
if
(
request
==
null
)
{
throw
new
IllegalArgumentException
(
"request cannot be null"
);
}
String
sceneName
=
requireText
(
request
.
getSceneName
(),
"sceneName"
);
String
userId
=
requireText
(
request
.
getUserId
(),
"userId"
);
String
sourceSceneId
=
normalize
(
request
.
getSourceSceneId
());
if
(
sourceSceneId
!=
null
&&
sceneConfigMapper
.
selectById
(
sourceSceneId
)
==
null
)
{
throw
new
IllegalArgumentException
(
"source macro scene does not exist: "
+
sourceSceneId
);
}
Long
duplicateCount
=
sceneConfigMapper
.
selectCount
(
new
com
.
baomidou
.
mybatisplus
.
core
.
conditions
.
query
.
LambdaQueryWrapper
<
MacroSceneConfig
>()
.
eq
(
MacroSceneConfig:
:
getSceneName
,
sceneName
));
if
(
duplicateCount
!=
null
&&
duplicateCount
>
0
)
{
throw
new
IllegalArgumentException
(
"macro scene name already exists: "
+
sceneName
);
}
String
sceneId
=
UUID
.
randomUUID
().
toString
();
LocalDateTime
now
=
LocalDateTime
.
now
();
MacroSceneConfig
config
=
new
MacroSceneConfig
();
config
.
setSceneId
(
sceneId
);
config
.
setSceneName
(
sceneName
);
config
.
setSceneDesc
(
request
.
getSceneDesc
());
config
.
setSourceSceneId
(
sourceSceneId
);
config
.
setSceneStatus
(
"COPYING"
);
config
.
setCreateUser
(
userId
);
config
.
setCreateTime
(
now
);
config
.
setUpdateUser
(
userId
);
config
.
setUpdateTime
(
now
);
sceneConfigMapper
.
insert
(
config
);
try
{
cloneSceneData
(
sourceSceneId
,
sceneId
);
config
.
setSceneStatus
(
"READY"
);
config
.
setUpdateTime
(
LocalDateTime
.
now
());
sceneConfigMapper
.
updateById
(
config
);
long
durationMs
=
elapsedMillis
(
createStartNanos
);
log
.
info
(
"主计划场景创建完成,场景ID:{},场景名称:{},耗时:{}毫秒"
,
sceneId
,
sceneName
,
durationMs
);
return
config
;
}
catch
(
RuntimeException
ex
)
{
log
.
error
(
"主计划场景创建失败,场景ID:{},场景名称:{},耗时:{}毫秒"
,
sceneId
,
sceneName
,
elapsedMillis
(
createStartNanos
),
ex
);
try
{
cleanupSceneData
(
sceneId
);
config
.
setSceneStatus
(
"FAILED"
);
config
.
setUpdateTime
(
LocalDateTime
.
now
());
sceneConfigMapper
.
updateById
(
config
);
}
catch
(
RuntimeException
cleanupEx
)
{
log
.
error
(
"Macro scene cleanup failed: sceneId={}"
,
sceneId
,
cleanupEx
);
}
throw
ex
;
}
}
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
deleteScene
(
String
sceneId
)
{
String
normalizedSceneId
=
requireText
(
sceneId
,
"sceneId"
);
if
(
sceneConfigMapper
.
selectById
(
normalizedSceneId
)
==
null
)
{
return
;
}
cleanupSceneData
(
normalizedSceneId
);
sceneConfigMapper
.
deleteById
(
normalizedSceneId
);
}
private
void
cleanupSceneData
(
String
sceneId
)
{
MacroSceneContext
.
execute
(
sceneId
,
()
->
{
apsDemandOrderMapper
.
delete
(
null
);
routingDetailEquipMapper
.
delete
(
null
);
routingDetailConnectMapper
.
delete
(
null
);
routingsupportingMapper
.
delete
(
null
);
routingDetailMapper
.
delete
(
null
);
routingHeaderMapper
.
delete
(
null
);
equipShiftCapacityMapper
.
delete
(
null
);
planResourceMapper
.
delete
(
null
);
equipinfoMapper
.
delete
(
null
);
stockMapper
.
delete
(
null
);
materialPurchaseMapper
.
delete
(
null
);
erpPurchaseOrderMapper
.
delete
(
null
);
purchaseReceiptMapper
.
delete
(
null
);
sjzPfWhStockMapper
.
delete
(
null
);
materialInfoMapper
.
delete
(
null
);
apsTimeConfigMapper
.
delete
(
null
);
});
}
private
void
cloneSceneData
(
String
sourceSceneId
,
String
targetSceneId
)
{
Map
<
Integer
,
Integer
>
equipIds
=
copyEquipinfo
(
sourceSceneId
,
targetSceneId
);
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
;
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
);
restoreMaterialMatchRelations
(
targetSceneId
,
materialCopy
.
sourceRows
,
materialIds
);
copyDemandOrders
(
sourceSceneId
,
targetSceneId
,
materialIds
,
routingIds
);
copyStocksAndSupplies
(
sourceSceneId
,
targetSceneId
,
materialIds
,
routingIds
);
copyEquipCapacity
(
sourceSceneId
,
targetSceneId
,
equipIds
,
resourceIds
);
copySimpleRows
(
sourceSceneId
,
targetSceneId
,
apsTimeConfigMapper
,
ApsTimeConfig
.
class
,
null
);
}
private
Map
<
Integer
,
Integer
>
copyEquipinfo
(
String
source
,
String
target
)
{
List
<
Equipinfo
>
sourceRows
=
loadRows
(
source
,
equipinfoMapper
);
List
<
Integer
>
newIds
=
sequenceMapper
.
nextEquipinfoIds
(
sourceRows
.
size
());
Map
<
Integer
,
Integer
>
idMap
=
new
HashMap
<>();
List
<
Equipinfo
>
copies
=
new
ArrayList
<>(
sourceRows
.
size
());
for
(
int
i
=
0
;
i
<
sourceRows
.
size
();
i
++)
{
Equipinfo
row
=
sourceRows
.
get
(
i
);
Integer
oldId
=
row
.
getId
();
Equipinfo
copy
=
copyOf
(
row
,
Equipinfo
.
class
);
copy
.
setId
(
newIds
.
get
(
i
));
idMap
.
put
(
oldId
,
copy
.
getId
());
copies
.
add
(
copy
);
}
batchInsert
(
target
,
equipinfoMapper
,
copies
);
return
idMap
;
}
private
Map
<
Integer
,
Integer
>
copyPlanResources
(
String
source
,
String
target
,
Map
<
Integer
,
Integer
>
equipIds
)
{
List
<
PlanResource
>
sourceRows
=
loadRows
(
source
,
planResourceMapper
);
List
<
Integer
>
newIds
=
sequenceMapper
.
nextPlanResourceIds
(
sourceRows
.
size
());
Map
<
Integer
,
Integer
>
idMap
=
new
HashMap
<>();
List
<
PlanResource
>
copies
=
new
ArrayList
<>(
sourceRows
.
size
());
for
(
int
i
=
0
;
i
<
sourceRows
.
size
();
i
++)
{
PlanResource
row
=
sourceRows
.
get
(
i
);
Integer
oldId
=
row
.
getId
();
PlanResource
copy
=
copyOf
(
row
,
PlanResource
.
class
);
copy
.
setId
(
newIds
.
get
(
i
));
copy
.
setReferenceId
(
remap
(
row
.
getReferenceId
(),
equipIds
));
idMap
.
put
(
oldId
,
copy
.
getId
());
copies
.
add
(
copy
);
}
batchInsert
(
target
,
planResourceMapper
,
copies
);
return
idMap
;
}
private
MaterialCopyResult
copyMaterials
(
String
source
,
String
target
,
Map
<
Integer
,
Integer
>
equipIds
,
Map
<
Integer
,
Integer
>
resourceIds
)
{
List
<
MaterialReference
>
sourceRows
=
loadMaterialReferences
(
source
);
copyMaterialsInDatabase
(
source
,
target
,
equipIds
,
resourceIds
);
Map
<
String
,
String
>
idMap
=
loadMaterialIdMap
(
target
);
return
new
MaterialCopyResult
(
idMap
,
sourceRows
);
}
private
RoutingHeaderCopyResult
copyRoutingHeaders
(
String
source
,
String
target
)
{
List
<
RoutingHeaderReference
>
sourceRows
=
loadRoutingHeaderReferences
(
source
);
copyRoutingHeadersInDatabase
(
source
,
target
);
Map
<
Integer
,
Integer
>
idMap
=
loadRoutingHeaderIdMap
(
target
);
return
new
RoutingHeaderCopyResult
(
idMap
,
sourceRows
);
}
private
void
copyMaterialsInDatabase
(
String
source
,
String
target
,
Map
<
Integer
,
Integer
>
equipIds
,
Map
<
Integer
,
Integer
>
resourceIds
)
{
TableInfo
tableInfo
=
requiredTableInfo
(
MaterialInfo
.
class
);
List
<
String
>
columns
=
new
ArrayList
<>();
List
<
String
>
values
=
new
ArrayList
<>();
columns
.
add
(
tableInfo
.
getKeyColumn
());
values
.
add
(
"LOWER(REGEXP_REPLACE(RAWTOHEX(SYS_GUID()), "
+
"'(.{8})(.{4})(.{4})(.{4})(.{12})', '\\1-\\2-\\3-\\4-\\5'))"
);
for
(
TableFieldInfo
field
:
tableInfo
.
getFieldList
())
{
String
column
=
field
.
getColumn
();
if
(
"MP_SCENE_ID"
.
equalsIgnoreCase
(
column
))
{
continue
;
}
columns
.
add
(
column
);
if
(
"MATCH_BIGPRO_ID"
.
equalsIgnoreCase
(
column
))
{
values
.
add
(
"src.ID"
);
}
else
if
(
"MATCH_SMALLPRO_ID"
.
equalsIgnoreCase
(
column
))
{
values
.
add
(
"NULL"
);
}
else
if
(
"EQUIP_ID"
.
equalsIgnoreCase
(
column
))
{
values
.
add
(
"NVL(resource_map.NEW_ID, NVL(equip_map.NEW_ID, src.EQUIP_ID))"
);
}
else
{
values
.
add
(
"src."
+
column
);
}
}
columns
.
add
(
"MP_SCENE_ID"
);
values
.
add
(
"?"
);
List
<
Long
>
parameters
=
new
ArrayList
<>();
String
equipMapSql
=
mapCte
(
"equip_map"
,
equipIds
,
parameters
);
String
resourceMapSql
=
mapCte
(
"resource_map"
,
resourceIds
,
parameters
);
String
sourcePredicate
=
source
==
null
?
"src.MP_SCENE_ID IS NULL"
:
"src.MP_SCENE_ID = ?"
;
String
sql
=
"INSERT INTO "
+
tableInfo
.
getTableName
()
+
" ("
+
String
.
join
(
", "
,
columns
)
+
") "
+
"WITH "
+
equipMapSql
+
", "
+
resourceMapSql
+
" "
+
"SELECT "
+
String
.
join
(
", "
,
values
)
+
" FROM "
+
tableInfo
.
getTableName
()
+
" src "
+
"LEFT JOIN equip_map ON equip_map.OLD_ID = src.EQUIP_ID "
+
"LEFT JOIN resource_map ON resource_map.OLD_ID = src.EQUIP_ID "
+
"WHERE src.ISDELETED = 0 AND "
+
sourcePredicate
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
int
index
=
1
;
for
(
Long
parameter
:
parameters
)
{
statement
.
setLong
(
index
++,
parameter
);
}
statement
.
setString
(
index
++,
target
);
if
(
source
!=
null
)
{
statement
.
setString
(
index
,
source
);
}
int
copiedRows
=
statement
.
executeUpdate
();
log
.
info
(
"Macro scene database copy: target=MaterialInfo, rows={}"
,
copiedRows
);
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Failed to copy MaterialInfo in database"
,
ex
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
private
long
elapsedMillis
(
long
startNanos
)
{
return
java
.
util
.
concurrent
.
TimeUnit
.
NANOSECONDS
.
toMillis
(
System
.
nanoTime
()
-
startNanos
);
}
private
Map
<
String
,
String
>
loadMaterialIdMap
(
String
target
)
{
Map
<
String
,
String
>
idMap
=
new
HashMap
<>();
String
sql
=
"SELECT ID, MATCH_BIGPRO_ID FROM MATERIAL_INFO WHERE MP_SCENE_ID = ?"
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
statement
.
setString
(
1
,
target
);
try
(
ResultSet
resultSet
=
statement
.
executeQuery
())
{
while
(
resultSet
.
next
())
{
idMap
.
put
(
resultSet
.
getString
(
"MATCH_BIGPRO_ID"
),
resultSet
.
getString
(
"ID"
));
}
}
return
idMap
;
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Failed to load MaterialInfo ID mapping"
,
ex
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
private
void
copyRoutingHeadersInDatabase
(
String
source
,
String
target
)
{
TableInfo
tableInfo
=
requiredTableInfo
(
RoutingHeader
.
class
);
List
<
String
>
columns
=
new
ArrayList
<>();
List
<
String
>
values
=
new
ArrayList
<>();
columns
.
add
(
tableInfo
.
getKeyColumn
());
values
.
add
(
"SEQ_ROUTING_HEADERS.NEXTVAL"
);
for
(
TableFieldInfo
field
:
tableInfo
.
getFieldList
())
{
String
column
=
field
.
getColumn
();
if
(
"MP_SCENE_ID"
.
equalsIgnoreCase
(
column
))
{
continue
;
}
columns
.
add
(
column
);
if
(
"UP_DETAIL_ID"
.
equalsIgnoreCase
(
column
))
{
values
.
add
(
"src.ID"
);
}
else
if
(
"MATERIAL_ID"
.
equalsIgnoreCase
(
column
))
{
values
.
add
(
"NVL(target_material.ID, src.MATERIAL_ID)"
);
}
else
{
values
.
add
(
"src."
+
column
);
}
}
columns
.
add
(
"MP_SCENE_ID"
);
values
.
add
(
"?"
);
String
sourcePredicate
=
source
==
null
?
"src.MP_SCENE_ID IS NULL"
:
"src.MP_SCENE_ID = ?"
;
String
sql
=
"INSERT INTO "
+
tableInfo
.
getTableName
()
+
" ("
+
String
.
join
(
", "
,
columns
)
+
") "
+
"SELECT "
+
String
.
join
(
", "
,
values
)
+
" FROM "
+
tableInfo
.
getTableName
()
+
" src "
+
"LEFT JOIN MATERIAL_INFO target_material ON target_material.MP_SCENE_ID = ? "
+
"AND target_material.MATCH_BIGPRO_ID = src.MATERIAL_ID WHERE "
+
sourcePredicate
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
int
index
=
1
;
statement
.
setString
(
index
++,
target
);
statement
.
setString
(
index
++,
target
);
if
(
source
!=
null
)
{
statement
.
setString
(
index
,
source
);
}
int
copiedRows
=
statement
.
executeUpdate
();
log
.
info
(
"Macro scene database copy: target=RoutingHeader, rows={}"
,
copiedRows
);
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Failed to copy RoutingHeader in database"
,
ex
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
private
Map
<
Integer
,
Integer
>
loadRoutingHeaderIdMap
(
String
target
)
{
Map
<
Integer
,
Integer
>
idMap
=
new
HashMap
<>();
String
sql
=
"SELECT ID, UP_DETAIL_ID FROM ROUTING_HEADER WHERE MP_SCENE_ID = ?"
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
statement
.
setString
(
1
,
target
);
try
(
ResultSet
resultSet
=
statement
.
executeQuery
())
{
while
(
resultSet
.
next
())
{
idMap
.
put
(
resultSet
.
getInt
(
"UP_DETAIL_ID"
),
resultSet
.
getInt
(
"ID"
));
}
}
return
idMap
;
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Failed to load RoutingHeader ID mapping"
,
ex
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
private
List
<
MaterialReference
>
loadMaterialReferences
(
String
source
)
{
String
predicate
=
source
==
null
?
"MP_SCENE_ID IS NULL"
:
"MP_SCENE_ID = ?"
;
String
sql
=
"SELECT ID, LINKMATERIALID, MATCH_BIGPRO_ID, MATCH_SMALLPRO_ID FROM MATERIAL_INFO "
+
"WHERE ISDELETED = 0 AND "
+
predicate
;
List
<
MaterialReference
>
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
MaterialReference
(
resultSet
.
getString
(
"ID"
),
resultSet
.
getString
(
"LINKMATERIALID"
),
resultSet
.
getString
(
"MATCH_BIGPRO_ID"
),
resultSet
.
getString
(
"MATCH_SMALLPRO_ID"
)));
}
}
log
.
info
(
"Macro scene reference rows: target=MaterialInfo, rows={}"
,
rows
.
size
());
return
rows
;
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Failed to load MaterialInfo references"
,
ex
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
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
,
Map
<
Long
,
Long
>
detailIds
)
{
List
<
RoutingHeader
>
sourceRows
=
loadRows
(
source
,
routingHeaderMapper
);
jdbcClearRoutingHierarchyMarker
(
target
);
jdbcBatchUpdateRoutingHierarchy
(
target
,
sourceRows
,
routingIds
,
detailIds
);
}
private
RoutingDetailCopyResult
copyRoutingDetails
(
String
source
,
String
target
,
Map
<
Integer
,
Integer
>
routingIds
)
{
TableInfo
tableInfo
=
TableInfoHelper
.
getTableInfo
(
RoutingDetail
.
class
);
if
(
tableInfo
==
null
)
{
throw
new
IllegalStateException
(
"No MyBatis-Plus table metadata for RoutingDetail"
);
}
List
<
String
>
columns
=
new
ArrayList
<>();
List
<
String
>
values
=
new
ArrayList
<>();
columns
.
add
(
tableInfo
.
getKeyColumn
());
values
.
add
(
"SEQ_ROUTING_DETAILS.NEXTVAL"
);
for
(
TableFieldInfo
field
:
tableInfo
.
getFieldList
())
{
if
(
"MP_SCENE_ID"
.
equalsIgnoreCase
(
field
.
getColumn
()))
{
continue
;
}
columns
.
add
(
field
.
getColumn
());
if
(
"ROUTING_HEADER_ID"
.
equalsIgnoreCase
(
field
.
getColumn
()))
{
values
.
add
(
"NVL(target_header.ID, src.ROUTING_HEADER_ID)"
);
}
else
if
(
"PRE_DETAIL_ID"
.
equalsIgnoreCase
(
field
.
getColumn
()))
{
// Keep the original row ID briefly so the old/new map can be read without a helper table.
values
.
add
(
"src.ID"
);
}
else
{
values
.
add
(
"src."
+
field
.
getColumn
());
}
}
columns
.
add
(
"MP_SCENE_ID"
);
values
.
add
(
"?"
);
String
sourcePredicate
=
source
==
null
?
"src.MP_SCENE_ID IS NULL"
:
"src.MP_SCENE_ID = ?"
;
String
sql
=
"INSERT INTO "
+
tableInfo
.
getTableName
()
+
" ("
+
String
.
join
(
", "
,
columns
)
+
") "
+
"SELECT "
+
String
.
join
(
", "
,
values
)
+
" FROM "
+
tableInfo
.
getTableName
()
+
" src "
+
"LEFT JOIN ROUTING_HEADER target_header ON target_header.MP_SCENE_ID = ? "
+
"AND target_header.UP_DETAIL_ID = src.ROUTING_HEADER_ID "
+
"WHERE src.IS_DELETED = 0 AND "
+
sourcePredicate
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
int
index
=
1
;
statement
.
setString
(
index
++,
target
);
statement
.
setString
(
index
++,
target
);
if
(
source
!=
null
)
{
statement
.
setString
(
index
,
source
);
}
int
copiedRows
=
statement
.
executeUpdate
();
log
.
info
(
"Macro scene database copy: target=RoutingDetail, rows={}"
,
copiedRows
);
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Failed to copy RoutingDetail in database"
,
ex
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
Map
<
Long
,
Long
>
idMap
=
loadRoutingDetailIdMap
(
target
,
tableInfo
.
getTableName
());
List
<
RoutingDetailReference
>
sourceRows
=
loadRoutingDetailReferences
(
source
);
return
new
RoutingDetailCopyResult
(
idMap
,
sourceRows
);
}
private
Map
<
Long
,
Long
>
loadRoutingDetailIdMap
(
String
sceneId
,
String
tableName
)
{
Map
<
Long
,
Long
>
idMap
=
new
HashMap
<>();
String
sql
=
"SELECT ID, PRE_DETAIL_ID FROM "
+
tableName
+
" WHERE MP_SCENE_ID = ?"
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
statement
.
setString
(
1
,
sceneId
);
try
(
ResultSet
resultSet
=
statement
.
executeQuery
())
{
while
(
resultSet
.
next
())
{
idMap
.
put
(
resultSet
.
getLong
(
"PRE_DETAIL_ID"
),
resultSet
.
getLong
(
"ID"
));
}
}
return
idMap
;
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Failed to load RoutingDetail ID mapping"
,
ex
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
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
restoreMaterialMatchRelations
(
String
target
,
List
<
MaterialReference
>
sourceRows
,
Map
<
String
,
String
>
materialIds
)
{
String
sql
=
"MERGE INTO MATERIAL_INFO target_material USING ("
+
"SELECT mapped.TARGET_ID, mapped.LINK_ID, mapped.MATCH_BIG_ID, mapped.MATCH_SMALL_ID "
+
"FROM JSON_TABLE(?, '$[*]' COLUMNS ("
+
"TARGET_ID VARCHAR2(128) PATH '$.targetId', "
+
"LINK_ID VARCHAR2(128) PATH '$.linkId', "
+
"MATCH_BIG_ID VARCHAR2(128) PATH '$.matchBigId', "
+
"MATCH_SMALL_ID VARCHAR2(128) PATH '$.matchSmallId')) mapped) source_map "
+
"ON (target_material.ID = source_map.TARGET_ID AND target_material.MP_SCENE_ID = ?) "
+
"WHEN MATCHED THEN UPDATE SET target_material.LINKMATERIALID = source_map.LINK_ID, "
+
"target_material.MATCH_BIGPRO_ID = source_map.MATCH_BIG_ID, "
+
"target_material.MATCH_SMALLPRO_ID = source_map.MATCH_SMALL_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
(
MaterialReference
row
:
sourceRows
)
{
String
copiedId
=
materialIds
.
get
(
row
.
id
);
if
(
copiedId
==
null
)
{
continue
;
}
Map
<
String
,
Object
>
mapping
=
new
LinkedHashMap
<>();
mapping
.
put
(
"targetId"
,
copiedId
);
mapping
.
put
(
"linkId"
,
remap
(
row
.
linkMaterialId
,
materialIds
));
mapping
.
put
(
"matchBigId"
,
remap
(
row
.
matchBigproId
,
materialIds
));
mapping
.
put
(
"matchSmallId"
,
remap
(
row
.
matchSmallproId
,
materialIds
));
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=MaterialInfoMatchRelations, rows={}"
,
updatedRows
);
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Failed to restore MaterialInfo match relations"
,
ex
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
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
int
executeJsonMerge
(
PreparedStatement
statement
,
String
target
,
List
<
Map
<
String
,
Object
>>
mappings
)
throws
SQLException
{
String
json
;
try
{
json
=
OBJECT_MAPPER
.
writeValueAsString
(
mappings
);
}
catch
(
JsonProcessingException
ex
)
{
throw
new
IllegalStateException
(
"Failed to serialize scene ID mappings"
,
ex
);
}
Clob
clob
=
statement
.
getConnection
().
createClob
();
try
{
clob
.
setString
(
1
,
json
);
statement
.
setClob
(
1
,
clob
);
statement
.
setString
(
2
,
target
);
return
statement
.
executeUpdate
();
}
finally
{
clob
.
free
();
}
}
private
void
copyRoutingsupporting
(
String
source
,
String
target
,
Map
<
String
,
String
>
materialIds
,
Map
<
Integer
,
Integer
>
routingIds
,
Map
<
Long
,
Long
>
detailIds
)
{
Map
<
String
,
String
>
values
=
new
HashMap
<>();
values
.
put
(
"ROUTING_HEADER_ID"
,
"NVL(target_header.ID, src.ROUTING_HEADER_ID)"
);
values
.
put
(
"ROUTING_DETAIL_ID"
,
"NVL(target_detail.ID, src.ROUTING_DETAIL_ID)"
);
values
.
put
(
"MATERIAL_ID"
,
"NVL(target_material.ID, src.MATERIAL_ID)"
);
values
.
put
(
"STR_ID"
,
"TO_CHAR(SEQ_ROUTINGSUPPORTINGS.CURRVAL)"
);
String
joins
=
" LEFT JOIN ROUTING_HEADER target_header ON target_header.MP_SCENE_ID = ? "
+
"AND target_header.UP_DETAIL_ID = src.ROUTING_HEADER_ID "
+
"LEFT JOIN ROUTING_DETAIL target_detail ON target_detail.MP_SCENE_ID = ? "
+
"AND target_detail.PRE_DETAIL_ID = src.ROUTING_DETAIL_ID "
+
"LEFT JOIN MATERIAL_INFO target_material ON target_material.MP_SCENE_ID = ? "
+
"AND target_material.MATCH_BIGPRO_ID = src.MATERIAL_ID "
;
executeMappedDatabaseCopy
(
Routingsupporting
.
class
,
"SEQ_ROUTINGSUPPORTINGS"
,
source
,
target
,
values
,
joins
,
java
.
util
.
Arrays
.
asList
(
target
,
target
,
target
),
null
,
null
);
}
private
void
copyRoutingConnections
(
String
source
,
String
target
,
Map
<
Integer
,
Integer
>
routingIds
,
Map
<
Long
,
Long
>
detailIds
)
{
Map
<
String
,
String
>
values
=
new
HashMap
<>();
values
.
put
(
"ROUTING_HEADER_ID"
,
"NVL(target_header.ID, src.ROUTING_HEADER_ID)"
);
values
.
put
(
"SOURCEOPERATIONID"
,
"NVL(source_detail.ID, src.SOURCEOPERATIONID)"
);
values
.
put
(
"DESTOPERATIONID"
,
"NVL(dest_detail.ID, src.DESTOPERATIONID)"
);
values
.
put
(
"STR_ID"
,
"TO_CHAR(SEQ_ROUTING_DETAIL_CONNECTS.CURRVAL)"
);
String
joins
=
" LEFT JOIN ROUTING_HEADER target_header ON target_header.MP_SCENE_ID = ? "
+
"AND target_header.UP_DETAIL_ID = src.ROUTING_HEADER_ID "
+
"LEFT JOIN ROUTING_DETAIL source_detail ON source_detail.MP_SCENE_ID = ? "
+
"AND source_detail.PRE_DETAIL_ID = src.SOURCEOPERATIONID "
+
"LEFT JOIN ROUTING_DETAIL dest_detail ON dest_detail.MP_SCENE_ID = ? "
+
"AND dest_detail.PRE_DETAIL_ID = src.DESTOPERATIONID "
;
executeMappedDatabaseCopy
(
RoutingDetailConnect
.
class
,
"SEQ_ROUTING_DETAIL_CONNECTS"
,
source
,
target
,
values
,
joins
,
java
.
util
.
Arrays
.
asList
(
target
,
target
,
target
),
null
,
null
);
}
private
void
copyRoutingEquipment
(
String
source
,
String
target
,
Map
<
Integer
,
Integer
>
routingIds
,
Map
<
Long
,
Long
>
detailIds
,
Map
<
Integer
,
Integer
>
resourceIds
)
{
List
<
Long
>
mapParameters
=
new
ArrayList
<>();
String
withClause
=
"WITH "
+
mapCte
(
"resource_map"
,
resourceIds
,
mapParameters
)
+
" "
;
Map
<
String
,
String
>
values
=
new
HashMap
<>();
values
.
put
(
"ROUTING_HEADER_ID"
,
"NVL(target_header.ID, src.ROUTING_HEADER_ID)"
);
values
.
put
(
"ROUTING_DETAIL_ID"
,
"NVL(target_detail.ID, src.ROUTING_DETAIL_ID)"
);
values
.
put
(
"EQUIP_ID"
,
"NVL(resource_map.NEW_ID, src.EQUIP_ID)"
);
values
.
put
(
"STR_ID"
,
"TO_CHAR(SEQ_ROUTING_DETAIL_EQUIPS.CURRVAL)"
);
String
joins
=
" LEFT JOIN ROUTING_HEADER target_header ON target_header.MP_SCENE_ID = ? "
+
"AND target_header.UP_DETAIL_ID = src.ROUTING_HEADER_ID "
+
"LEFT JOIN ROUTING_DETAIL target_detail ON target_detail.MP_SCENE_ID = ? "
+
"AND target_detail.PRE_DETAIL_ID = src.ROUTING_DETAIL_ID "
+
"LEFT JOIN resource_map ON resource_map.OLD_ID = src.EQUIP_ID "
;
executeMappedDatabaseCopy
(
RoutingDetailEquip
.
class
,
"SEQ_ROUTING_DETAIL_EQUIPS"
,
source
,
target
,
values
,
joins
,
java
.
util
.
Arrays
.
asList
(
target
,
target
),
withClause
,
mapParameters
);
}
private
void
executeMappedDatabaseCopy
(
Class
<?>
entityType
,
String
sequenceName
,
String
source
,
String
target
,
Map
<
String
,
String
>
mappedValues
,
String
joins
,
List
<?>
joinParameters
,
String
withClause
,
List
<?>
prefixParameters
)
{
TableInfo
tableInfo
=
TableInfoHelper
.
getTableInfo
(
entityType
);
if
(
tableInfo
==
null
)
{
throw
new
IllegalStateException
(
"No MyBatis-Plus table metadata for "
+
entityType
.
getName
());
}
List
<
String
>
columns
=
new
ArrayList
<>();
List
<
String
>
values
=
new
ArrayList
<>();
columns
.
add
(
tableInfo
.
getKeyColumn
());
values
.
add
(
sequenceName
+
".NEXTVAL"
);
for
(
TableFieldInfo
field
:
tableInfo
.
getFieldList
())
{
String
column
=
field
.
getColumn
();
if
(
"MP_SCENE_ID"
.
equalsIgnoreCase
(
column
))
{
continue
;
}
columns
.
add
(
column
);
String
mappedValue
=
mappedValues
.
get
(
column
.
toUpperCase
(
Locale
.
ROOT
));
values
.
add
(
mappedValue
==
null
?
"src."
+
column
:
mappedValue
);
}
columns
.
add
(
"MP_SCENE_ID"
);
values
.
add
(
"?"
);
String
sourcePredicate
=
source
==
null
?
"src.MP_SCENE_ID IS NULL"
:
"src.MP_SCENE_ID = ?"
;
String
sql
=
"INSERT INTO "
+
tableInfo
.
getTableName
()
+
" ("
+
String
.
join
(
", "
,
columns
)
+
") "
+
(
withClause
==
null
?
""
:
withClause
)
+
"SELECT "
+
String
.
join
(
", "
,
values
)
+
" FROM "
+
tableInfo
.
getTableName
()
+
" src "
+
joins
+
"WHERE src.ISDELETED = 0 AND "
+
sourcePredicate
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
int
index
=
1
;
if
(
prefixParameters
!=
null
)
{
for
(
Object
parameter
:
prefixParameters
)
{
statement
.
setObject
(
index
++,
parameter
);
}
}
statement
.
setString
(
index
++,
target
);
for
(
Object
parameter
:
joinParameters
)
{
statement
.
setObject
(
index
++,
parameter
);
}
if
(
source
!=
null
)
{
statement
.
setString
(
index
,
source
);
}
int
copiedRows
=
statement
.
executeUpdate
();
log
.
info
(
"Macro scene database copy: target={}, rows={}"
,
entityType
.
getSimpleName
(),
copiedRows
);
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Failed to copy "
+
entityType
.
getSimpleName
()
+
" in database"
,
ex
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
private
TableInfo
requiredTableInfo
(
Class
<?>
entityType
)
{
TableInfo
tableInfo
=
TableInfoHelper
.
getTableInfo
(
entityType
);
if
(
tableInfo
==
null
)
{
throw
new
IllegalStateException
(
"No MyBatis-Plus table metadata for "
+
entityType
.
getName
());
}
return
tableInfo
;
}
private
void
copyDemandOrders
(
String
source
,
String
target
,
Map
<
String
,
String
>
materialIds
,
Map
<
Integer
,
Integer
>
routingIds
)
{
List
<
ApsDemandOrder
>
copies
=
new
ArrayList
<>();
for
(
ApsDemandOrder
row
:
loadRows
(
source
,
apsDemandOrderMapper
))
{
ApsDemandOrder
copy
=
copyOf
(
row
,
ApsDemandOrder
.
class
);
copy
.
setId
(
UUID
.
randomUUID
().
toString
());
copy
.
setMmid
(
remap
(
row
.
getMmid
(),
materialIds
));
copy
.
setRoutingid
(
remapLong
(
row
.
getRoutingid
(),
routingIds
));
copies
.
add
(
copy
);
}
batchInsert
(
target
,
apsDemandOrderMapper
,
copies
);
}
private
void
copyStocksAndSupplies
(
String
source
,
String
target
,
Map
<
String
,
String
>
materialIds
,
Map
<
Integer
,
Integer
>
routingIds
)
{
List
<
Stock
>
stocks
=
loadRows
(
source
,
stockMapper
);
List
<
Long
>
stockIds
=
sequenceMapper
.
nextStockIds
(
stocks
.
size
());
for
(
int
i
=
0
;
i
<
stocks
.
size
();
i
++)
{
Stock
row
=
copyOf
(
stocks
.
get
(
i
),
Stock
.
class
);
row
.
setId
(
stockIds
.
get
(
i
));
row
.
setMaterialId
(
remap
(
row
.
getMaterialId
(),
materialIds
));
stocks
.
set
(
i
,
row
);
}
batchInsert
(
target
,
stockMapper
,
stocks
);
List
<
MaterialPurchase
>
purchases
=
loadRows
(
source
,
materialPurchaseMapper
);
List
<
Long
>
purchaseIds
=
sequenceMapper
.
nextMaterialPurchaseIds
(
purchases
.
size
());
for
(
int
i
=
0
;
i
<
purchases
.
size
();
i
++)
{
MaterialPurchase
row
=
copyOf
(
purchases
.
get
(
i
),
MaterialPurchase
.
class
);
row
.
setId
(
purchaseIds
.
get
(
i
));
row
.
setMaterialId
(
remap
(
row
.
getMaterialId
(),
materialIds
));
purchases
.
set
(
i
,
row
);
}
batchInsert
(
target
,
materialPurchaseMapper
,
purchases
);
List
<
ErpPurchaseOrder
>
orders
=
loadRows
(
source
,
erpPurchaseOrderMapper
);
List
<
Long
>
orderIds
=
sequenceMapper
.
nextErpPurchaseOrderIds
(
orders
.
size
());
for
(
int
i
=
0
;
i
<
orders
.
size
();
i
++)
{
ErpPurchaseOrder
row
=
copyOf
(
orders
.
get
(
i
),
ErpPurchaseOrder
.
class
);
row
.
setId
(
orderIds
.
get
(
i
));
row
.
setMaterialId
(
remap
(
row
.
getMaterialId
(),
materialIds
));
orders
.
set
(
i
,
row
);
}
batchInsert
(
target
,
erpPurchaseOrderMapper
,
orders
);
List
<
PurchaseReceipt
>
receipts
=
loadRows
(
source
,
purchaseReceiptMapper
);
List
<
Long
>
receiptIds
=
sequenceMapper
.
nextPurchaseReceiptIds
(
receipts
.
size
());
for
(
int
i
=
0
;
i
<
receipts
.
size
();
i
++)
{
PurchaseReceipt
row
=
copyOf
(
receipts
.
get
(
i
),
PurchaseReceipt
.
class
);
row
.
setId
(
receiptIds
.
get
(
i
));
row
.
setMaterialid
(
remap
(
row
.
getMaterialid
(),
materialIds
));
receipts
.
set
(
i
,
row
);
}
batchInsert
(
target
,
purchaseReceiptMapper
,
receipts
);
List
<
SjzPfWhStock
>
sjzStocks
=
loadRows
(
source
,
sjzPfWhStockMapper
);
List
<
Long
>
sjzIds
=
sequenceMapper
.
nextSjzPfWhStockIds
(
sjzStocks
.
size
());
for
(
int
i
=
0
;
i
<
sjzStocks
.
size
();
i
++)
{
SjzPfWhStock
row
=
copyOf
(
sjzStocks
.
get
(
i
),
SjzPfWhStock
.
class
);
row
.
setId
(
sjzIds
.
get
(
i
));
row
.
setMaterialid
(
remap
(
row
.
getMaterialid
(),
materialIds
));
if
(
row
.
getRoutingid
()
!=
null
)
{
try
{
Integer
newRoutingId
=
routingIds
.
get
(
Integer
.
valueOf
(
row
.
getRoutingid
()));
if
(
newRoutingId
!=
null
)
row
.
setRoutingid
(
String
.
valueOf
(
newRoutingId
));
}
catch
(
NumberFormatException
ignored
)
{
// Some records use a business routing code instead of a numeric ID.
}
}
sjzStocks
.
set
(
i
,
row
);
}
batchInsert
(
target
,
sjzPfWhStockMapper
,
sjzStocks
);
}
private
void
copyEquipCapacity
(
String
source
,
String
target
,
Map
<
Integer
,
Integer
>
equipIds
,
Map
<
Integer
,
Integer
>
resourceIds
)
{
TableInfo
tableInfo
=
TableInfoHelper
.
getTableInfo
(
EquipShiftCapacity
.
class
);
if
(
tableInfo
==
null
)
{
throw
new
IllegalStateException
(
"No MyBatis-Plus table metadata for EquipShiftCapacity"
);
}
List
<
String
>
columns
=
new
ArrayList
<>();
List
<
String
>
values
=
new
ArrayList
<>();
columns
.
add
(
tableInfo
.
getKeyColumn
());
values
.
add
(
"SEQ_EQUIP_SHIFT_CAPACITYS.NEXTVAL"
);
for
(
TableFieldInfo
field
:
tableInfo
.
getFieldList
())
{
if
(
"MP_SCENE_ID"
.
equalsIgnoreCase
(
field
.
getColumn
()))
{
continue
;
}
columns
.
add
(
field
.
getColumn
());
if
(
"EQUIP_ID"
.
equalsIgnoreCase
(
field
.
getColumn
()))
{
values
.
add
(
"NVL(equip_map.NEW_ID, src.EQUIP_ID)"
);
}
else
if
(
"PLAN_RESOURCE_ID"
.
equalsIgnoreCase
(
field
.
getColumn
()))
{
values
.
add
(
"NVL(resource_map.NEW_ID, src.PLAN_RESOURCE_ID)"
);
}
else
{
values
.
add
(
"src."
+
field
.
getColumn
());
}
}
columns
.
add
(
"MP_SCENE_ID"
);
values
.
add
(
"?"
);
List
<
Long
>
parameters
=
new
ArrayList
<>();
String
equipMapSql
=
mapCte
(
"equip_map"
,
equipIds
,
parameters
);
String
resourceMapSql
=
mapCte
(
"resource_map"
,
resourceIds
,
parameters
);
String
sourcePredicate
=
source
==
null
?
"src.MP_SCENE_ID IS NULL"
:
"src.MP_SCENE_ID = ?"
;
String
sql
=
"INSERT INTO "
+
tableInfo
.
getTableName
()
+
" ("
+
String
.
join
(
", "
,
columns
)
+
") "
+
"WITH "
+
equipMapSql
+
", "
+
resourceMapSql
+
" "
+
"SELECT "
+
String
.
join
(
", "
,
values
)
+
" FROM "
+
tableInfo
.
getTableName
()
+
" src "
+
"LEFT JOIN equip_map ON equip_map.OLD_ID = src.EQUIP_ID "
+
"LEFT JOIN resource_map ON resource_map.OLD_ID = src.PLAN_RESOURCE_ID "
+
"WHERE src.IS_DELETED = 0 AND "
+
sourcePredicate
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
int
index
=
1
;
for
(
Long
parameter
:
parameters
)
{
statement
.
setLong
(
index
++,
parameter
);
}
statement
.
setString
(
index
++,
target
);
if
(
source
!=
null
)
{
statement
.
setString
(
index
,
source
);
}
int
copiedRows
=
statement
.
executeUpdate
();
log
.
info
(
"Macro scene database copy: target=EquipShiftCapacity, rows={}"
,
copiedRows
);
}
catch
(
SQLException
ex
)
{
throw
new
IllegalStateException
(
"Failed to copy EquipShiftCapacity in database"
,
ex
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
private
String
mapCte
(
String
name
,
Map
<
Integer
,
Integer
>
idMap
,
List
<
Long
>
parameters
)
{
List
<
String
>
rows
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
Integer
,
Integer
>
entry
:
idMap
.
entrySet
())
{
if
(
entry
.
getKey
()
==
null
||
entry
.
getValue
()
==
null
)
{
continue
;
}
rows
.
add
(
"SELECT ? AS OLD_ID, ? AS NEW_ID FROM DUAL"
);
parameters
.
add
(
entry
.
getKey
().
longValue
());
parameters
.
add
(
entry
.
getValue
().
longValue
());
}
String
emptySet
=
"SELECT CAST(NULL AS NUMBER) AS OLD_ID, CAST(NULL AS NUMBER) AS NEW_ID FROM DUAL WHERE 1 = 0"
;
return
name
+
" (OLD_ID, NEW_ID) AS ("
+
(
rows
.
isEmpty
()
?
emptySet
:
String
.
join
(
" UNION ALL "
,
rows
))
+
")"
;
}
private
<
T
>
void
copySimpleRows
(
String
source
,
String
target
,
BaseMapper
<
T
>
mapper
,
Class
<
T
>
type
,
Consumer
<
T
>
mutator
)
{
List
<
T
>
copies
=
new
ArrayList
<>();
for
(
T
row
:
loadRows
(
source
,
mapper
))
{
T
copy
=
copyOf
(
row
,
type
);
if
(
mutator
!=
null
)
{
mutator
.
accept
(
copy
);
}
copies
.
add
(
copy
);
}
log
.
info
(
"Macro scene batch insert: target={}, rows={}"
,
type
.
getSimpleName
(),
copies
.
size
());
batchInsert
(
target
,
mapper
,
copies
);
}
private
<
T
>
List
<
T
>
loadRows
(
String
sceneId
,
BaseMapper
<
T
>
mapper
)
{
return
MacroSceneContext
.
execute
(
sceneId
,
()
->
{
QueryWrapper
<
T
>
wrapper
=
new
QueryWrapper
<>();
String
deletedColumn
=
deletedColumn
(
mapper
);
if
(
deletedColumn
!=
null
)
{
wrapper
.
eq
(
deletedColumn
,
0
);
}
List
<
T
>
rows
=
new
ArrayList
<>(
mapper
.
selectList
(
wrapper
));
log
.
info
(
"Macro scene source rows: mapper={}, sceneId={}, activeRows={}"
,
mapper
.
getClass
().
getSimpleName
(),
sceneId
,
rows
.
size
());
return
rows
;
});
}
private
String
deletedColumn
(
BaseMapper
<?>
mapper
)
{
if
(
mapper
==
apsDemandOrderMapper
||
mapper
==
materialInfoMapper
||
mapper
==
routingsupportingMapper
||
mapper
==
routingDetailConnectMapper
||
mapper
==
routingDetailEquipMapper
||
mapper
==
stockMapper
||
mapper
==
materialPurchaseMapper
||
mapper
==
erpPurchaseOrderMapper
||
mapper
==
purchaseReceiptMapper
||
mapper
==
sjzPfWhStockMapper
||
mapper
==
planResourceMapper
||
mapper
==
equipinfoMapper
)
{
return
"ISDELETED"
;
}
if
(
mapper
==
routingDetailMapper
||
mapper
==
equipShiftCapacityMapper
)
{
return
"IS_DELETED"
;
}
return
null
;
}
private
<
T
>
void
insert
(
String
sceneId
,
BaseMapper
<
T
>
mapper
,
T
row
)
{
MacroSceneContext
.
execute
(
sceneId
,
()
->
mapper
.
insert
(
row
));
}
private
<
T
>
void
batchInsert
(
String
sceneId
,
BaseMapper
<
T
>
mapper
,
List
<
T
>
rows
)
{
if
(
rows
==
null
||
rows
.
isEmpty
())
{
return
;
}
MacroSceneContext
.
execute
(
sceneId
,
()
->
jdbcBatchInsert
(
sceneId
,
rows
));
}
private
<
T
>
void
jdbcSingleInsert
(
String
sceneId
,
List
<
T
>
rows
)
{
Class
<?>
entityType
=
rows
.
get
(
0
).
getClass
();
TableInfo
tableInfo
=
TableInfoHelper
.
getTableInfo
(
entityType
);
if
(
tableInfo
==
null
)
{
throw
new
IllegalStateException
(
"No MyBatis-Plus table metadata for "
+
entityType
.
getName
());
}
List
<
String
>
columns
=
new
ArrayList
<>();
List
<
String
>
properties
=
new
ArrayList
<>();
if
(
tableInfo
.
getKeyColumn
()
!=
null
&&
tableInfo
.
getKeyProperty
()
!=
null
)
{
columns
.
add
(
tableInfo
.
getKeyColumn
());
properties
.
add
(
tableInfo
.
getKeyProperty
());
}
for
(
TableFieldInfo
field
:
tableInfo
.
getFieldList
())
{
if
(!
"MP_SCENE_ID"
.
equalsIgnoreCase
(
field
.
getColumn
()))
{
columns
.
add
(
field
.
getColumn
());
properties
.
add
(
field
.
getProperty
());
}
}
columns
.
add
(
"MP_SCENE_ID"
);
String
sql
=
"INSERT INTO "
+
tableInfo
.
getTableName
()
+
" ("
+
String
.
join
(
", "
,
columns
)
+
") VALUES ("
+
String
.
join
(
", "
,
java
.
util
.
Collections
.
nCopies
(
columns
.
size
(),
"?"
))
+
")"
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
List
<
Integer
>
jdbcTypes
=
loadJdbcTypes
(
connection
,
tableInfo
.
getTableName
(),
columns
);
for
(
T
row
:
rows
)
{
BeanWrapperImpl
bean
=
new
BeanWrapperImpl
(
row
);
int
index
=
1
;
for
(
String
property
:
properties
)
{
bindValue
(
statement
,
index
,
bean
.
getPropertyValue
(
property
),
jdbcTypes
.
get
(
index
-
1
));
index
++;
}
bindValue
(
statement
,
index
,
sceneId
,
jdbcTypes
.
get
(
index
-
1
));
statement
.
executeUpdate
();
}
}
catch
(
SQLException
e
)
{
throw
new
IllegalStateException
(
"Failed to insert "
+
tableInfo
.
getTableName
(),
e
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
private
<
T
>
void
jdbcBatchInsert
(
String
sceneId
,
List
<
T
>
rows
)
{
Class
<?>
entityType
=
rows
.
get
(
0
).
getClass
();
TableInfo
tableInfo
=
TableInfoHelper
.
getTableInfo
(
entityType
);
if
(
tableInfo
==
null
)
{
throw
new
IllegalStateException
(
"No MyBatis-Plus table metadata for "
+
entityType
.
getName
());
}
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
{
Map
<
String
,
Integer
>
typeByColumn
=
loadJdbcTypeMap
(
connection
,
tableInfo
.
getTableName
());
List
<
String
>
columns
=
new
ArrayList
<>();
List
<
String
>
properties
=
new
ArrayList
<>();
List
<
Integer
>
jdbcTypes
=
new
ArrayList
<>();
List
<
TableFieldInfo
>
largeTextFields
=
new
ArrayList
<>();
if
(
tableInfo
.
getKeyColumn
()
!=
null
&&
tableInfo
.
getKeyProperty
()
!=
null
)
{
columns
.
add
(
tableInfo
.
getKeyColumn
());
properties
.
add
(
tableInfo
.
getKeyProperty
());
jdbcTypes
.
add
(
requiredJdbcType
(
typeByColumn
,
tableInfo
.
getTableName
(),
tableInfo
.
getKeyColumn
()));
}
for
(
TableFieldInfo
field
:
tableInfo
.
getFieldList
())
{
if
(
"MP_SCENE_ID"
.
equalsIgnoreCase
(
field
.
getColumn
()))
{
continue
;
}
int
jdbcType
=
requiredJdbcType
(
typeByColumn
,
tableInfo
.
getTableName
(),
field
.
getColumn
());
if
((
isLargeTextType
(
jdbcType
)
&&
containsNonNullValue
(
rows
,
field
.
getProperty
()))
||
containsLongString
(
rows
,
field
.
getProperty
()))
{
largeTextFields
.
add
(
field
);
}
else
{
columns
.
add
(
field
.
getColumn
());
properties
.
add
(
field
.
getProperty
());
jdbcTypes
.
add
(
jdbcType
);
}
}
columns
.
add
(
"MP_SCENE_ID"
);
jdbcTypes
.
add
(
requiredJdbcType
(
typeByColumn
,
tableInfo
.
getTableName
(),
"MP_SCENE_ID"
));
String
sql
=
"INSERT INTO "
+
tableInfo
.
getTableName
()
+
" ("
+
String
.
join
(
", "
,
columns
)
+
") VALUES ("
+
String
.
join
(
", "
,
java
.
util
.
Collections
.
nCopies
(
columns
.
size
(),
"?"
))
+
")"
;
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
int
pending
=
0
;
for
(
T
row
:
rows
)
{
BeanWrapperImpl
bean
=
new
BeanWrapperImpl
(
row
);
int
index
=
1
;
for
(
String
property
:
properties
)
{
bindValue
(
statement
,
index
,
bean
.
getPropertyValue
(
property
),
jdbcTypes
.
get
(
index
-
1
));
index
++;
}
bindValue
(
statement
,
index
,
sceneId
,
jdbcTypes
.
get
(
index
-
1
));
statement
.
addBatch
();
if
(++
pending
==
JDBC_BATCH_SIZE
)
{
statement
.
executeBatch
();
pending
=
0
;
}
}
if
(
pending
>
0
)
{
statement
.
executeBatch
();
}
}
updateLargeTextFields
(
connection
,
sceneId
,
tableInfo
,
rows
,
largeTextFields
,
typeByColumn
);
}
catch
(
SQLException
e
)
{
throw
new
IllegalStateException
(
"Failed to batch insert "
+
tableInfo
.
getTableName
(),
e
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
private
<
T
>
void
updateLargeTextFields
(
Connection
connection
,
String
sceneId
,
TableInfo
tableInfo
,
List
<
T
>
rows
,
List
<
TableFieldInfo
>
fields
,
Map
<
String
,
Integer
>
typeByColumn
)
throws
SQLException
{
if
(
fields
.
isEmpty
())
{
return
;
}
if
(
tableInfo
.
getKeyColumn
()
==
null
||
tableInfo
.
getKeyProperty
()
==
null
)
{
throw
new
IllegalStateException
(
"Large text update requires a primary key: "
+
tableInfo
.
getTableName
());
}
int
keyType
=
requiredJdbcType
(
typeByColumn
,
tableInfo
.
getTableName
(),
tableInfo
.
getKeyColumn
());
int
sceneType
=
requiredJdbcType
(
typeByColumn
,
tableInfo
.
getTableName
(),
"MP_SCENE_ID"
);
for
(
TableFieldInfo
field
:
fields
)
{
int
fieldType
=
requiredJdbcType
(
typeByColumn
,
tableInfo
.
getTableName
(),
field
.
getColumn
());
String
sql
=
"UPDATE "
+
tableInfo
.
getTableName
()
+
" SET "
+
field
.
getColumn
()
+
" = ? WHERE "
+
tableInfo
.
getKeyColumn
()
+
" = ? AND MP_SCENE_ID = ?"
;
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
int
pending
=
0
;
for
(
T
row
:
rows
)
{
BeanWrapperImpl
bean
=
new
BeanWrapperImpl
(
row
);
Object
value
=
bean
.
getPropertyValue
(
field
.
getProperty
());
if
(
value
==
null
)
{
continue
;
}
bindValue
(
statement
,
1
,
value
,
fieldType
);
bindValue
(
statement
,
2
,
bean
.
getPropertyValue
(
tableInfo
.
getKeyProperty
()),
keyType
);
bindValue
(
statement
,
3
,
sceneId
,
sceneType
);
statement
.
addBatch
();
if
(++
pending
==
JDBC_BATCH_SIZE
)
{
statement
.
executeBatch
();
pending
=
0
;
}
}
if
(
pending
>
0
)
{
statement
.
executeBatch
();
}
}
}
}
private
<
T
>
boolean
containsLongString
(
List
<
T
>
rows
,
String
property
)
{
for
(
T
row
:
rows
)
{
Object
value
=
new
BeanWrapperImpl
(
row
).
getPropertyValue
(
property
);
if
(
value
instanceof
String
&&
((
String
)
value
).
length
()
>
2000
)
{
return
true
;
}
}
return
false
;
}
private
<
T
>
boolean
containsNonNullValue
(
List
<
T
>
rows
,
String
property
)
{
for
(
T
row
:
rows
)
{
if
(
new
BeanWrapperImpl
(
row
).
getPropertyValue
(
property
)
!=
null
)
{
return
true
;
}
}
return
false
;
}
private
List
<
Integer
>
loadJdbcTypes
(
Connection
connection
,
String
tableName
,
List
<
String
>
columns
)
throws
SQLException
{
Map
<
String
,
Integer
>
typeByColumn
=
loadJdbcTypeMap
(
connection
,
tableName
);
List
<
Integer
>
jdbcTypes
=
new
ArrayList
<>(
columns
.
size
());
for
(
String
column
:
columns
)
{
jdbcTypes
.
add
(
requiredJdbcType
(
typeByColumn
,
tableName
,
column
));
}
return
jdbcTypes
;
}
private
Map
<
String
,
Integer
>
loadJdbcTypeMap
(
Connection
connection
,
String
tableName
)
throws
SQLException
{
Map
<
String
,
Integer
>
typeByColumn
=
new
HashMap
<>();
DatabaseMetaData
metaData
=
connection
.
getMetaData
();
String
schema
=
metaData
.
getUserName
();
String
metadataTableName
=
tableName
;
int
separator
=
tableName
.
indexOf
(
'.'
);
if
(
separator
>
0
&&
separator
<
tableName
.
length
()
-
1
)
{
schema
=
tableName
.
substring
(
0
,
separator
);
metadataTableName
=
tableName
.
substring
(
separator
+
1
);
}
try
(
ResultSet
resultSet
=
metaData
.
getColumns
(
null
,
schema
,
metadataTableName
.
toUpperCase
(
Locale
.
ROOT
),
null
))
{
while
(
resultSet
.
next
())
{
typeByColumn
.
put
(
resultSet
.
getString
(
"COLUMN_NAME"
).
toUpperCase
(
Locale
.
ROOT
),
resultSet
.
getInt
(
"DATA_TYPE"
));
}
}
return
typeByColumn
;
}
private
int
requiredJdbcType
(
Map
<
String
,
Integer
>
typeByColumn
,
String
tableName
,
String
column
)
{
Integer
jdbcType
=
typeByColumn
.
get
(
column
.
toUpperCase
(
Locale
.
ROOT
));
if
(
jdbcType
==
null
)
{
throw
new
IllegalStateException
(
"Column metadata not found: "
+
tableName
+
"."
+
column
);
}
return
jdbcType
;
}
private
void
jdbcBatchUpdateRoutingHierarchy
(
String
sceneId
,
List
<
RoutingHeader
>
sourceRows
,
Map
<
Integer
,
Integer
>
routingIds
,
Map
<
Long
,
Long
>
detailIds
)
{
String
sql
=
"UPDATE ROUTING_HEADER SET UP_DETAIL_ID = ? WHERE ID = ? AND MP_SCENE_ID = ?"
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
int
pending
=
0
;
for
(
RoutingHeader
row
:
sourceRows
)
{
if
(
row
.
getUpDetailId
()
==
null
)
{
continue
;
}
Integer
copiedRoutingId
=
routingIds
.
get
(
row
.
getId
());
Long
copiedDetailId
=
detailIds
.
get
(
row
.
getUpDetailId
().
longValue
());
if
(
copiedRoutingId
==
null
||
copiedDetailId
==
null
)
{
continue
;
}
statement
.
setLong
(
1
,
copiedDetailId
);
statement
.
setInt
(
2
,
copiedRoutingId
);
statement
.
setString
(
3
,
sceneId
);
statement
.
addBatch
();
if
(++
pending
==
500
)
{
statement
.
executeBatch
();
pending
=
0
;
}
}
if
(
pending
>
0
)
{
statement
.
executeBatch
();
}
}
catch
(
SQLException
e
)
{
throw
new
IllegalStateException
(
"Failed to update routing hierarchy"
,
e
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
private
void
jdbcClearRoutingHierarchyMarker
(
String
sceneId
)
{
String
sql
=
"UPDATE ROUTING_HEADER SET UP_DETAIL_ID = NULL WHERE MP_SCENE_ID = ?"
;
Connection
connection
=
DataSourceUtils
.
getConnection
(
dataSource
);
try
(
PreparedStatement
statement
=
connection
.
prepareStatement
(
sql
))
{
statement
.
setString
(
1
,
sceneId
);
statement
.
executeUpdate
();
}
catch
(
SQLException
e
)
{
throw
new
IllegalStateException
(
"Failed to clear routing hierarchy marker"
,
e
);
}
finally
{
DataSourceUtils
.
releaseConnection
(
connection
,
dataSource
);
}
}
private
void
bindValue
(
PreparedStatement
statement
,
int
index
,
Object
value
,
int
jdbcType
)
throws
SQLException
{
if
(
value
==
null
)
{
statement
.
setNull
(
index
,
jdbcType
);
}
else
if
(
value
instanceof
String
&&
isNationalLargeTextType
(
jdbcType
))
{
String
text
=
(
String
)
value
;
statement
.
setNCharacterStream
(
index
,
new
java
.
io
.
StringReader
(
text
),
text
.
length
());
}
else
if
(
value
instanceof
String
&&
isLargeTextType
(
jdbcType
))
{
String
text
=
(
String
)
value
;
statement
.
setCharacterStream
(
index
,
new
java
.
io
.
StringReader
(
text
),
text
.
length
());
}
else
if
(
value
instanceof
String
&&
isNationalTextType
(
jdbcType
))
{
statement
.
setNString
(
index
,
(
String
)
value
);
}
else
if
(
value
instanceof
String
)
{
statement
.
setString
(
index
,
(
String
)
value
);
}
else
if
(
value
instanceof
java
.
time
.
LocalDate
)
{
statement
.
setDate
(
index
,
java
.
sql
.
Date
.
valueOf
((
java
.
time
.
LocalDate
)
value
));
}
else
if
(
value
instanceof
java
.
time
.
LocalDateTime
)
{
statement
.
setTimestamp
(
index
,
java
.
sql
.
Timestamp
.
valueOf
((
java
.
time
.
LocalDateTime
)
value
));
}
else
if
(
value
instanceof
Boolean
)
{
statement
.
setInt
(
index
,
(
Boolean
)
value
?
1
:
0
);
}
else
{
statement
.
setObject
(
index
,
value
);
}
}
private
boolean
isLargeTextType
(
int
jdbcType
)
{
return
jdbcType
==
Types
.
LONGVARCHAR
||
jdbcType
==
Types
.
LONGNVARCHAR
||
jdbcType
==
Types
.
CLOB
||
jdbcType
==
Types
.
NCLOB
;
}
private
boolean
isNationalLargeTextType
(
int
jdbcType
)
{
return
jdbcType
==
Types
.
LONGNVARCHAR
||
jdbcType
==
Types
.
NCLOB
;
}
private
boolean
isNationalTextType
(
int
jdbcType
)
{
return
jdbcType
==
Types
.
NCHAR
||
jdbcType
==
Types
.
NVARCHAR
;
}
private
<
T
>
void
update
(
String
sceneId
,
BaseMapper
<
T
>
mapper
,
T
row
)
{
MacroSceneContext
.
execute
(
sceneId
,
()
->
mapper
.
updateById
(
row
));
}
private
<
T
>
T
copyOf
(
T
source
,
Class
<
T
>
type
)
{
try
{
T
target
=
type
.
getDeclaredConstructor
().
newInstance
();
BeanUtils
.
copyProperties
(
source
,
target
,
"mpSceneId"
);
return
target
;
}
catch
(
ReflectiveOperationException
e
)
{
throw
new
IllegalStateException
(
"Cannot copy "
+
type
.
getSimpleName
(),
e
);
}
}
private
<
K
,
V
>
V
remap
(
K
oldId
,
Map
<
K
,
V
>
idMap
)
{
if
(
oldId
==
null
)
{
return
null
;
}
V
newId
=
idMap
.
get
(
oldId
);
return
newId
==
null
?
castSameType
(
oldId
)
:
newId
;
}
@SuppressWarnings
(
"unchecked"
)
private
<
K
,
V
>
V
castSameType
(
K
value
)
{
return
(
V
)
value
;
}
private
Long
remapLong
(
Long
oldId
,
Map
<
Integer
,
Integer
>
idMap
)
{
if
(
oldId
==
null
)
{
return
null
;
}
Integer
newId
=
idMap
.
get
(
oldId
.
intValue
());
return
newId
==
null
?
oldId
:
newId
.
longValue
();
}
private
static
final
class
MaterialCopyResult
{
private
final
Map
<
String
,
String
>
idMap
;
private
final
List
<
MaterialReference
>
sourceRows
;
private
MaterialCopyResult
(
Map
<
String
,
String
>
idMap
,
List
<
MaterialReference
>
sourceRows
)
{
this
.
idMap
=
idMap
;
this
.
sourceRows
=
sourceRows
;
}
}
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
;
private
final
String
linkMaterialId
;
private
final
String
matchBigproId
;
private
final
String
matchSmallproId
;
private
MaterialReference
(
String
id
,
String
linkMaterialId
,
String
matchBigproId
,
String
matchSmallproId
)
{
this
.
id
=
id
;
this
.
linkMaterialId
=
linkMaterialId
;
this
.
matchBigproId
=
matchBigproId
;
this
.
matchSmallproId
=
matchSmallproId
;
}
}
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
)
{
throw
new
IllegalStateException
(
"Database did not return generated ID for "
+
table
);
}
}
private
String
requireText
(
String
value
,
String
field
)
{
String
normalized
=
normalize
(
value
);
if
(
normalized
==
null
)
{
throw
new
IllegalArgumentException
(
field
+
" cannot be blank"
);
}
return
normalized
;
}
private
String
normalize
(
String
value
)
{
return
value
==
null
||
value
.
trim
().
isEmpty
()
?
null
:
value
.
trim
();
}
}
src/main/java/com/aps/mapper/MacroSceneConfigMapper.java
0 → 100644
View file @
b0e9cc4a
package
com
.
aps
.
mapper
;
import
com.aps.entity.MacroSceneConfig
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
public
interface
MacroSceneConfigMapper
extends
BaseMapper
<
MacroSceneConfig
>
{
}
src/main/java/com/aps/mapper/MacroSceneSequenceMapper.java
0 → 100644
View file @
b0e9cc4a
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
);
}
src/main/java/com/aps/service/impl/LanuchServiceImpl.java
View file @
b0e9cc4a
...
...
@@ -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
,
r
outingHeader
,
equipTypeMap
))
.
map
(
detail
->
createProcessExec
(
prodOrderMain
,
detail
,
sceneId
,
routingDetailEquip
,
currentR
outingHeader
,
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
()
...
...
src/main/java/com/aps/service/schedule/SceneInheritanceService.java
0 → 100644
View file @
b0e9cc4a
package
com
.
aps
.
service
.
schedule
;
import
com.aps.entity.ApsTimeConfig
;
import
com.aps.entity.Dispatch
;
import
com.aps.entity.Algorithm.Chromosome
;
import
com.aps.entity.Algorithm.GAScheduleResult
;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.basic.Order
;
import
com.aps.service.ApsTimeConfigService
;
import
com.aps.service.DispatchService
;
import
com.aps.service.plan.SceneService
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.CopyOnWriteArrayList
;
import
java.util.stream.Collectors
;
/**
* 场景继承服务
* 负责在创建新场景时,从Dispatch表中读取冻结期内的工单,并继承到新场景
*/
@Service
@Slf4j
public
class
SceneInheritanceService
{
@Autowired
private
DispatchService
dispatchService
;
@Autowired
private
ApsTimeConfigService
apsTimeConfigService
;
@Autowired
private
SceneService
sceneService
;
/**
* 继承冻结期内的工单到新场景
* 从Dispatch表读取冻结期工单,转换为Chromosome格式并保存到文件
*
* @param newSceneId 新场景ID
* @param newBaseTime 新基准时间
* @return 是否成功继承
*/
public
boolean
inheritFrozenOrdersToChromosome
(
String
newSceneId
,
LocalDateTime
newBaseTime
)
{
log
.
info
(
"开始继承冻结期内的工单到Chromosome,新场景ID: {}, 新基准时间: {}"
,
newSceneId
,
newBaseTime
);
try
{
// 1. 获取时间配置
ApsTimeConfig
timeConfig
=
apsTimeConfigService
.
getOne
(
new
LambdaQueryWrapper
<>());
if
(
timeConfig
==
null
)
{
log
.
warn
(
"未找到ApsTimeConfig配置,无法继承冻结期工单"
);
return
false
;
}
LocalDateTime
baseTime
=
timeConfig
.
getBaseTime
();
if
(
baseTime
==
null
)
{
log
.
warn
(
"ApsTimeConfig中baseTime为空,无法继承冻结期工单"
);
return
false
;
}
// 2. 计算冻结期范围
long
freezeDays
=
timeConfig
.
getFreezeDate
()
!=
null
?
timeConfig
.
getFreezeDate
().
longValue
()
:
0
;
LocalDateTime
freezeEndTime
=
baseTime
.
plusDays
(
freezeDays
);
log
.
info
(
"冻结期范围: {} 到 {}"
,
baseTime
,
freezeEndTime
);
// 3. 从Dispatch表查询冻结期内的所有工序
// 查询条件:beginTime >= baseTime AND beginTime <= freezeEndTime
List
<
Dispatch
>
frozenDispatches
=
dispatchService
.
lambdaQuery
()
.
ge
(
Dispatch:
:
getBeginTime
,
baseTime
)
.
le
(
Dispatch:
:
getBeginTime
,
freezeEndTime
)
.
eq
(
Dispatch:
:
getIsDeleted
,
0L
)
.
orderBy
(
true
,
true
,
Dispatch:
:
getMesCode
,
Dispatch:
:
getTaskSeq
)
.
list
();
log
.
info
(
"查询到冻结期内的工序数: {}"
,
frozenDispatches
.
size
());
if
(
frozenDispatches
.
isEmpty
())
{
log
.
info
(
"冻结期内没有工单需要继承"
);
return
false
;
}
// 4. 按订单分组,筛选出第一道工序在冻结期内的订单
Map
<
String
,
List
<
Dispatch
>>
orderDispatchMap
=
frozenDispatches
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
Dispatch:
:
getMesCode
));
// 筛选:只保留第一道工序在冻结期内的订单的所有工序
List
<
Dispatch
>
validDispatches
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
String
,
List
<
Dispatch
>>
entry
:
orderDispatchMap
.
entrySet
())
{
List
<
Dispatch
>
orderDispatches
=
entry
.
getValue
();
// 按taskSeq排序
orderDispatches
.
sort
((
d1
,
d2
)
->
{
Long
seq1
=
d1
.
getTaskSeq
()
!=
null
?
d1
.
getTaskSeq
()
:
0L
;
Long
seq2
=
d2
.
getTaskSeq
()
!=
null
?
d2
.
getTaskSeq
()
:
0L
;
return
seq1
.
compareTo
(
seq2
);
});
// 检查第一道工序是否在冻结期内
if
(!
orderDispatches
.
isEmpty
())
{
Dispatch
firstDispatch
=
orderDispatches
.
get
(
0
);
if
(
firstDispatch
.
getBeginTime
()
!=
null
&&
!
firstDispatch
.
getBeginTime
().
isBefore
(
baseTime
)
&&
!
firstDispatch
.
getBeginTime
().
isAfter
(
freezeEndTime
))
{
// 第一道工序在冻结期内,保留该订单的所有工序
validDispatches
.
addAll
(
orderDispatches
);
}
}
}
log
.
info
(
"筛选后的冻结期工序数: {}"
,
validDispatches
.
size
());
if
(
validDispatches
.
isEmpty
())
{
log
.
info
(
"没有符合条件的冻结期工单"
);
return
false
;
}
// 5. 转换为Chromosome对象
Chromosome
frozenChromosome
=
convertDispatchesToChromosome
(
validDispatches
,
newSceneId
,
newBaseTime
,
baseTime
);
// 6. 保存到文件
boolean
saved
=
sceneService
.
saveChromosomeToFile
(
frozenChromosome
,
newSceneId
);
if
(
saved
)
{
log
.
info
(
"成功继承 {} 个冻结期工序到新场景,涉及 {} 个订单"
,
validDispatches
.
size
(),
orderDispatchMap
.
size
());
}
else
{
log
.
error
(
"保存冻结期Chromosome文件失败"
);
}
return
saved
;
}
catch
(
Exception
e
)
{
log
.
error
(
"继承冻结期工单时发生错误"
,
e
);
return
false
;
}
}
/**
* 将Dispatch列表转换为Chromosome对象
*
* @param dispatches Dispatch列表
* @param sceneId 场景ID
* @param newBaseTime 新基准时间
* @param oldBaseTime 旧基准时间
* @return Chromosome对象
*/
private
Chromosome
convertDispatchesToChromosome
(
List
<
Dispatch
>
dispatches
,
String
sceneId
,
LocalDateTime
newBaseTime
,
LocalDateTime
oldBaseTime
)
{
Chromosome
chromosome
=
new
Chromosome
();
chromosome
.
setScenarioID
(
sceneId
);
chromosome
.
setBaseTime
(
newBaseTime
);
// 创建Result列表(GAScheduleResult)
CopyOnWriteArrayList
<
GAScheduleResult
>
results
=
new
CopyOnWriteArrayList
<>();
// 创建Entry列表
CopyOnWriteArrayList
<
Entry
>
entries
=
new
CopyOnWriteArrayList
<>();
// 创建Order列表(去重)
Map
<
String
,
Order
>
orderMap
=
new
HashMap
<>();
int
entryId
=
0
;
for
(
Dispatch
dispatch
:
dispatches
)
{
// 创建GAScheduleResult
GAScheduleResult
result
=
new
GAScheduleResult
();
result
.
setOrderId
(
dispatch
.
getMesCode
());
result
.
setExecId
(
dispatch
.
getRoutingDetailId
()
!=
null
?
dispatch
.
getRoutingDetailId
().
toString
()
:
""
);
result
.
setQuantity
(
dispatch
.
getQuantity
()
!=
null
?
dispatch
.
getQuantity
()
:
0
);
// 计算相对时间(相对于新基准时间)
if
(
dispatch
.
getBeginTime
()
!=
null
&&
dispatch
.
getEndTime
()
!=
null
)
{
long
startSeconds
=
java
.
time
.
temporal
.
ChronoUnit
.
SECONDS
.
between
(
newBaseTime
,
dispatch
.
getBeginTime
());
long
endSeconds
=
java
.
time
.
temporal
.
ChronoUnit
.
SECONDS
.
between
(
newBaseTime
,
dispatch
.
getEndTime
());
result
.
setStartTime
((
int
)
startSeconds
);
result
.
setEndTime
((
int
)
endSeconds
);
}
results
.
add
(
result
);
// 创建Entry
Entry
entry
=
new
Entry
();
entry
.
setId
(
entryId
++);
entry
.
setOrderId
(
dispatch
.
getMesCode
());
entry
.
setSceneId
(
sceneId
);
entry
.
setExecId
(
dispatch
.
getRoutingDetailId
()
!=
null
?
dispatch
.
getRoutingDetailId
().
toString
()
:
""
);
entry
.
setRoutingDetailId
(
dispatch
.
getRoutingDetailId
());
entry
.
setRoutingDetailName
(
dispatch
.
getOpe
());
entry
.
setTaskSeq
(
dispatch
.
getTaskSeq
());
entry
.
setDepartmentId
(
dispatch
.
getShopid
());
entry
.
setQuantity
(
dispatch
.
getQuantity
()
!=
null
?
dispatch
.
getQuantity
()
:
0
);
// 设置指定开始时间(保持原来的绝对时间)
entry
.
setDesignatedStartTime
(
dispatch
.
getBeginTime
());
entries
.
add
(
entry
);
// 创建Order(如果还没有)
if
(!
orderMap
.
containsKey
(
dispatch
.
getMesCode
()))
{
Order
order
=
new
Order
();
order
.
setOrderId
(
dispatch
.
getMesCode
());
order
.
setQuantity
(
dispatch
.
getQuantity
()
!=
null
?
dispatch
.
getQuantity
()
:
0
);
// 可以从Dispatch中获取更多信息填充Order
orderMap
.
put
(
dispatch
.
getMesCode
(),
order
);
}
}
chromosome
.
setResult
(
results
);
chromosome
.
setAllOperations
(
entries
);
chromosome
.
setOrders
(
new
CopyOnWriteArrayList
<>(
orderMap
.
values
()));
log
.
info
(
"转换完成:Result数={}, Entry数={}, Order数={}"
,
results
.
size
(),
entries
.
size
(),
orderMap
.
size
());
return
chromosome
;
}
/**
* 从场景加载冻结期工单的Entry列表
* 用于在排产时获取冻结期工单
*
* @param sceneId 场景ID
* @return 冻结期工单的Entry列表
*/
public
List
<
Entry
>
loadFrozenEntriesFromScene
(
String
sceneId
)
{
try
{
Chromosome
chromosome
=
sceneService
.
loadChromosomeFromFile
(
sceneId
);
if
(
chromosome
==
null
||
chromosome
.
getAllOperations
()
==
null
)
{
log
.
info
(
"场景 {} 没有冻结期工单"
,
sceneId
);
return
new
ArrayList
<>();
}
List
<
Entry
>
frozenEntries
=
new
ArrayList
<>(
chromosome
.
getAllOperations
());
log
.
info
(
"从场景 {} 加载了 {} 个冻结期工序"
,
sceneId
,
frozenEntries
.
size
());
return
frozenEntries
;
}
catch
(
Exception
e
)
{
log
.
error
(
"加载冻结期工单失败,场景ID: {}"
,
sceneId
,
e
);
return
new
ArrayList
<>();
}
}
/**
* 获取冻结期配置信息
*
* @return 冻结期配置
*/
public
FrozenPeriodConfig
getFrozenPeriodConfig
()
{
ApsTimeConfig
timeConfig
=
apsTimeConfigService
.
getOne
(
new
LambdaQueryWrapper
<>());
if
(
timeConfig
==
null
)
{
return
null
;
}
FrozenPeriodConfig
config
=
new
FrozenPeriodConfig
();
config
.
setBaseTime
(
timeConfig
.
getBaseTime
());
config
.
setFreezeDate
(
timeConfig
.
getFreezeDate
()
!=
null
?
timeConfig
.
getFreezeDate
().
longValue
()
:
0
);
if
(
timeConfig
.
getBaseTime
()
!=
null
&&
timeConfig
.
getFreezeDate
()
!=
null
)
{
config
.
setFreezeEndTime
(
timeConfig
.
getBaseTime
().
plusDays
(
timeConfig
.
getFreezeDate
().
longValue
()));
}
return
config
;
}
/**
* 冻结期配置信息
*/
public
static
class
FrozenPeriodConfig
{
private
LocalDateTime
baseTime
;
private
long
freezeDate
;
private
LocalDateTime
freezeEndTime
;
public
LocalDateTime
getBaseTime
()
{
return
baseTime
;
}
public
void
setBaseTime
(
LocalDateTime
baseTime
)
{
this
.
baseTime
=
baseTime
;
}
public
long
getFreezeDate
()
{
return
freezeDate
;
}
public
void
setFreezeDate
(
long
freezeDate
)
{
this
.
freezeDate
=
freezeDate
;
}
public
LocalDateTime
getFreezeEndTime
()
{
return
freezeEndTime
;
}
public
void
setFreezeEndTime
(
LocalDateTime
freezeEndTime
)
{
this
.
freezeEndTime
=
freezeEndTime
;
}
}
}
src/main/resources/mapper/ApsDemandOrderMapper.xml
View file @
b0e9cc4a
...
...
@@ -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>
...
...
src/main/resources/mapper/ApsTimeConfigMapper.xml
View file @
b0e9cc4a
...
...
@@ -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>
...
...
src/main/resources/mapper/EquipinfoMapper.xml
View file @
b0e9cc4a
...
...
@@ -61,10 +61,12 @@
<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>
...
...
src/main/resources/mapper/ErpPurchaseOrderMapper.xml
View file @
b0e9cc4a
...
...
@@ -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>
...
...
src/main/resources/mapper/MaterialInfoMapper.xml
View file @
b0e9cc4a
...
...
@@ -101,10 +101,12 @@
<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>
...
...
src/main/resources/mapper/PlanResourceMapper.xml
View file @
b0e9cc4a
...
...
@@ -32,10 +32,12 @@
<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>
...
...
src/main/resources/mapper/PurchaseReceiptMapper.xml
View file @
b0e9cc4a
...
...
@@ -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>
...
...
src/main/resources/mapper/RoutingDetailConnectMapper.xml
View file @
b0e9cc4a
...
...
@@ -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>
...
...
src/main/resources/mapper/RoutingDetailEquipMapper.xml
View file @
b0e9cc4a
...
...
@@ -28,10 +28,12 @@
<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>
...
...
src/main/resources/mapper/RoutingDetailMapper.xml
View file @
b0e9cc4a
...
...
@@ -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>
...
...
src/main/resources/mapper/RoutingHeaderMapper.xml
View file @
b0e9cc4a
...
...
@@ -64,10 +64,12 @@
<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>
...
...
src/main/resources/mapper/RoutingsupportingMapper.xml
View file @
b0e9cc4a
...
...
@@ -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>
...
...
src/main/resources/mapper/SjzPfWhStockMapper.xml
View file @
b0e9cc4a
...
...
@@ -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>
...
...
src/main/resources/mapper/StockMapper.xml
View file @
b0e9cc4a
...
...
@@ -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>
...
...
src/test/java/com/aps/demo/KpiCalculatorTest.java
0 → 100644
View file @
b0e9cc4a
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
src/test/java/com/aps/macroplanner/scene/MacroSceneDataPermissionHandlerTest.java
0 → 100644
View file @
b0e9cc4a
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
);
}
}
src/test/java/com/aps/macroplanner/scene/MacroSceneSqlInterceptorTest.java
0 → 100644
View file @
b0e9cc4a
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"
));
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment