Ver a proveniência

no message

master
kelvin.yau há 13 horas
ascendente
cometimento
a70a78db4b
3 ficheiros alterados com 123 adições e 87 eliminações
  1. +71
    -58
      src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt
  2. +47
    -29
      src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt
  3. +5
    -0
      src/main/resources/db/changelog/changes/20260413_01_codex/01_add_unique_index_delivery_note_code.sql

+ 71
- 58
src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt Ver ficheiro

@@ -39,6 +39,7 @@ import com.ffii.fpsms.modules.stock.web.model.SuggestedPickLotForPoRequest
import com.ffii.fpsms.modules.user.entity.UserRepository
import com.ffii.fpsms.modules.user.service.UserService
import org.springframework.data.domain.PageRequest
import org.springframework.dao.DataIntegrityViolationException
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Service
@@ -1343,36 +1344,31 @@ open class PickOrderService(
}
println(" All pick orders in this do_pick_order are completed, moving to record table")
val prefix = "DN"
val midfix = CodeGenerator.DEFAULT_MIDFIX
val latestCode = doPickOrderRecordRepository.findLatestDeliveryNoteCodeByPrefix("${prefix}-${midfix}")
val deliveryNoteCode = CodeGenerator.generateNo(prefix = prefix, midfix = midfix, latestCode = latestCode)
// 2) 先复制 do_pick_order -> do_pick_order_record
val dpoRecord = DoPickOrderRecord(
recordId =dpo.id,
storeId = dpo.storeId ?: "",
ticketNo = dpo.ticketNo ?: "",
ticketStatus = DoPickOrderStatus.completed,
truckId = dpo.truckId,
truckDepartureTime = dpo.truckDepartureTime,
shopId = dpo.shopId,
handledBy = dpo.handledBy,
handlerName = dpo.handlerName,
doOrderId = dpo.doOrderId,
pickOrderCode = dpo.pickOrderCode,
deliveryOrderCode = dpo.deliveryOrderCode,
deliveryNoteCode = deliveryNoteCode,
loadingSequence = dpo.loadingSequence,
ticketReleaseTime = dpo.ticketReleaseTime,
ticketCompleteDateTime = java.time.LocalDateTime.now(),
truckLanceCode = dpo.truckLanceCode,
shopCode = dpo.shopCode,
shopName = dpo.shopName,
requiredDeliveryDate = dpo.requiredDeliveryDate
)
val savedHeader = doPickOrderRecordRepository.save(dpoRecord)
val savedHeader = saveDoPickOrderRecordWithDnRetry { deliveryNoteCode ->
DoPickOrderRecord(
recordId = dpo.id,
storeId = dpo.storeId ?: "",
ticketNo = dpo.ticketNo ?: "",
ticketStatus = DoPickOrderStatus.completed,
truckId = dpo.truckId,
truckDepartureTime = dpo.truckDepartureTime,
shopId = dpo.shopId,
handledBy = dpo.handledBy,
handlerName = dpo.handlerName,
doOrderId = dpo.doOrderId,
pickOrderCode = dpo.pickOrderCode,
deliveryOrderCode = dpo.deliveryOrderCode,
deliveryNoteCode = deliveryNoteCode,
loadingSequence = dpo.loadingSequence,
ticketReleaseTime = dpo.ticketReleaseTime,
ticketCompleteDateTime = java.time.LocalDateTime.now(),
truckLanceCode = dpo.truckLanceCode,
shopCode = dpo.shopCode,
shopName = dpo.shopName,
requiredDeliveryDate = dpo.requiredDeliveryDate
)
}

