浏览代码

update so jo

master
CANCERYS\kw093 6 天前
父节点
当前提交
f8727734ac
共有 7 个文件被更改,包括 121 次插入4 次删除
  1. +17
    -1
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt
  2. +1
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/web/model/CreateJobOrderRequest.kt
  3. +37
    -1
      src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickExecutionIssueService.kt
  4. +6
    -1
      src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt
  5. +43
    -0
      src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt
  6. +5
    -1
      src/main/java/com/ffii/fpsms/modules/stock/web/InventoryLotLineController.kt
  7. +12
    -0
      src/main/java/com/ffii/fpsms/modules/stock/web/StockOutLineController.kt

+ 17
- 1
src/main/java/com/ffii/fpsms/modules/jobOrder/service/JoPickOrderService.kt 查看文件

@@ -494,7 +494,8 @@ open class JoPickOrderService(
uomShortDesc = uom?.udfShortDesc,
matchStatus = jpo?.matchStatus?.value,
matchBy = jpo?.matchBy,
matchQty = jpo?.matchQty?.toDouble()
matchQty = jpo?.matchQty?.toDouble(),
stockInLineId = null,
)
}

@@ -1914,6 +1915,15 @@ open fun getJobOrderLotsHierarchicalByPickOrderId(pickOrderId: Long): JobOrderLo
stockOutLineRepository.findAllByPickOrderLineIdAndDeletedFalse(polId)
}
// 获取 stock in lines 通过 inventoryLotLineId(用于填充 stockInLineId)
val stockInLinesByInventoryLotLineId = if (inventoryLotLineIds.isNotEmpty()) {
inventoryLotLineIds.associateWith { illId ->
stockInLineRepository.findStockInLineInfoByInventoryLotLineId(illId).orElse(null)?.id
}.filterValues { it != null }
} else {
emptyMap()
}
// 获取 jo_pick_order 记录
val joPickOrders = joPickOrderRepository.findByPickOrderId(pickOrder.id!!)
@@ -1983,6 +1993,11 @@ open fun getJobOrderLotsHierarchicalByPickOrderId(pickOrderId: Long): JobOrderLo
else -> "pending"
}
// 获取 stockInLineId
val stockInLineId = ill.id?.let { illId ->
stockInLinesByInventoryLotLineId[illId]
}
LotDetailResponse(
lotId = ill.id,
lotNo = il.lotNo,
@@ -2000,6 +2015,7 @@ open fun getJobOrderLotsHierarchicalByPickOrderId(pickOrderId: Long): JobOrderLo
pickOrderConsoCode = pickOrder.consoCode,
pickOrderLineId = pol.id,
stockOutLineId = sol?.id,
stockInLineId = stockInLineId,
suggestedPickLotId = spl.id,
stockOutLineQty = sol?.qty ?: 0.0,
stockOutLineStatus = sol?.status,


+ 1
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/web/model/CreateJobOrderRequest.kt 查看文件

@@ -109,6 +109,7 @@ data class LotDetailResponse(
val pickOrderConsoCode: String?,
val pickOrderLineId: Long?,
val stockOutLineId: Long?,
val stockInLineId: Long?,
val suggestedPickLotId: Long?,
val stockOutLineQty: Double?,
val stockOutLineStatus: String?,


+ 37
- 1
src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickExecutionIssueService.kt 查看文件

@@ -590,7 +590,7 @@ private fun handleMissItemOnly(request: PickExecutionIssueRequest, missQty: BigD
val newStatus = if (actualPickQtyDouble >= requiredQty) {
"completed"
} else {
"partially_completed"
"completed"
}
stockOutLine.status = newStatus
@@ -606,6 +606,42 @@ private fun handleMissItemOnly(request: PickExecutionIssueRequest, missQty: BigD
createStockLedgerForStockOut(savedStockOutLine, "Nor")
}
}

// ✅ NEW: If all stock_out_line under this pick order line are finished (completed/rejected),
// mark pick_order_line as COMPLETED. This is required for "miss all required qty" flows
// where qty can be 0 but picking decision is finalized via issue form.
try {
stockOutLineRepository.flush()

val allStockOutLines = stockOutLineRepository.findAllByPickOrderLineIdAndDeletedFalse(request.pickOrderLineId)
val unfinishedLines = allStockOutLines.filter {
it.status != StockOutLineStatus.COMPLETE.status &&
it.status != StockOutLineStatus.REJECTED.status
}

println("Miss item: Checking pick order line ${request.pickOrderLineId}")
println(" Total stock out lines: ${allStockOutLines.size}")
println(" Unfinished lines: ${unfinishedLines.size}")
unfinishedLines.forEach { line ->
println(" - Line ${line.id}: status=${line.status}")
}

if (unfinishedLines.isEmpty() && allStockOutLines.isNotEmpty()) {
val pickOrderLine = pickOrderLineRepository.findById(request.pickOrderLineId).orElse(null)
if (pickOrderLine != null) {
pickOrderLine.status = PickOrderLineStatus.COMPLETED
pickOrderLineRepository.saveAndFlush(pickOrderLine)
println("✅ Miss item: Updated pick order line ${request.pickOrderLineId} status to COMPLETED")
} else {
println("⚠️ Miss item: Pick order line ${request.pickOrderLineId} not found")
}
} else {
println("⚠️ Miss item: Pick order line ${request.pickOrderLineId} still has ${unfinishedLines.size} unfinished lines")
}
} catch (e: Exception) {
println("⚠️ Miss item: Error checking pick order line completion: ${e.message}")
e.printStackTrace()
}
// ✅ 修改:不重新建议拣货批次(因为 lot 仍然可用)
// resuggestPickOrder(request.pickOrderId) // 删除这行


+ 6
- 1
src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt 查看文件

@@ -51,6 +51,8 @@ import com.ffii.fpsms.modules.deliveryOrder.web.models.PrintQrCodeForDoRequest
import com.ffii.fpsms.modules.stock.service.InventoryLotLineService
import com.ffii.fpsms.modules.stock.entity.StockLedgerRepository
import com.ffii.fpsms.modules.stock.entity.InventoryRepository
import org.springframework.http.HttpStatus
import org.springframework.web.server.ResponseStatusException
@Serializable
data class QrContent(val itemId: Long, val stockInLineId: Long)

@@ -81,7 +83,10 @@ open class StockInLineService(
): AbstractBaseEntityService<StockInLine, Long, StockInLineRepository>(jdbcDao, stockInLineRepository) {

open fun getStockInLineInfo(stockInLineId: Long): StockInLineInfo {
return stockInLineRepository.findStockInLineInfoByIdAndDeletedFalse(stockInLineId)
// Use Optional-returning repository method to avoid EmptyResultDataAccessException
return stockInLineRepository.findStockInLineInfoById(stockInLineId).orElseThrow {
ResponseStatusException(HttpStatus.NOT_FOUND, "stockInLineId $stockInLineId not found")
}
}
open fun getReceivedStockInLineInfo(stockInLineId: Long): StockInLineInfo {
return stockInLineRepository.findStockInLineInfoByIdAndStatusAndDeletedFalse(id = stockInLineId, status = StockInLineStatus.RECEIVED.status).orElseThrow()


+ 43
- 0
src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt 查看文件

@@ -855,9 +855,11 @@ open fun batchSubmit(request: QrPickBatchSubmitRequest): MessageResponse {

@Transactional
open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineStatusByQRCodeAndLotNoRequest): MessageResponse {
val totalStartTime = System.currentTimeMillis()
val startTime = System.currentTimeMillis()
try {
println("=== QR SCAN REQUEST RECEIVED ===")
println("⏰ Request received at: ${java.time.LocalDateTime.now()}")
println(" Request details:")
println(" - stockOutLineId: ${request.stockOutLineId}")
println(" - pickOrderLineId: ${request.pickOrderLineId}")
@@ -865,10 +867,14 @@ open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineSta
println(" - itemId: ${request.itemId}")
println(" - status: ${request.status}")

// Step 1: Find StockOutLine
val findStockOutLineStart = System.currentTimeMillis()
val stockOutLine = stockOutLineRepository.findById(request.stockOutLineId).orElseThrow {
println(" StockOutLine not found with ID: ${request.stockOutLineId}")
IllegalArgumentException("StockOutLine not found with ID: ${request.stockOutLineId}")
}
val findStockOutLineTime = System.currentTimeMillis() - findStockOutLineStart
println("⏱️ [STEP 1] Find StockOutLine: ${findStockOutLineTime}ms")
println(" Found StockOutLine:")
println(" - ID: ${stockOutLine.id}")
@@ -878,8 +884,13 @@ open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineSta
println(" - Item ID: ${stockOutLine.item?.id}")
println(" - InventoryLotLine ID: ${stockOutLine.inventoryLotLine?.id}")
// Step 2: Get InventoryLotLine
val getInventoryLotLineStart = System.currentTimeMillis()
// 修复:从 stockOutLine.inventoryLotLine 获取 inventoryLot,而不是使用错误的参数
val inventoryLotLine = stockOutLine.inventoryLotLine
val getInventoryLotLineTime = System.currentTimeMillis() - getInventoryLotLineStart
println("⏱️ [STEP 2] Get InventoryLotLine: ${getInventoryLotLineTime}ms")
if (inventoryLotLine == null) {
println(" StockOutLine has no associated InventoryLotLine")
return MessageResponse(
@@ -892,7 +903,12 @@ open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineSta
)
}
// Step 3: Get InventoryLot
val getInventoryLotStart = System.currentTimeMillis()
val inventoryLot = inventoryLotLine.inventoryLot
val getInventoryLotTime = System.currentTimeMillis() - getInventoryLotStart
println("⏱️ [STEP 3] Get InventoryLot: ${getInventoryLotTime}ms")
if (inventoryLot == null) {
println(" InventoryLotLine has no associated InventoryLot")
return MessageResponse(
@@ -911,9 +927,13 @@ open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineSta
println(" - Item ID: ${inventoryLot.item?.id}")
println(" - InventoryLot ID: ${inventoryLot.id}")

// Step 4: Validation
val validationStart = System.currentTimeMillis()
// 修复:比较逻辑
val lotNoMatch = inventoryLot.lotNo == request.inventoryLotNo
val itemIdMatch = inventoryLot.item?.id == request.itemId
val validationTime = System.currentTimeMillis() - validationStart
println("⏱️ [STEP 4] Validation: ${validationTime}ms")
println(" Matching results:")
println(" - Lot No match: $lotNoMatch (Expected: ${inventoryLot.lotNo}, Got: ${request.inventoryLotNo})")
@@ -923,6 +943,8 @@ open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineSta
println(" MATCH SUCCESS: Lot and Item both match!")
// Step 5: Update StockOutLine
val updateStart = System.currentTimeMillis()
stockOutLine.status = request.status
if (request.status == "checked") {
stockOutLine.startTime = LocalDateTime.now()
@@ -930,15 +952,30 @@ open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineSta
if (request.status == "completed") {
stockOutLine.endTime = LocalDateTime.now()
}
val updateTime = System.currentTimeMillis() - updateStart
println("⏱️ [STEP 5] Update entity: ${updateTime}ms")
// Step 6: Save to database
val saveStart = System.currentTimeMillis()
val savedStockOutLine = stockOutLineRepository.saveAndFlush(stockOutLine)
val saveTime = System.currentTimeMillis() - saveStart
println("⏱️ [STEP 6] Save to DB: ${saveTime}ms")
println(" Status updated successfully:")
println(" - New status: ${savedStockOutLine.status}")
println(" - StockOutLine ID: ${savedStockOutLine.id}")
// Step 7: Fetch mapped info
val fetchMappedStart = System.currentTimeMillis()
val mappedStockOutLine = stockOutLineRepository.findStockOutLineInfoById(savedStockOutLine.id!!)
val fetchMappedTime = System.currentTimeMillis() - fetchMappedStart
println("⏱️ [STEP 7] Fetch mapped info: ${fetchMappedTime}ms")
val totalTime = System.currentTimeMillis() - totalStartTime
println("=== QR SCAN COMPLETED SUCCESSFULLY ===")
println("⏱️ [TOTAL BACKEND TIME] ${totalTime}ms (${totalTime / 1000.0}s)")
println("📊 Breakdown: findStockOutLine=${findStockOutLineTime}ms, getInventoryLotLine=${getInventoryLotLineTime}ms, getInventoryLot=${getInventoryLotTime}ms, validation=${validationTime}ms, update=${updateTime}ms, save=${saveTime}ms, fetchMapped=${fetchMappedTime}ms")
println("⏰ Completed at: ${java.time.LocalDateTime.now()}")
return MessageResponse(
id = savedStockOutLine.id,
@@ -951,6 +988,8 @@ open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineSta
)
} else if (!lotNoMatch && itemIdMatch) {
// Item 匹配但 lotNo 不匹配
val totalTime = System.currentTimeMillis() - totalStartTime
println("⏱️ [TOTAL BACKEND TIME] ${totalTime}ms (LOT MISMATCH)")
println(" LOT NUMBER MISMATCH:")
println(" - Expected lotNo: ${inventoryLot.lotNo}, Got: ${request.inventoryLotNo}")
println(" - Item ID matches: ${inventoryLot.item?.id} == ${request.itemId}")
@@ -965,6 +1004,8 @@ open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineSta
)
} else {
// Item 不匹配
val totalTime = System.currentTimeMillis() - totalStartTime
println("⏱️ [TOTAL BACKEND TIME] ${totalTime}ms (ITEM MISMATCH)")
println(" ITEM MISMATCH:")
println(" - Expected itemId: ${inventoryLot.item?.id}, Got: ${request.itemId}")
println(" - Expected lotNo: ${inventoryLot.lotNo}, Got: ${request.inventoryLotNo}")
@@ -980,6 +1021,8 @@ open fun updateStockOutLineStatusByQRCodeAndLotNo(request: UpdateStockOutLineSta
}

} catch (e: Exception) {
val totalTime = System.currentTimeMillis() - totalStartTime
println("⏱️ [TOTAL BACKEND TIME] ${totalTime}ms (ERROR)")
println(" ERROR updating stock out line status by QR: ${e.message}")
println(" Exception type: ${e.javaClass.simpleName}")
println(" Stack trace:")


+ 5
- 1
src/main/java/com/ffii/fpsms/modules/stock/web/InventoryLotLineController.kt 查看文件

@@ -26,6 +26,8 @@ import com.ffii.fpsms.modules.master.web.models.MessageResponse
import com.ffii.fpsms.modules.stock.web.model.UpdateInventoryLotLineStatusRequest
import com.ffii.fpsms.modules.stock.web.model.QrCodeAnalysisRequest
import com.ffii.fpsms.modules.stock.web.model.QrCodeAnalysisResponse
import org.springframework.http.HttpStatus
import org.springframework.web.server.ResponseStatusException

@RequestMapping("/inventoryLotLine")
@RestController
@@ -53,7 +55,9 @@ class InventoryLotLineController (

@GetMapping("/lot-detail/{stockInLineId}")
fun getLotDetail(@Valid @PathVariable stockInLineId: Long): LotLineInfo {
val stockInLine = stockInLineRepository.findById(stockInLineId).orElseThrow()
val stockInLine = stockInLineRepository.findById(stockInLineId).orElseThrow {
ResponseStatusException(HttpStatus.NOT_FOUND, "stockInLineId $stockInLineId not found")
}
val inventoryLotLine = stockInLine.inventoryLotLine!!
val zero = BigDecimal.ZERO
return LotLineInfo(


+ 12
- 0
src/main/java/com/ffii/fpsms/modules/stock/web/StockOutLineController.kt 查看文件

@@ -52,8 +52,10 @@ class StockOutLineController(
}
@PostMapping("/updateStatusByQRCodeAndLotNo")
fun updateStatusByQRCodeAndLotNo(@Valid @RequestBody request: UpdateStockOutLineStatusByQRCodeAndLotNoRequest): MessageResponse {
val controllerStartTime = System.currentTimeMillis()
try {
println("=== CONTROLLER: updateStatusByQRCodeAndLotNo called ===")
println("⏰ Controller start time: ${java.time.LocalDateTime.now()}")
println(" Request received:")
println(" - stockOutLineId: ${request.stockOutLineId}")
println(" - pickOrderLineId: ${request.pickOrderLineId}")
@@ -61,11 +63,21 @@ class StockOutLineController(
println(" - itemId: ${request.itemId}")
println(" - status: ${request.status}")
// Measure service call time
val serviceCallStart = System.currentTimeMillis()
val result = stockOutLineService.updateStockOutLineStatusByQRCodeAndLotNo(request)
val serviceCallTime = System.currentTimeMillis() - serviceCallStart
println("⏱️ [CONTROLLER] Service call time: ${serviceCallTime}ms (${serviceCallTime / 1000.0}s)")
val controllerTotalTime = System.currentTimeMillis() - controllerStartTime
println("⏱️ [CONTROLLER] Total controller time: ${controllerTotalTime}ms (${controllerTotalTime / 1000.0}s)")
println("📊 Controller breakdown: serviceCall=${serviceCallTime}ms, overhead=${controllerTotalTime - serviceCallTime}ms")
println(" CONTROLLER: Service call completed, returning result")
println("⏰ Controller end time: ${java.time.LocalDateTime.now()}")
return result
} catch (e: Exception) {
val controllerTotalTime = System.currentTimeMillis() - controllerStartTime
println("⏱️ [CONTROLLER] Total time before error: ${controllerTotalTime}ms")
println(" CONTROLLER ERROR: ${e.message}")
println(" Exception type: ${e.javaClass.simpleName}")
e.printStackTrace()


正在加载...
取消
保存