瀏覽代碼

need to resyn the po if the m18Lot not match, if not the whole PO cannot create GRN

master
Fai Luk 6 小時之前
父節點
當前提交
d5990fef2f
共有 1 個檔案被更改,包括 45 行新增0 行删除
  1. +45
    -0
      src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt

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

@@ -63,6 +63,7 @@ import com.ffii.fpsms.m18.model.GoodsReceiptNoteAntValue
import com.ffii.fpsms.m18.entity.M18GoodsReceiptNoteLog
import com.ffii.fpsms.m18.entity.M18GoodsReceiptNoteLogRepository
import com.ffii.fpsms.m18.service.M18GoodsReceiptNoteService
import com.ffii.fpsms.m18.service.M18PurchaseOrderService
import com.ffii.fpsms.m18.utils.CommonUtils
import com.google.gson.Gson
import org.slf4j.LoggerFactory
@@ -97,6 +98,7 @@ open class StockInLineService(
private val inventoryRepository: InventoryRepository,
private val m18GoodsReceiptNoteService: M18GoodsReceiptNoteService,
private val m18GoodsReceiptNoteLogRepository: M18GoodsReceiptNoteLogRepository,
private val m18PurchaseOrderService: M18PurchaseOrderService,
) : AbstractBaseEntityService<StockInLine, Long, StockInLineRepository>(jdbcDao, stockInLineRepository) {

private val logger = LoggerFactory.getLogger(StockInLineService::class.java)
@@ -502,6 +504,46 @@ open class StockInLineService(
return poRepository.saveAndFlush(po)
}

/**
* Calls M18 GET `/root/api/read/po?id={m18PoId}` (same as [M18PurchaseOrderService.getPurchaseOrder]) using
* [PurchaseOrder.m18DataLog].m18Id, compares each local POL's [PurchaseOrderLine.m18Lot] to M18 `pot[].lot`
* (matched by POL [com.ffii.fpsms.m18.entity.M18DataLog.m18Id] == M18 line id), and persists updates when different.
* Run before building the GRN so `sourceLot` matches M18.
*/
private fun syncPurchaseOrderLineM18LotFromM18(po: PurchaseOrder) {
val m18PoId = po.m18DataLog?.m18Id ?: run {
logger.debug("[GRN m18Lot sync] PO id=${po.id} code=${po.code} has no m18DataLog.m18Id, skip")
return
}
val response = try {
m18PurchaseOrderService.getPurchaseOrder(m18PoId)
} catch (e: Exception) {
logger.warn("[GRN m18Lot sync] read/po failed m18PoId=$m18PoId PO=${po.code}: ${e.message}")
null
} ?: return

val pot = response.data?.pot ?: return
if (pot.isEmpty()) return

val lotByM18LineId = pot.associate { it.id to (it.lot ?: "").trim() }
val pols = polRepository.findAllByPurchaseOrderIdAndDeletedIsFalseAndM18DataLogIsNotNull(po.id!!)
var changed = 0
for (pol in pols) {
val m18LineId = pol.m18DataLog?.m18Id ?: continue
if (!lotByM18LineId.containsKey(m18LineId)) continue
val remoteLot = lotByM18LineId[m18LineId]!!
val localLot = (pol.m18Lot ?: "").trim()
if (localLot == remoteLot) continue
logger.info("[GRN m18Lot sync] PO ${po.code} POL id=${pol.id} m18LineId=$m18LineId: local m18Lot='$localLot' -> M18 lot='$remoteLot'")
pol.m18Lot = if (remoteLot.isEmpty()) null else remoteLot
polRepository.saveAndFlush(pol)
changed++
}
if (changed > 0) {
logger.info("[GRN m18Lot sync] Updated m18Lot on $changed POL row(s) for PO id=${po.id} code=${po.code}")
}
}

/**
* Builds M18 Goods Receipt Note (AN) request from completed PO and its completed stock-in lines.
*/
@@ -631,6 +673,9 @@ open class StockInLineService(
logger.info("[updatePurchaseOrderStatus] savedPo id=${savedPo.id}, status=${savedPo.status}")
// TODO: For test only - normally check savedPo.status == PurchaseOrderStatus.COMPLETED and use only COMPLETE lines
try {
// Align POL.m18Lot with M18 before GRN (sourceLot must match M18 PO line lot or AN save may fail).
syncPurchaseOrderLineM18LotFromM18(savedPo)

// Defensive: load only completed stock-in lines for the PO, so GRN payload can't include pending/escalated.
val linesForGrn = stockInLineRepository.findCompletedByPurchaseOrderIdAndDeletedFalseWithItemNames(savedPo.id!!)
if (linesForGrn.isEmpty()) {


Loading…
取消
儲存