// 3) 复制行 do_pick_order_line -> do_pick_order_line_record
val lines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(dpo.id!!)
@@ -1548,35 +1544,31 @@ open class PickOrderService(

private fun moveDoPickOrderToCompletedRecordAfterForce(dpo: DoPickOrder) {
val doOrderIdForDelivery = dpo.doOrderId
val prefix = "DN"
val midfix = CodeGenerator.DEFAULT_MIDFIX
val latestCode = doPickOrderRecordRepository.findLatestDeliveryNoteCodeByPrefix("$prefix-$midfix")
val deliveryNoteCode = CodeGenerator.generateNo(prefix = prefix, midfix = midfix, latestCode = latestCode)

val dpoRecord = DoPickOrderRecord(
recordId = dpo.id,
storeId = dpo.storeId ?: "",
ticketNo = dpo.ticketNo ?: "",
ticketStatus = DoPickOrderStatus.completed,
truckId = dpo.truckId,
truckDepartureTime = dpo.truckDepartureTime,
pickOrderId = dpo.pickOrderId,
doOrderId = dpo.doOrderId,
ticketReleaseTime = dpo.ticketReleaseTime,
shopId = dpo.shopId,
handlerName = dpo.handlerName,
handledBy = dpo.handledBy,
ticketCompleteDateTime = LocalDateTime.now(),
truckLanceCode = dpo.truckLanceCode,
shopCode = dpo.shopCode,
shopName = dpo.shopName,
requiredDeliveryDate = dpo.requiredDeliveryDate,
pickOrderCode = dpo.pickOrderCode,
deliveryOrderCode = dpo.deliveryOrderCode,
deliveryNoteCode = deliveryNoteCode,
loadingSequence = dpo.loadingSequence,
)
val savedHeader = doPickOrderRecordRepository.save(dpoRecord)
val savedHeader = saveDoPickOrderRecordWithDnRetry { deliveryNoteCode ->
DoPickOrderRecord(
recordId = dpo.id,
storeId = dpo.storeId ?: "",
ticketNo = dpo.ticketNo ?: "",
ticketStatus = DoPickOrderStatus.completed,
truckId = dpo.truckId,
truckDepartureTime = dpo.truckDepartureTime,
pickOrderId = dpo.pickOrderId,
doOrderId = dpo.doOrderId,
ticketReleaseTime = dpo.ticketReleaseTime,
shopId = dpo.shopId,
handlerName = dpo.handlerName,
handledBy = dpo.handledBy,
ticketCompleteDateTime = LocalDateTime.now(),
truckLanceCode = dpo.truckLanceCode,
shopCode = dpo.shopCode,
shopName = dpo.shopName,
requiredDeliveryDate = dpo.requiredDeliveryDate,
pickOrderCode = dpo.pickOrderCode,
deliveryOrderCode = dpo.deliveryOrderCode,
deliveryNoteCode = deliveryNoteCode,
loadingSequence = dpo.loadingSequence,
)
}

val lines = doPickOrderLineRepository.findByDoPickOrderIdAndDeletedFalse(dpo.id!!)
val lineRecords = lines.map { l: DoPickOrderLine ->
@@ -1607,6 +1599,27 @@ open class PickOrderService(
}
}

private fun saveDoPickOrderRecordWithDnRetry(
maxAttempts: Int = 3,
buildRecord: (String) -> DoPickOrderRecord
): DoPickOrderRecord {
val prefix = "DN"
repeat(maxAttempts) { attempt ->
val midfix = LocalDate.now().format(CodeGenerator.DEFAULT_FORMATTER)
val latestCode = doPickOrderRecordRepository.findLatestDeliveryNoteCodeByPrefix("$prefix-$midfix")
val deliveryNoteCode = CodeGenerator.generateNo(prefix = prefix, midfix = midfix, latestCode = latestCode)
val dpoRecord = buildRecord(deliveryNoteCode)
try {
return doPickOrderRecordRepository.save(dpoRecord)
} catch (e: DataIntegrityViolationException) {
if (attempt == maxAttempts - 1) {
throw e
}
}
}
throw IllegalStateException("Failed to generate unique delivery note code after $maxAttempts attempts")
}

@Transactional(rollbackFor = [java.lang.Exception::class])
open fun checkAndCompletePickOrderByConsoCode(consoCode: String): MessageResponse {
try {


+ 47
- 29
src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt Ver ficheiro

@@ -10,6 +10,7 @@ import com.ffii.fpsms.modules.pickOrder.enums.PickOrderLineStatus
import com.ffii.fpsms.modules.stock.entity.*
import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo
import com.ffii.fpsms.modules.stock.web.model.*
import org.springframework.dao.DataIntegrityViolationException
import org.springframework.data.repository.query.Param
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
@@ -483,36 +484,32 @@ private fun getStockOutIdFromPickOrderLine(pickOrderLineId: Long): Long {
dpo.ticketCompleteDateTime = LocalDateTime.now()
doPickOrderRepository.save(dpo)

val prefix = "DN"
val midfix = CodeGenerator.DEFAULT_MIDFIX
val latestCode = doPickOrderRecordRepository.findLatestDeliveryNoteCodeByPrefix("${prefix}-${midfix}")
val deliveryNoteCode = CodeGenerator.generateNo(prefix = prefix, midfix = midfix, latestCode = latestCode)

// 4) 可选:复制 header 到 record 表,复制 lines 到 line_record,再删除原有行/头(与你在 PickOrderService.completeStockOut 的做法保持一致)
val dpoRecord = DoPickOrderRecord(
recordId =dpoId,
storeId = dpo.storeId ?: "",
ticketNo = dpo.ticketNo ?: "",
ticketStatus = DoPickOrderStatus.completed,
truckId = dpo.truckId,
pickOrderId = dpo.pickOrderId,
truckDepartureTime = dpo.truckDepartureTime,
shopId = dpo.shopId,
handledBy = dpo.handledBy,
handlerName = dpo.handlerName,
doOrderId = dpo.doOrderId,
pickOrderCode = dpo.pickOrderCode,
deliveryOrderCode = dpo.deliveryOrderCode,
deliveryNoteCode = deliveryNoteCode,
loadingSequence = dpo.loadingSequence,
ticketReleaseTime = dpo.ticketReleaseTime,
ticketCompleteDateTime = LocalDateTime.now(),
truckLanceCode = dpo.truckLanceCode,
shopCode = dpo.shopCode,
shopName = dpo.shopName,
requiredDeliveryDate = dpo.requiredDeliveryDate
)
val savedHeader = doPickOrderRecordRepository.save(dpoRecord)
val savedHeader = saveDoPickOrderRecordWithDnRetry { deliveryNoteCode ->
DoPickOrderRecord(
recordId = dpoId,
storeId = dpo.storeId ?: "",
ticketNo = dpo.ticketNo ?: "",
ticketStatus = DoPickOrderStatus.completed,
truckId = dpo.truckId,
pickOrderId = dpo.pickOrderId,
truckDepartureTime = dpo.truckDepartureTime,
shopId = dpo.shopId,
handledBy = dpo.handledBy,
handlerName = dpo.handlerName,
doOrderId = dpo.doOrderId,
pickOrderCode = dpo.pickOrderCode,
deliveryOrderCode = dpo.deliveryOrderCode,
deliveryNoteCode = deliveryNoteCode,
loadingSequence = dpo.loadingSequence,
ticketReleaseTime = dpo.ticketReleaseTime,
ticketCompleteDateTime = LocalDateTime.now(),
truckLanceCode = dpo.truckLanceCode,
shopCode = dpo.shopCode,
shopName = dpo.shopName,
requiredDeliveryDate = dpo.requiredDeliveryDate
)
}
val lineRecords = allLines.map { l ->
DoPickOrderLineRecord().apply {
@@ -590,6 +587,27 @@ private fun getStockOutIdFromPickOrderLine(pickOrderLineId: Long): Long {
entity = lineInfoList,
)
}

private fun saveDoPickOrderRecordWithDnRetry(
maxAttempts: Int = 3,
buildRecord: (String) -> DoPickOrderRecord
): DoPickOrderRecord {
val prefix = "DN"
repeat(maxAttempts) { attempt ->
val midfix = LocalDate.now().format(CodeGenerator.DEFAULT_FORMATTER)
val latestCode = doPickOrderRecordRepository.findLatestDeliveryNoteCodeByPrefix("$prefix-$midfix")
val deliveryNoteCode = CodeGenerator.generateNo(prefix = prefix, midfix = midfix, latestCode = latestCode)
val dpoRecord = buildRecord(deliveryNoteCode)
try {
return doPickOrderRecordRepository.save(dpoRecord)
} catch (e: DataIntegrityViolationException) {
if (attempt == maxAttempts - 1) {
throw e
}
}
}
throw IllegalStateException("Failed to generate unique delivery note code after $maxAttempts attempts")
}
private fun completeDoForPickOrder(pickOrderId: Long) {
// 1) 原表 do_pick_order → completed
val dpos = doPickOrderRepository.findByPickOrderId(pickOrderId)


+ 5
- 0
src/main/resources/db/changelog/changes/20260413_01_codex/01_add_unique_index_delivery_note_code.sql Ver ficheiro

@@ -0,0 +1,5 @@
-- liquibase formatted sql
-- changeset codex:add_unique_index_delivery_note_code_20260413

ALTER TABLE `fpsmsdb`.`do_pick_order_record`
ADD CONSTRAINT `uk_do_pick_order_record_delivery_note_code` UNIQUE (`deliveryNoteCode`);

Carregando…
Cancelar
Guardar