CANCERYS\kw093 2 тижднів тому
джерело
коміт
c2c8b40fb3
11 змінених файлів з 345 додано та 21 видалено
  1. +1
    -0
      src/main/java/com/ffii/fpsms/modules/master/entity/ItemsQcCategoryMappingRepository.kt
  2. +20
    -3
      src/main/java/com/ffii/fpsms/modules/master/service/ItemUomService.kt
  3. +1
    -0
      src/main/java/com/ffii/fpsms/modules/master/web/models/DeleteResponse.kt
  4. +1
    -0
      src/main/java/com/ffii/fpsms/modules/master/web/models/ItemQcCategoryMappingInfo.kt
  5. +1
    -0
      src/main/java/com/ffii/fpsms/modules/master/web/models/QcCategoryWithItemCount.kt
  6. +1
    -0
      src/main/java/com/ffii/fpsms/modules/master/web/models/QcCategoryWithQcItemCount.kt
  7. +2
    -1
      src/main/java/com/ffii/fpsms/modules/productProcess/entity/ProductProcessLine.kt
  8. +7
    -4
      src/main/java/com/ffii/fpsms/modules/productProcess/entity/projections/ProductProcessInfo.kt
  9. +306
    -13
      src/main/java/com/ffii/fpsms/modules/productProcess/service/ProductProcessService.kt
  10. +4
    -0
      src/main/java/com/ffii/fpsms/modules/productProcess/web/ProductProcessController.kt
  11. +1
    -0
      src/main/java/com/ffii/fpsms/modules/productProcess/web/model/SaveProductProcessRequest.kt

+ 1
- 0
src/main/java/com/ffii/fpsms/modules/master/entity/ItemsQcCategoryMappingRepository.kt Переглянути файл

@@ -24,3 +24,4 @@ interface ItemsQcCategoryMappingRepository : AbstractRepository<ItemsQcCategoryM
fun findMappings(qcCategoryId: Long?, itemId: Long?): List<ItemsQcCategoryMapping>
}



+ 20
- 3
src/main/java/com/ffii/fpsms/modules/master/service/ItemUomService.kt Переглянути файл

