diff --git a/src/main/java/com/ffii/fpsms/m18/entity/M18GoodsReceiptNoteLog.kt b/src/main/java/com/ffii/fpsms/m18/entity/M18GoodsReceiptNoteLog.kt index 060c075..6093d4d 100644 --- a/src/main/java/com/ffii/fpsms/m18/entity/M18GoodsReceiptNoteLog.kt +++ b/src/main/java/com/ffii/fpsms/m18/entity/M18GoodsReceiptNoteLog.kt @@ -9,8 +9,8 @@ import jakarta.validation.constraints.Size /** * Logs the result of creating a Goods Receipt Note (AN) in M18. - * One row per purchase order line (POL) in the GRN, so we can trace - * m18RecordId back by stockInLineId or purchaseOrderLineId. + * One row per [stock_in_line] included in that GRN (same POL can have multiple SILs / receipts); + * retry logic uses [stock_in_line_id] to avoid duplicate GRNs per delivery batch. */ @Entity @Table(name = "m18_goods_receipt_note_log") diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt index bac3b58..38f5fbd 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt @@ -826,38 +826,41 @@ open class StockInLineService( val byPol = linesForGrn.groupBy { it.purchaseOrderLine!!.id!! } if (grnResponse.status == true) { logger.info("M18 Goods Receipt Note created for PO ${savedPo.code}, goodsReceiptNote id (recordId)=${grnResponse.recordId}") + // One log row per stock-in line (same POL can have multiple SILs / receipts); retry uses existsByStockInLineIdAndStatusTrue per line. byPol.forEach { (_, silList) -> - val sil = silList.first() - val pol = sil.purchaseOrderLine!! - val logEntry = M18GoodsReceiptNoteLog().apply { - m18RecordId = grnResponse.recordId - stockInLineId = sil.id - purchaseOrderLineId = pol.id - purchaseOrderId = savedPo.id - poCode = savedPo.code - status = true - message = null - requestJson = grnRequestJson + for (sil in silList) { + val pol = sil.purchaseOrderLine!! + val logEntry = M18GoodsReceiptNoteLog().apply { + m18RecordId = grnResponse.recordId + stockInLineId = sil.id + purchaseOrderLineId = pol.id + purchaseOrderId = savedPo.id + poCode = savedPo.code + status = true + message = null + requestJson = grnRequestJson + } + m18GoodsReceiptNoteLogRepository.save(logEntry) } - m18GoodsReceiptNoteLogRepository.save(logEntry) } } else { logger.warn("M18 Goods Receipt Note save returned status=false for PO ${savedPo.code}, recordId=${grnResponse?.recordId}, messages=${grnResponse?.messages}. Request sent (for M18 discussion): $grnRequestJson") val msg = grnResponse?.messages?.joinToString { it.msgDetail ?: it.msgCode ?: "" } ?: "" byPol.forEach { (_, silList) -> - val sil = silList.first() - val pol = sil.purchaseOrderLine!! - val logEntry = M18GoodsReceiptNoteLog().apply { - m18RecordId = grnResponse?.recordId ?: 0L - stockInLineId = sil.id - purchaseOrderLineId = pol.id - purchaseOrderId = savedPo.id - poCode = savedPo.code - status = false - message = msg.take(1000) - requestJson = grnRequestJson + for (sil in silList) { + val pol = sil.purchaseOrderLine!! + val logEntry = M18GoodsReceiptNoteLog().apply { + m18RecordId = grnResponse?.recordId ?: 0L + stockInLineId = sil.id + purchaseOrderLineId = pol.id + purchaseOrderId = savedPo.id + poCode = savedPo.code + status = false + message = msg.take(1000) + requestJson = grnRequestJson + } + m18GoodsReceiptNoteLogRepository.save(logEntry) } - m18GoodsReceiptNoteLogRepository.save(logEntry) } } } catch (e: Exception) {