|
|
@@ -11,12 +11,12 @@ import com.ffii.fpsms.modules.master.entity.EquipmentDetailRepository |
|
|
import com.ffii.fpsms.modules.productProcess.entity.projections.jobOrderLineInfo |
|
|
import com.ffii.fpsms.modules.productProcess.entity.projections.jobOrderLineInfo |
|
|
import org.springframework.stereotype.Service |
|
|
import org.springframework.stereotype.Service |
|
|
import org.springframework.transaction.annotation.Transactional |
|
|
import org.springframework.transaction.annotation.Transactional |
|
|
import java.time.LocalDate |
|
|
|
|
|
|
|
|
|
|
|
import java.time.LocalDateTime |
|
|
import java.time.LocalDateTime |
|
|
import java.time.temporal.ChronoUnit |
|
|
import java.time.temporal.ChronoUnit |
|
|
import com.ffii.fpsms.modules.user.entity.UserRepository |
|
|
import com.ffii.fpsms.modules.user.entity.UserRepository |
|
|
import com.ffii.fpsms.modules.user.entity.User |
|
|
import com.ffii.fpsms.modules.user.entity.User |
|
|
import java.time.format.DateTimeFormatter |
|
|
|
|
|
|
|
|
|
|
|
import com.ffii.fpsms.modules.master.entity.BomRepository |
|
|
import com.ffii.fpsms.modules.master.entity.BomRepository |
|
|
import com.ffii.fpsms.modules.master.entity.BomProcessRepository |
|
|
import com.ffii.fpsms.modules.master.entity.BomProcessRepository |
|
|
import com.ffii.fpsms.modules.jobOrder.entity.JobOrderRepository |
|
|
import com.ffii.fpsms.modules.jobOrder.entity.JobOrderRepository |
|
|
@@ -50,6 +50,9 @@ import com.ffii.fpsms.modules.master.entity.UomConversionRepository |
|
|
import com.ffii.fpsms.modules.master.entity.ItemUomRespository |
|
|
import com.ffii.fpsms.modules.master.entity.ItemUomRespository |
|
|
import com.ffii.fpsms.modules.master.web.models.* |
|
|
import com.ffii.fpsms.modules.master.web.models.* |
|
|
import java.math.RoundingMode |
|
|
import java.math.RoundingMode |
|
|
|
|
|
import java.time.LocalDate |
|
|
|
|
|
import java.time.format.DateTimeFormatter |
|
|
|
|
|
|
|
|
@Service |
|
|
@Service |
|
|
@Transactional |
|
|
@Transactional |
|
|
open class ProductProcessService( |
|
|
open class ProductProcessService( |
|
|
@@ -1783,42 +1786,35 @@ val sufficientStockQty = bomMaterials |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
open fun getJobProcessStatus(): List<JobProcessStatusResponse> { |
|
|
|
|
|
val productProcesses = productProcessRepository.findAllByDeletedIsFalse() |
|
|
|
|
|
.filter { it.status != ProductProcessStatus.COMPLETED } |
|
|
|
|
|
|
|
|
open fun getJobProcessStatus(date: LocalDate?): List<JobProcessStatusResponse> { |
|
|
|
|
|
val productProcesses = productProcessRepository.findAllByDeletedIsFalse() |
|
|
|
|
|
.let { list -> if (date == null) list else list.filter { it.date == date } } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return productProcesses.mapNotNull { process -> |
|
|
return productProcesses.mapNotNull { process -> |
|
|
val jobOrder = jobOrderRepository.findById(process.jobOrder?.id ?: 0L).orElse(null) |
|
|
val jobOrder = jobOrderRepository.findById(process.jobOrder?.id ?: 0L).orElse(null) |
|
|
|
|
|
|
|
|
// Filter out jobOrders in PLANNING status |
|
|
|
|
|
if (jobOrder?.status == JobOrderStatus.PLANNING) { |
|
|
|
|
|
return@mapNotNull null |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 仍然保留:PLANNING 不显示(如你也要显示,删掉这段) |
|
|
|
|
|
if (jobOrder?.status == JobOrderStatus.PLANNING) return@mapNotNull null |
|
|
|
|
|
|
|
|
val lines = productProcessLineRepository.findByProductProcess_Id(process.id ?: 0L) |
|
|
val lines = productProcessLineRepository.findByProductProcess_Id(process.id ?: 0L) |
|
|
.sortedBy { it.seqNo } |
|
|
.sortedBy { it.seqNo } |
|
|
val bom=bomRepository.findById(process.bom?.id ?: 0L).orElse(null) |
|
|
|
|
|
|
|
|
|
|
|
// Calculate planEndTime based on first start time + remaining processing time |
|
|
|
|
|
val firstStartTime = lines.firstOrNull { it.startTime != null }?.startTime |
|
|
val firstStartTime = lines.firstOrNull { it.startTime != null }?.startTime |
|
|
val calculatedPlanEndTime = if (firstStartTime != null) { |
|
|
val calculatedPlanEndTime = if (firstStartTime != null) { |
|
|
// Calculate total remaining processing time (in minutes) for unfinished processes |
|
|
|
|
|
var totalRemainingMinutes = 0L |
|
|
var totalRemainingMinutes = 0L |
|
|
lines.forEach { line -> |
|
|
lines.forEach { line -> |
|
|
if (line.endTime == null) { |
|
|
if (line.endTime == null) { |
|
|
// Process is not finished, add its processing time |
|
|
|
|
|
totalRemainingMinutes += (line.processingTime ?: 0).toLong() |
|
|
totalRemainingMinutes += (line.processingTime ?: 0).toLong() |
|
|
totalRemainingMinutes += (line.setupTime ?: 0).toLong() |
|
|
totalRemainingMinutes += (line.setupTime ?: 0).toLong() |
|
|
totalRemainingMinutes += (line.changeoverTime ?: 0).toLong() |
|
|
totalRemainingMinutes += (line.changeoverTime ?: 0).toLong() |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// Add remaining time to first start time |
|
|
|
|
|
firstStartTime.plusMinutes(totalRemainingMinutes) |
|
|
firstStartTime.plusMinutes(totalRemainingMinutes) |
|
|
} else { |
|
|
} else { |
|
|
// No process has started yet, use original planEndTime |
|
|
|
|
|
jobOrder?.planEnd |
|
|
jobOrder?.planEnd |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JobProcessStatusResponse( |
|
|
JobProcessStatusResponse( |
|
|
jobOrderId = jobOrder?.id ?: 0L, |
|
|
jobOrderId = jobOrder?.id ?: 0L, |
|
|
jobOrderCode = jobOrder?.code ?: "", |
|
|
jobOrderCode = jobOrder?.code ?: "", |
|
|
@@ -1829,29 +1825,20 @@ open fun getJobProcessStatus(): List<JobProcessStatusResponse> { |
|
|
processes = (0 until 6).map { index -> |
|
|
processes = (0 until 6).map { index -> |
|
|
if (index < lines.size) { |
|
|
if (index < lines.size) { |
|
|
val line = lines[index] |
|
|
val line = lines[index] |
|
|
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 ?: "") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// equipment.description + equipment_detail.name |
|
|
|
|
|
val equipmentDescription = line.equipment?.description |
|
|
|
|
|
?: try { line.bomProcess?.equipment?.description } catch (_: jakarta.persistence.EntityNotFoundException) { null } |
|
|
|
|
|
?: line.equipmentType |
|
|
|
|
|
|
|
|
|
|
|
val equipmentDetailName = line.equipmentDetailId?.let { id -> |
|
|
|
|
|
equipmentDetailRepository.findById(id).orElse(null)?.name |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ProcessStatusInfo( |
|
|
ProcessStatusInfo( |
|
|
equipmentCode = equipmentCode, |
|
|
|
|
|
|
|
|
processName = line.name, // ✅ 新增:工序名称 |
|
|
|
|
|
equipmentDescription = equipmentDescription, // ✅ 替代 equipmentCode |
|
|
|
|
|
equipmentDetailName = equipmentDetailName, // ✅ 新增 |
|
|
startTime = line.startTime, |
|
|
startTime = line.startTime, |
|
|
endTime = line.endTime, |
|
|
endTime = line.endTime, |
|
|
processingTime = line.processingTime, |
|
|
processingTime = line.processingTime, |
|
|
@@ -1861,13 +1848,15 @@ open fun getJobProcessStatus(): List<JobProcessStatusResponse> { |
|
|
) |
|
|
) |
|
|
} else { |
|
|
} else { |
|
|
ProcessStatusInfo( |
|
|
ProcessStatusInfo( |
|
|
|
|
|
processName = null, |
|
|
|
|
|
equipmentDescription = null, |
|
|
|
|
|
equipmentDetailName = null, |
|
|
startTime = null, |
|
|
startTime = null, |
|
|
endTime = null, |
|
|
endTime = null, |
|
|
processingTime = null, |
|
|
processingTime = null, |
|
|
setupTime = null, |
|
|
setupTime = null, |
|
|
changeoverTime = null, |
|
|
changeoverTime = null, |
|
|
isRequired = false, |
|
|
|
|
|
equipmentCode = null, |
|
|
|
|
|
|
|
|
isRequired = false |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|