@@ -138,7 +138,24 @@ open class ItemUomService(
)
}
}
if (request.uomId == 784L) {
val targetItemUom = findTargetItemUom(request.itemId, request.targetUnit)
val targetUomId = targetItemUom?.uom?.id
if (targetUomId == 18L) {
// Direct conversion: 1 KG = 1000 milliliters (assuming density = 1 g/ml for water-based products)
// Note: This is a general conversion, actual conversion may vary by product density
val convertedQty = request.qty.multiply(BigDecimal(1000))
val milliliterUom = uomConversionService.findById(19L)
?: throw IllegalArgumentException("UomConversion not found for id=19 (milliliter)")
return ConvertUomByItemResponse(
newQty = convertedQty,
udfudesc = milliliterUom.udfudesc,
udfShortDesc = milliliterUom.udfShortDesc
)
}
}
// Find source ItemUom by itemId and uomId
val sourceItemUom = itemUomRespository.findByItemIdAndUomIdAndDeletedIsFalse(request.itemId, request.uomId)
?: throw IllegalArgumentException("Source ItemUom not found for itemId=${request.itemId}, uomId=${request.uomId}")
@@ -155,10 +172,10 @@ open class ItemUomService(
val targetRatioD = targetItemUom.ratioD ?: one
// Convert source qty to base: qty * ratioN / ratioD
val baseQty = request.qty.multiply(sourceRatioN).divide(sourceRatioD, 2, RoundingMode.HALF_UP)
val baseQty = request.qty.multiply(sourceRatioN).divide(sourceRatioD, 2, RoundingMode.UP)
// Convert base to target: baseQty * ratioD / ratioN
val newQty = baseQty.multiply(targetRatioD).divide(targetRatioN, 2, RoundingMode.HALF_UP)
val newQty = baseQty.multiply(targetRatioD).divide(targetRatioN, 2, RoundingMode.UP)
// Get UomConversion from target ItemUom
val uomConversion = targetItemUom.uom


+ 1
- 0
src/main/java/com/ffii/fpsms/modules/master/web/models/DeleteResponse.kt Переглянути файл

@@ -6,3 +6,4 @@ data class DeleteResponse(
val canDelete: Boolean = true
)



+ 1
- 0
src/main/java/com/ffii/fpsms/modules/master/web/models/ItemQcCategoryMappingInfo.kt Переглянути файл

@@ -11,3 +11,4 @@ data class ItemQcCategoryMappingInfo(
val type: String?
)



+ 1
- 0
src/main/java/com/ffii/fpsms/modules/master/web/models/QcCategoryWithItemCount.kt Переглянути файл

@@ -8,3 +8,4 @@ data class QcCategoryWithItemCount(
val itemCount: Long
)



+ 1
- 0
src/main/java/com/ffii/fpsms/modules/master/web/models/QcCategoryWithQcItemCount.kt Переглянути файл

@@ -8,3 +8,4 @@ data class QcCategoryWithQcItemCount(
val qcItemCount: Long
)



+ 2
- 1
src/main/java/com/ffii/fpsms/modules/productProcess/entity/ProductProcessLine.kt Переглянути файл

@@ -105,7 +105,8 @@ open class ProductProcessLine : BaseEntity<Long>() {
@Column(name = "startTime")
open var startTime: LocalDateTime? = null
@Column(name = "is_original")
open var isOriginal: Boolean? = null
@Column(name = "endTime")
open var endTime: LocalDateTime? = null
@ManyToOne(fetch = FetchType.LAZY)


+ 7
- 4
src/main/java/com/ffii/fpsms/modules/productProcess/entity/projections/ProductProcessInfo.kt Переглянути файл

@@ -10,9 +10,9 @@ data class ProductProcessInfo(
val id: Long?,
val productProcessCode: String?,
val status: ProductProcessStatus?,
@JsonFormat(pattern = "MM-dd HH:mm")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
val startTime: LocalDateTime?,
@JsonFormat(pattern = "MM-dd HH:mm")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
val endTime: LocalDateTime?,
@JsonFormat(pattern = "yyyy-MM-dd")
val date: LocalDate?,
@@ -80,10 +80,11 @@ data class ProductProcessLineInfo(
val durationInMinutes: Int?,
val prepTimeInMinutes: Int?,
val postProdTimeInMinutes: Int?,
@JsonFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
val startTime: LocalDateTime?,
@JsonFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
val endTime: LocalDateTime?,
val isOringinal: Boolean?,
)


@@ -97,6 +98,8 @@ data class jobOrderLineInfo(
val reqQty: Int?,
val baseReqQty: Int?,

val stockReqQty: Int?,

val stockQty: Int?,
val baseStockQty: Int?,



+ 306
- 13
src/main/java/com/ffii/fpsms/modules/productProcess/service/ProductProcessService.kt Переглянути файл

@@ -140,6 +140,7 @@ open class ProductProcessService(
this.name = bomProcess.process?.name
this.description = bomProcess.description
this.equipmentType = bomProcess.equipment?.name
this.isOriginal = true
}
productProcessLineRepository.save(line)
println("➕ Service: Created line ${index + 1} - seq: ${line.seqNo}, name: ${line.name}")
@@ -239,6 +240,7 @@ open class ProductProcessService(
this.name = request.name
this.description = request.description
this.equipmentType = request.equipmentType
this.isOriginal = false
}
val saved = productProcessLineRepository.save(line)
@@ -587,14 +589,14 @@ val sufficientStockQty = bomMaterials
else -> ""
}
}
return productProcesses.map { process ->

val jobType = jobTypeRepository.findById(process.jobOrder?.jobTypeId?:0L).orElse(null)

//val joPickOrders = joPickOrderRepository.findByJobOrderId(process.jobOrder?.id?:0L)
println("jobType id ${process.jobOrder?.jobTypeId}")
val newCreatedLineIds = findNewCreatedLineIds(process.id ?: 0L, bom?.id ?: 0L)
ProductProcessInfo(
id = process.id?:0,
bomId = process.bom?.id?:0,
@@ -667,7 +669,8 @@ val sufficientStockQty = bomMaterials
outputFromProcessQty = line.outputFromProcessQty?:0,
outputFromProcessUom = line.outputFromProcessUom?:"",
startTime = line.startTime,
endTime = line.endTime
endTime = line.endTime,
isOringinal = line.isOriginal?:false
)
}.sortedBy { it.seqNo },
@@ -762,8 +765,8 @@ val sufficientStockQty = bomMaterials
val targetRatioN = targetItemUom.ratioN ?: BigDecimal.ONE
val targetRatioD = targetItemUom.ratioD ?: BigDecimal.ONE
val baseQty = stockQtyValue.multiply(sourceRatioN).divide(sourceRatioD, 2, RoundingMode.HALF_UP)
val finalQty = baseQty.multiply(targetRatioD).divide(targetRatioN, 2, RoundingMode.HALF_UP)
val baseQty = stockQtyValue.multiply(sourceRatioN).divide(sourceRatioD, 2, RoundingMode.UP)
val finalQty = baseQty.multiply(targetRatioD).divide(targetRatioN, 2, RoundingMode.UP)
println(" Calculation: baseQty = $stockQtyValue * $sourceRatioN / $sourceRatioD = $baseQty")
println(" Calculation: finalQty = $baseQty * $targetRatioD / $targetRatioN = $finalQty")
@@ -793,10 +796,83 @@ val sufficientStockQty = bomMaterials
// Use the same baseUomName for stockBaseUom since it's the same base unit
val baseStockUomName = baseUomName
val baseStockShortUom = baseShortUom
println("Final values - reqQty: ${line.reqQty?.toInt()}, baseReqQty: $baseReqQty, stockQty: $stockQty, baseStockQty: $baseStockQty")


val reqStockQtyResult = if (reqUomId > 0 && stockUomId != null && stockUomId > 0 && reqUomId != stockUomId) {
try {
// Convert reqQty from reqUomId to stockUomId via baseUnit
// First convert to baseUnit
val baseReqQtyForStock = if (baseReqQtyResult != null) {
baseReqQtyResult.newQty
} else {
// If baseReqQty conversion failed, try again
try {
itemUomService.convertUomByItem(
ConvertUomByItemRequest(
itemId = itemId,
qty = line.reqQty ?: BigDecimal.ZERO,
uomId = reqUomId,
targetUnit = "baseUnit"
)
).newQty
} catch (e: Exception) {
println("Error converting reqQty to baseUnit for stock conversion: ${e.message}")
null
}
}
if (baseReqQtyForStock != null) {
// Now convert from baseUnit to stockUomId
val sourceItemUom = itemUomService.findBaseUnitByItemId(itemId)
val targetItemUom = itemUomRepository.findByItemIdAndUomIdAndDeletedIsFalse(itemId, stockUomId)
if (sourceItemUom != null && targetItemUom != null) {
val sourceRatioN = sourceItemUom.ratioN ?: BigDecimal.ONE
val sourceRatioD = sourceItemUom.ratioD ?: BigDecimal.ONE
val targetRatioN = targetItemUom.ratioN ?: BigDecimal.ONE
val targetRatioD = targetItemUom.ratioD ?: BigDecimal.ONE
// Convert base to stock: baseQty * targetRatioD / targetRatioN
val stockQtyDecimal = baseReqQtyForStock.multiply(targetRatioD).divide(targetRatioN, 2, RoundingMode.UP)
val stockQty = stockQtyDecimal.setScale(0, RoundingMode.UP) // Round up to integer
val stockUom = uomConversionRepository.findByIdAndDeletedFalse(stockUomId)
println("Converting reqQty to stock unit: ${line.reqQty} (UOM id=$reqUomId) -> $stockQty (UOM id=$stockUomId)")
ConvertUomByItemResponse(
newQty = stockQty,
udfudesc = stockUom?.udfudesc,
udfShortDesc = stockUom?.udfShortDesc
)
} else {
println("WARNING: Cannot convert reqQty to stock unit - missing ItemUom (sourceItemUom=${sourceItemUom != null}, targetItemUom=${targetItemUom != null})")
null
}
} else {
null
}
} catch (e: Exception) {
println("Error converting reqQty to stock unit: ${e.message}")
e.printStackTrace()
null
}
} else if (reqUomId > 0 && stockUomId != null && stockUomId > 0 && reqUomId == stockUomId) {
// If reqUomId and stockUomId are the same, no conversion needed
val stockUom = uomConversionRepository.findByIdAndDeletedFalse(stockUomId)
ConvertUomByItemResponse(
newQty = line.reqQty ?: BigDecimal.ZERO,
udfudesc = stockUom?.udfudesc,
udfShortDesc = stockUom?.udfShortDesc
)
} else {
println("Cannot convert reqQty to stock unit - reqUomId=$reqUomId, stockUomId=$stockUomId")
null
}
val reqStockQty = reqStockQtyResult?.newQty?.toInt() ?: 0
println("Final values - reqQty: ${line.reqQty?.toInt()}, baseReqQty: $baseReqQty, stockQty: $stockQty, baseStockQty: $baseStockQty, reqStockQty: $reqStockQty")
// Find BomProcessMaterial
val bomProcessMaterial = bomMaterial?.id?.let { bomMaterialId ->
bomProcessIds.firstNotNullOfOrNull { bomProcessId ->
@@ -825,6 +901,7 @@ val sufficientStockQty = bomMaterials
baseReqQty = baseReqQty,
// Add this field if not exists
stockQty = stockQty,
stockReqQty = reqStockQty,
baseStockQty = baseStockQty, // Add this field if not exists
reqUom = uomName ?: "",
reqBaseUom = baseUomName ?: "",
@@ -879,6 +956,7 @@ val sufficientStockQty = bomMaterials
this.processingTime = bomProcess.durationInMinute
this.setupTime = bomProcess.prepTimeInMinute
this.changeoverTime = bomProcess.postProdTimeInMinute
this.isOriginal=true
}
productProcessLineRepository.save(productProcessLine)
}
@@ -1732,9 +1810,12 @@ val sufficientStockQty = bomMaterials
this.defectDescription3 = sourceLine.defectDescription3
this.outputFromProcessQty = sourceLine.outputFromProcessQty
this.outputFromProcessUom = sourceLine.outputFromProcessUom
// 不复制时间字段,新 line 应该没有开始和结束时间
this.processingTime = sourceLine.processingTime
this.setupTime = sourceLine.setupTime
this.changeoverTime = sourceLine.changeoverTime
this.startTime = null
this.endTime = null
this.isOriginal = false
}
// 保存新 line(原 line 的 seqNo 保持不变,不需要更新)
@@ -1754,13 +1835,18 @@ open fun getJobProcessStatus(): List<JobProcessStatusResponse> {
val productProcesses = productProcessRepository.findAllByDeletedIsFalse()
.filter { it.status != ProductProcessStatus.COMPLETED }
return productProcesses.map { process ->
return productProcesses.mapNotNull { process ->
val jobOrder = jobOrderRepository.findById(process.jobOrder?.id ?: 0L).orElse(null)
// Filter out jobOrders in PLANNING status
if (jobOrder?.status == JobOrderStatus.PLANNING) {
return@mapNotNull null
}
val lines = productProcessLineRepository.findByProductProcess_Id(process.id ?: 0L)
.sortedBy { it.seqNo }
val bom=bomRepository.findById(process.bom?.id ?: 0L).orElse(null)

//val equipmentDetail = equipmentDetailRepository.findById(equipmentDetailId).orElse(null)
// Calculate planEndTime based on first start time + remaining processing time
val firstStartTime = lines.firstOrNull { it.startTime != null }?.startTime
val calculatedPlanEndTime = if (firstStartTime != null) {
@@ -1786,15 +1872,34 @@ open fun getJobProcessStatus(): List<JobProcessStatusResponse> {
jobOrderCode = jobOrder?.code ?: "",
itemCode = process.item?.code ?: "",
itemName = process.item?.name ?: "",
status = process.status?.value ?: "",
planEndTime = calculatedPlanEndTime,
processes = (0 until 6).map { index ->
if (index < lines.size) {
val line = lines[index]
val bomProcesses = bomProcessRepository.findByBomId(bom?.id ?: 0L).sortedBy { it.seqNo }
val equipmentDetailId = line.equipmentDetailId
// Use line's own data instead of indexing into bomProcesses
val equipmentCode = when {
equipmentDetailId != null -> {
equipmentDetailRepository.findById(equipmentDetailId).orElse(null)?.code ?: ""
}
line.equipment?.code != null -> {
line.equipment?.code ?: ""
}
else -> {
// Safely access bomProcess - it might be deleted
try {
line.bomProcess?.equipment?.code ?: ""
} catch (e: jakarta.persistence.EntityNotFoundException) {
// BomProcess was deleted, fallback to equipmentType
""
}.takeIf { it.isNotEmpty() } ?: (line.equipmentType ?: "")
}
}
ProcessStatusInfo(

equipmentCode = if(equipmentDetailId != null) equipmentDetailRepository.findById(equipmentDetailId).orElse(null)?.code ?: "" else bomProcesses[index].equipment?.code ?: "",
equipmentCode = equipmentCode,
startTime = line.startTime,
endTime = line.endTime,
processingTime = line.processingTime,
@@ -1817,6 +1922,194 @@ open fun getJobProcessStatus(): List<JobProcessStatusResponse> {
)
}
}
private fun findNewCreatedLineIds(productProcessId: Long, bomId: Long): Set<Long> {
// 获取 BOM 的所有 bomProcess,创建一个映射:bomProcessId -> seqNo
val bomProcessMap = bomProcessRepository.findByBomId(bomId)
.associate { it.id to (it.seqNo ?: 0L) }
if (bomProcessMap.isEmpty()) {
return emptySet()
}
// 获取所有 line,按 seqNo 排序
val allLines = productProcessLineRepository.findByProductProcess_Id(productProcessId)
.sortedBy { it.seqNo ?: 0L }
println("=== findNewCreatedLineIds DEBUG START ===")
println("BOM bomProcessMap: $bomProcessMap")
println("All lines (sorted by seqNo):")
allLines.forEach { line ->
println(" id=${line.id}, seqNo=${line.seqNo}, bomProcessId=${line.bomProcess?.id}")
}
// 创建一个集合来跟踪哪些 line 是新创建的
val newCreatedLineIds = mutableSetOf<Long>()
// 迭代检查,直到所有剩余的 line 都匹配
var iteration = 0
var hasChanges = true
while (hasChanges) {
iteration++
hasChanges = false
println("\n--- Iteration $iteration ---")
// 获取剩余的 line(排除已标记为新创建的),按 seqNo 排序
val remainingLines = allLines.filter { it.id !in newCreatedLineIds }
.sortedBy { it.seqNo ?: 0L }
println("Remaining lines (excluding new created):")
remainingLines.forEach { line ->
println(" id=${line.id}, seqNo=${line.seqNo}, bomProcessId=${line.bomProcess?.id}")
}
println("New created line IDs so far: $newCreatedLineIds")
// 计算每个剩余 line 的期望 seqNo(应该是连续的 1, 2, 3...)
val expectedSeqNoMap = remainingLines.mapIndexed { index, line ->
line.id to (index + 1).toLong()
}.toMap()
println("Expected seqNo map:")
expectedSeqNoMap.forEach { (lineId, expectedSeqNo) ->
println(" lineId=$lineId -> expectedSeqNo=$expectedSeqNo")
}
// 检查每个剩余 line
for (line in remainingLines) {
val bomProcessId = line.bomProcess?.id
val expectedSeqNo = expectedSeqNoMap[line.id] ?: continue
println("\nChecking line id=${line.id}, seqNo=${line.seqNo}, bomProcessId=$bomProcessId, expectedSeqNo=$expectedSeqNo")
if (bomProcessId == null) {
println(" -> No bomProcessId, marking as new created")
newCreatedLineIds.add(line.id ?: 0L)
hasChanges = true
continue
}
// 查找这个 bomProcessId 在 BOM 中的实际 seqNo
val bomProcessSeqNo = bomProcessMap[bomProcessId]
println(" -> BOM bomProcessId=$bomProcessId has seqNo=$bomProcessSeqNo in BOM")
if (bomProcessSeqNo == null) {
println(" -> bomProcessId not found in BOM, marking as new created")
newCreatedLineIds.add(line.id ?: 0L)
hasChanges = true
continue
}
// 检查 line 的期望 seqNo 是否匹配 BOM 中 bomProcess 的 seqNo
if (expectedSeqNo != bomProcessSeqNo) {
println(" -> MISMATCH: expectedSeqNo=$expectedSeqNo != bomProcessSeqNo=$bomProcessSeqNo, marking as new created")
newCreatedLineIds.add(line.id ?: 0L)
hasChanges = true
} else {
println(" -> MATCH: expectedSeqNo=$expectedSeqNo == bomProcessSeqNo=$bomProcessSeqNo, keeping as original")
}
}
}
println("\n=== Final Result ===")
println("New created line IDs: $newCreatedLineIds")
println("=== findNewCreatedLineIds DEBUG END ===\n")
return newCreatedLineIds
}

// 辅助函数:判断是否是原始创建的 line(使用缓存的结果)
private fun isOriginalLine(productProcessLine: ProductProcessLine, newCreatedLineIds: Set<Long>): Boolean {
val currentLineId = productProcessLine.id ?: 0L
return currentLineId !in newCreatedLineIds
}

open fun deleteProductProcessLine(productProcessLineId: Long): MessageResponse {
val productProcessLine = productProcessLineRepository.findById(productProcessLineId).orElse(null)
?: return MessageResponse(
id = productProcessLineId,
code = "404",
name = "ProductProcess Line Not Found",
type = "error",
message = "ProductProcess Line with ID $productProcessLineId not found",
errorPosition = null,
)
val productProcessId = productProcessLine.productProcess?.id ?: return MessageResponse(
id = productProcessLineId,
code = "400",
name = "Invalid ProductProcess",
type = "error",
message = "ProductProcess Line has no associated ProductProcess",
errorPosition = null,
)
// 检查 JobOrder 状态
val productProcess = productProcessRepository.findById(productProcessId).orElse(null)
val jobOrder = productProcess?.jobOrder
if (jobOrder?.status != JobOrderStatus.PLANNING) {
return MessageResponse(
id = productProcessLineId,
code = "400",
name = "JobOrder Not In Planning",
type = "error",
message = "Cannot delete line when JobOrder is not in planning status",
errorPosition = null,
)
}
// 检查是否是原始 line(使用 ID 判断)
val bomId = productProcess?.bom?.id ?: return MessageResponse(
id = productProcessLineId,
code = "400",
name = "Invalid BOM",
type = "error",
message = "ProductProcess has no associated BOM",
errorPosition = null,
)
// 获取新创建的 line IDs
val newCreatedLineIds = findNewCreatedLineIds(productProcessId, bomId)
// 检查是否是原始 line
if (productProcessLine.isOriginal == true) {
return MessageResponse(
id = productProcessLineId,
code = "400",
name = "Cannot Delete Original Line",
type = "error",
message = "Cannot delete original process line. Only newly created lines can be deleted.",
errorPosition = null,
)
}
val deletedSeqNo = productProcessLine.seqNo ?: 0L
// 删除 line
productProcessLineRepository.delete(productProcessLine)
// 获取所有剩余的 lines,按 seqNo 排序,然后调整 seqNo
val remainingLines = productProcessLineRepository.findByProductProcess_Id(productProcessId)
.sortedBy { it.seqNo ?: 0L }
// 更新所有 seqNo > deletedSeqNo 的 lines,将它们的 seqNo 减 1
remainingLines.filter {
it.seqNo != null &&
it.seqNo!! > deletedSeqNo
}.forEach { line ->
line.seqNo = (line.seqNo ?: 0) - 1
productProcessLineRepository.save(line)
}
return MessageResponse(
id = productProcessLineId,
code = "200",
name = "ProductProcess Line Deleted",
type = "success",
message = "ProductProcess Line deleted successfully",
errorPosition = null,
)
}
}


+ 4
- 0
src/main/java/com/ffii/fpsms/modules/productProcess/web/ProductProcessController.kt Переглянути файл

@@ -229,4 +229,8 @@ class ProductProcessController(
fun getJobProcessStatus(): List<JobProcessStatusResponse> {
return productProcessService.getJobProcessStatus()
}
@PostMapping("/Demo/ProcessLine/delete/{lineId}")
fun deleteProductProcessLine(@PathVariable lineId: Long): MessageResponse {
return productProcessService.deleteProductProcessLine(lineId)
}
}

+ 1
- 0
src/main/java/com/ffii/fpsms/modules/productProcess/web/model/SaveProductProcessRequest.kt Переглянути файл

@@ -235,5 +235,6 @@ data class JobProcessStatusResponse(
val itemCode: String,
val itemName: String,
val planEndTime: LocalDateTime?,
val status: String,
val processes: List<ProcessStatusInfo>
)

Завантаження…
Відмінити
Зберегти