ソースを参照

update

master
CANCERYS\kw093 5時間前
コミット
7bb8d45483
6個のファイルの変更118行の追加54行の削除
  1. +66
    -40
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt
  2. +4
    -4
      src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt
  3. +25
    -5
      src/main/java/com/ffii/fpsms/modules/productProcess/service/ProductProcessService.kt
  4. +2
    -0
      src/main/java/com/ffii/fpsms/modules/productProcess/web/model/SaveProductProcessRequest.kt
  5. +9
    -1
      src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt
  6. +12
    -4
      src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt

+ 66
- 40
src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt ファイルの表示

@@ -12,7 +12,7 @@ import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDate
import com.ffii.fpsms.modules.stock.entity.enum.InventoryLotLineStatus
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderLineStatus
import java.time.LocalDateTime
@@ -48,6 +48,7 @@ import com.ffii.fpsms.modules.jobOrder.web.model.LotDetailResponse

import com.ffii.fpsms.modules.stock.entity.enum.StockInLineStatus
import com.ffii.fpsms.modules.stock.entity.StockInLineRepository
import java.time.LocalDate
@Service
open class JoPickOrderService(
private val joPickOrderRepository: JoPickOrderRepository,
@@ -1305,50 +1306,75 @@ open fun getCompletedJobOrderPickOrdersWithCompletedSecondScan(): List<Map<Strin
emptyList()
}
}
open fun getJobOrderListForPrintQrCode(): List<JobOrderListForPrintQrCodeResponse> {
println("=== getJobOrderListForPrintQrCode ===")
return try {
val jobOrders = jobOrderRepository.findAllByStatusIn(listOf(JobOrderStatus.COMPLETED))
// Get all stockInLines and filter for "received" status and BOM type "半成品"
val allStockInLines = stockInLineRepository.findAll()
val stockInLines = allStockInLines.filter {
it.jobOrder != null &&
it.status == "received" &&
it.deleted == false &&
it.jobOrder?.bom?.description == "半成品"
}
val result = mutableListOf<JobOrderListForPrintQrCodeResponse>()

for (stockInLine in stockInLines) {
val jobOrder = jobOrders.find { it.id == stockInLine.jobOrder?.id }
if (jobOrder != null && jobOrder.bom?.description == "半成品") {
// Check if this job order is already in the result (to avoid duplicates)
val existing = result.find {
it.stockInLineId == stockInLine.id
}
open fun getJobOrderListForPrintQrCode(date: LocalDate): List<JobOrderListForPrintQrCodeResponse> {
println("=== getJobOrderListForPrintQrCode ===")
println("Filtering by receiptDate: $date")
return try {
// 1. 根据 receiptDate 日期过滤 StockInLine(在数据库层面过滤)
val allStockInLines = stockInLineRepository.findByReceiptDateAndDeletedFalse(date)
println("📦 Found ${allStockInLines.size} StockInLines with receiptDate = $date")
println("📦 All StockInLines: ${allStockInLines.map { it.id }}, ${allStockInLines.map { it.jobOrder?.id }}")
println("📦 All StockInLines: ${allStockInLines.map { it.status }}, ${allStockInLines.map { it.jobOrder?.bom?.description }}")
// 2. 进一步过滤:status = "received" 或 "completed",且 BOM type = "WIP" 或 "FG"
val stockInLines = allStockInLines.filter {
it.jobOrder != null &&
it.status == "received" && // 只显示 QC 完成但尚未 putaway 的
it.jobOrder?.bom?.description in listOf("WIP", "FG")
}
println("✅ After filtering: ${stockInLines.size} StockInLines")

if (existing == null) {
val response = JobOrderListForPrintQrCodeResponse(
id = stockInLine.id!!,
code = jobOrder.code ?: "JO-${jobOrder.id}",
name = jobOrder.bom?.name ?: "",
reqQty = jobOrder.reqQty ?: BigDecimal.ZERO,
stockInLineId = stockInLine.id!!,
stockInLineQty = stockInLine.acceptedQty?.toDouble() ?: 0.0,
stockInLineStatus = stockInLine.status ?: "received",
finihedTime = jobOrder.planEnd ?: jobOrder.modified ?: LocalDateTime.now()
)
result.add(response)
}
// 3. 获取相关的 JobOrder IDs
val jobOrderIds = stockInLines.mapNotNull { it.jobOrder?.id }.distinct()
println("📋 JobOrder IDs to check: $jobOrderIds")

// 4. 批量加载 JobOrders(只加载需要的,且状态为 COMPLETED)
val jobOrders = if (jobOrderIds.isNotEmpty()) {
jobOrderRepository.findAllById(jobOrderIds)
.filter { it.status == JobOrderStatus.COMPLETED }
} else {
emptyList()
}
println("✅ Completed JobOrders: ${jobOrders.map { "${it.id}(${it.status})" }}")

// 5. 构建响应
val result = mutableListOf<JobOrderListForPrintQrCodeResponse>()

for (stockInLine in stockInLines) {
val jobOrder = jobOrders.find { it.id == stockInLine.jobOrder?.id }
if (jobOrder != null && jobOrder.bom?.description in listOf("WIP", "FG")) {
// Check if this job order is already in the result (to avoid duplicates)
val existing = result.find {
it.stockInLineId == stockInLine.id
}

if (existing == null) {
val response = JobOrderListForPrintQrCodeResponse(
id = stockInLine.id!!,
code = jobOrder.code ?: "JO-${jobOrder.id}",
name = jobOrder.bom?.name ?: "",
reqQty = jobOrder.reqQty ?: BigDecimal.ZERO,
stockInLineId = stockInLine.id!!,
stockInLineQty = stockInLine.acceptedQty?.toDouble() ?: 0.0,
stockInLineStatus = stockInLine.status ?: "received",
finihedTime = jobOrder.planEnd ?: jobOrder.modified ?: LocalDateTime.now()
)
result.add(response)
println("✅ Added StockInLine ${stockInLine.id} (JobOrder ${jobOrder.id}, BOM: ${jobOrder.bom?.description})")
}
} else {
println("❌ StockInLine ${stockInLine.id}: JobOrder ${stockInLine.jobOrder?.id} not found or BOM type not WIP/FG")
}
result
} catch (e: Exception) {
println("❌ Error in getJobOrderListForPrintQrCode: ${e.message}")
e.printStackTrace()
emptyList()
}
println("📊 Final result: ${result.size} items")
result
} catch (e: Exception) {
println("❌ Error in getJobOrderListForPrintQrCode: ${e.message}")
e.printStackTrace()
emptyList()
}
}
open fun getCompletedJobOrderPickOrderLotDetails(pickOrderId: Long): List<Map<String, Any?>> {
println("=== getCompletedJobOrderPickOrderLotDetails ===")
println("pickOrderId: $pickOrderId")


+ 4
- 4
src/main/java/com/ffii/fpsms/modules/jobOrder/web/JobOrderController.kt ファイルの表示

@@ -40,7 +40,7 @@ import com.ffii.fpsms.modules.jobOrder.web.model.UpdateJoPickOrderHandledByReque
import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderInfo
import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderInfoWithTypeName
import com.ffii.fpsms.modules.jobOrder.web.model.ExportFGStockInLabelRequest
import java.time.LocalDate

@RestController
@RequestMapping("/jo")
@@ -231,9 +231,9 @@ fun recordSecondScanIssue(
fun getCompletedJobOrderPickOrders(): List<Map<String, Any?>> {
return joPickOrderService.getCompletedJobOrderPickOrders()
}
@GetMapping("/joForPrintQrCode")
fun getJoForPrintQrCode(): List<JobOrderListForPrintQrCodeResponse> {
return joPickOrderService.getJobOrderListForPrintQrCode()
@GetMapping("/joForPrintQrCode/{date}")
fun getJoForPrintQrCode(@PathVariable date: String): List<JobOrderListForPrintQrCodeResponse> {
return joPickOrderService.getJobOrderListForPrintQrCode(LocalDate.parse(date))
}

@GetMapping("/completed-job-order-pick-order-lot-details-completed-pick/{pickOrderId}")


+ 25
- 5
src/main/java/com/ffii/fpsms/modules/productProcess/service/ProductProcessService.kt ファイルの表示

@@ -47,6 +47,7 @@ import java.time.ZoneOffset
import com.ffii.fpsms.modules.jobOrder.entity.JoPickOrderRepository
import com.ffii.fpsms.modules.jobOrder.enums.JoPickOrderStatus
import com.ffii.fpsms.modules.master.entity.UomConversionRepository
import com.ffii.fpsms.modules.master.entity.ItemUomRespository
@Service
@Transactional
open class ProductProcessService(
@@ -71,6 +72,7 @@ open class ProductProcessService(
private val pickOrderRepository: PickOrderRepository,
private val joPickOrderRepository: JoPickOrderRepository,
private val uomConversionRepository: UomConversionRepository,
private val itemUomRepository: ItemUomRespository,
) {
open fun findAll(pageable: Pageable): Page<ProductProcess> {
@@ -782,7 +784,7 @@ open class ProductProcessService(
code = "400",
name = "Equipment Validation Failed",
type = "error",
message = "Input Equipment ID($equipmentId) and BOM Process Equipment ID(${bomProcessEquipment?.id}) not match",
message = "Input Equipment is not match with prcess",
errorPosition = "equipmentId"
)
}
@@ -824,7 +826,7 @@ open class ProductProcessService(
code = "400",
name = "User Required",
type = "error",
message = "Staff No is required when equipment is provided",
message = "Staff No is required",
errorPosition = "staffNo"
)
}
@@ -839,7 +841,7 @@ open class ProductProcessService(
code = "400",
name = "Equipment Validation Failed",
type = "error",
message = "Input Equipment ID(${equipmentDetail.equipmentTypeId}) and BOM Process Equipment ID(${bomProcessEquipment?.id}) not match",
message = "Input Equipment is not match with process",
errorPosition = "equipmentId"
)
}
@@ -855,7 +857,22 @@ open class ProductProcessService(
errorPosition = "staffNo"
)
}

if (user != null && productProcessLine.operator != null) {
val existingOperatorId = productProcessLine.operator?.id
val newOperatorId = user.id
// 如果不是同一个用户,拒绝更新
if (existingOperatorId != null && existingOperatorId != newOperatorId) {
return MessageResponse(
id = request.productProcessLineId,
code = "409",
name = "Conflict",
type = "error",
message = "This process line is already assigned to another operator",
errorPosition = "operator"
)
}
}
// ===== 通过校验,开始更新 =====

// 设备有(且已通过匹配校验) → 更新 equipment / equipmentDetailId
@@ -1082,7 +1099,8 @@ open class ProductProcessService(
val stockInLineId = stockInLine?.id
val pickOrder = pickOrderRepository.findAllByJobOrder_Id(jobOrder?.id?:0L).firstOrNull()
val joPickOrdersList = joPickOrderRepository.findByPickOrderId(pickOrder?.id?:0L)

val itemUom = itemUomRepository.findByItemIdAndStockUnitIsTrueAndDeletedIsFalse(productProcesses.item?.id?:0L)
val bomUom = uomConversionRepository.findById(itemUom?.uom?.id?:0L).orElse(null)
//val silHandlerId = stockInLine?.escalationLog?.firstOrNull { it.status == "pending" }?.handler?.id

AllJoborderProductProcessInfoResponse(
@@ -1100,10 +1118,12 @@ open class ProductProcessService(
"pending"
},
RequiredQty = jobOrder?.reqQty?.toInt() ?: 0,
Uom = bomUom?.udfShortDesc,
date = productProcesses.date,
bomId = productProcesses.bom?.id,
assignedTo = pickOrder?.assignTo?.id,
itemName = productProcesses.item?.name,
itemCode = productProcesses.item?.code,
pickOrderId = pickOrder?.id,
pickOrderStatus = pickOrder?.status?.value,
jobOrderId = productProcesses.jobOrder?.id,


+ 2
- 0
src/main/java/com/ffii/fpsms/modules/productProcess/web/model/SaveProductProcessRequest.kt ファイルの表示

@@ -161,8 +161,10 @@ data class AllJoborderProductProcessInfoResponse(
val date: LocalDate?,
val bomId: Long?,
val itemName: String?,
val itemCode: String?,
val matchStatus: String?,
val RequiredQty: Int?,
val Uom: String?,
val jobOrderId: Long?,
val jobOrderCode: String?,
val assignedTo: Long?,


+ 9
- 1
src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt ファイルの表示

@@ -6,7 +6,7 @@ import com.ffii.fpsms.modules.stock.entity.projection.StockInLineInfo
import org.springframework.data.jpa.repository.Query
import org.springframework.stereotype.Repository
import java.util.Optional
import java.time.LocalDate
@Repository
interface StockInLineRepository : AbstractRepository<StockInLine, Long> {
fun findAllStockInLineInfoByStockInIdAndDeletedFalse(stockInId: Long): List<StockInLineInfo>
@@ -23,4 +23,12 @@ interface StockInLineRepository : AbstractRepository<StockInLine, Long> {

@Query("SELECT sil FROM StockInLine sil WHERE sil.item.id = :itemId AND sil.deleted = false")
fun findAllByItemIdAndDeletedFalse(itemId: Long): List<StockInLine>

@Query("""
SELECT sil FROM StockInLine sil
WHERE sil.receiptDate IS NOT NULL
AND DATE(sil.receiptDate) = :date
AND sil.deleted = false
""")
fun findByReceiptDateAndDeletedFalse(date: LocalDate): List<StockInLine>
}

+ 12
- 4
src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt ファイルの表示

@@ -421,10 +421,18 @@ open class StockInLineService(

if (inventoryLotLines.sumOf { it.inQty ?: BigDecimal.ZERO } >= request.acceptQty?.times(ratio)) {
stockInLine.apply {
this.status = if (request.acceptQty?.compareTo(request.acceptedQty) == 0)
StockInLineStatus.COMPLETE.status else StockInLineStatus.PARTIALLY_COMPLETE.status
// this.inventoryLotLine = savedInventoryLotLine
}
val isWipJobOrder = stockInLine.jobOrder?.bom?.description == "WIP"
this.status = if (isWipJobOrder) {
StockInLineStatus.COMPLETE.status
} else {
// For non-WIP, use original logic
if (request.acceptQty?.compareTo(request.acceptedQty) == 0)
StockInLineStatus.COMPLETE.status
else
StockInLineStatus.PARTIALLY_COMPLETE.status
}
// this.inventoryLotLine = savedInventoryLotLine
}
// Update JO Status
if (stockInLine.jobOrder != null) { //TODO Improve
val jo = stockInLine.jobOrder


読み込み中…
キャンセル
保存