Kaynağa Gözat

1st time create GRN success

reset-do-picking-order
[email protected] 2 hafta önce
ebeveyn
işleme
c1e4e7ca1b
4 değiştirilmiş dosya ile 50 ekleme ve 13 silme
  1. +3
    -0
      src/main/java/com/ffii/fpsms/m18/entity/M18GoodsReceiptNoteLogRepository.kt
  2. +18
    -3
      src/main/java/com/ffii/fpsms/m18/model/GoodsReceiptNoteRequest.kt
  3. +1
    -1
      src/main/java/com/ffii/fpsms/m18/service/M18GoodsReceiptNoteService.kt
  4. +28
    -9
      src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt

+ 3
- 0
src/main/java/com/ffii/fpsms/m18/entity/M18GoodsReceiptNoteLogRepository.kt Dosyayı Görüntüle

@@ -3,4 +3,7 @@ package com.ffii.fpsms.m18.entity
import com.ffii.core.support.AbstractRepository import com.ffii.core.support.AbstractRepository


interface M18GoodsReceiptNoteLogRepository : AbstractRepository<M18GoodsReceiptNoteLog, Long> { interface M18GoodsReceiptNoteLogRepository : AbstractRepository<M18GoodsReceiptNoteLog, Long> {

/** Returns true if a successful GRN was already created for this PO (avoids core_201 duplicate). */
fun existsByPurchaseOrderIdAndStatusTrue(purchaseOrderId: Long): Boolean
} }

+ 18
- 3
src/main/java/com/ffii/fpsms/m18/model/GoodsReceiptNoteRequest.kt Dosyayı Görüntüle

@@ -1,33 +1,46 @@
package com.ffii.fpsms.m18.model package com.ffii.fpsms.m18.model


import com.fasterxml.jackson.annotation.JsonInclude

/** /**
* Request body for M18 Goods Receipt Note (AN) save API. * Request body for M18 Goods Receipt Note (AN) save API.
* PUT /root/api/save/an?menuCode=an * PUT /root/api/save/an?menuCode=an
*/ */
@JsonInclude(JsonInclude.Include.NON_NULL)
data class GoodsReceiptNoteRequest( data class GoodsReceiptNoteRequest(
val mainan: GoodsReceiptNoteMainan, val mainan: GoodsReceiptNoteMainan,
val ant: GoodsReceiptNoteAnt, val ant: GoodsReceiptNoteAnt,
) )


@JsonInclude(JsonInclude.Include.NON_NULL)
data class GoodsReceiptNoteMainan( data class GoodsReceiptNoteMainan(
val values: List<GoodsReceiptNoteMainanValue>, val values: List<GoodsReceiptNoteMainanValue>,
) )


@JsonInclude(JsonInclude.Include.NON_NULL)
data class GoodsReceiptNoteMainanValue( data class GoodsReceiptNoteMainanValue(
val id: String? = null, // "" for create new
val beId: Int, val beId: Int,
val code: String,
val code: String? = null, // omit; M18 auto-generates GRN code
val venId: Int, val venId: Int,
val curId: Int,
val curId: Int, // required by M18 (core_101905)
val rate: Number, val rate: Number,
val status: String? = "Y",
val docDate: String? = null,
val tDate: String? = null, // PO delivery date (estimatedArrivalDate)
val locId: Int? = null,
val flowTypeId: Int, val flowTypeId: Int,
val staffId: Int,
val staffId: Int, // required by M18 (core_101905)
val cnDeptId: Int? = null,
val virDeptId: Int? = null, val virDeptId: Int? = null,
) )


@JsonInclude(JsonInclude.Include.NON_NULL)
data class GoodsReceiptNoteAnt( data class GoodsReceiptNoteAnt(
val values: List<GoodsReceiptNoteAntValue>, val values: List<GoodsReceiptNoteAntValue>,
) )


@JsonInclude(JsonInclude.Include.NON_NULL)
data class GoodsReceiptNoteAntValue( data class GoodsReceiptNoteAntValue(
val sourceType: String, val sourceType: String,
val sourceId: Long, val sourceId: Long,
@@ -38,4 +51,6 @@ data class GoodsReceiptNoteAntValue(
val qty: Number, val qty: Number,
val up: Number, val up: Number,
val amt: Number, val amt: Number,
val beId: Int? = null,
val flowTypeId: Int? = null,
) )

+ 1
- 1
src/main/java/com/ffii/fpsms/m18/service/M18GoodsReceiptNoteService.kt Dosyayı Görüntüle

@@ -56,7 +56,7 @@ open class M18GoodsReceiptNoteService(
add("menuCode", MENU_CODE_AN) add("menuCode", MENU_CODE_AN)
param?.let { add("param", it) } param?.let { add("param", it) }
} }
val queryString = queryParams.entries.joinToString("&") { (k, v) -> "$k=$v" }
val queryString = queryParams.entries.flatMap { (k, v) -> v.map { value -> "$k=$value" } }.joinToString("&")
val fullUrl = "${m18Config.BASE_URL}$M18_SAVE_GOODS_RECEIPT_NOTE_API?$queryString" val fullUrl = "${m18Config.BASE_URL}$M18_SAVE_GOODS_RECEIPT_NOTE_API?$queryString"
val requestJson = Gson().toJson(request) val requestJson = Gson().toJson(request)
logger.info("[M18 GRN API] call=PUT url=$fullUrl queryParams=$queryParams body=$requestJson") logger.info("[M18 GRN API] call=PUT url=$fullUrl queryParams=$queryParams body=$requestJson")


+ 28
- 9
src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt Dosyayı Görüntüle

@@ -414,37 +414,52 @@ open class StockInLineService(
* Builds M18 Goods Receipt Note (AN) request from completed PO and its completed stock-in lines. * Builds M18 Goods Receipt Note (AN) request from completed PO and its completed stock-in lines.
*/ */
private fun buildGoodsReceiptNoteRequest(po: PurchaseOrder, stockInLines: List<StockInLine>): GoodsReceiptNoteRequest { private fun buildGoodsReceiptNoteRequest(po: PurchaseOrder, stockInLines: List<StockInLine>): GoodsReceiptNoteRequest {
val poCode = po.code ?: ""
val beId = po.m18BeId?.toInt() ?: 1
val flowTypeId = when {
poCode.startsWith("TOA") -> 1
poCode.startsWith("PF") -> 2
poCode.startsWith("PP") -> 3
else -> 1
}
val mainan = GoodsReceiptNoteMainan( val mainan = GoodsReceiptNoteMainan(
values = listOf( values = listOf(
GoodsReceiptNoteMainanValue( GoodsReceiptNoteMainanValue(
beId = po.m18BeId!!.toInt(),
code = po.code!!,
id = null, // omit; "0" and "" didn't fix core_201
beId = beId,
code = null, // omit; empty string may cause 400
venId = (po.supplier?.m18Id ?: 0L).toInt(), venId = (po.supplier?.m18Id ?: 0L).toInt(),
curId = (po.currency?.m18Id ?: 0L).toInt(), curId = (po.currency?.m18Id ?: 0L).toInt(),
rate = 1, rate = 1,
flowTypeId = 1, // TODO temp for M18 API
staffId = 232, // TODO temp for M18 API; revert to config/default when done
virDeptId = 117, // TODO temp for M18 API
flowTypeId = flowTypeId,
staffId = 194, // Steve
virDeptId = po.shop?.m18Id?.toInt(),
tDate = (po.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now()).format(DateTimeFormatter.ofPattern("MM/dd/yyyy")),
status = null, // commented out - omit
// docDate = ..., locId = ..., cnDeptId = ...
) )
) )
) )
val sourceId = po.m18DataLog?.m18Id ?: 0L val sourceId = po.m18DataLog?.m18Id ?: 0L
val antValues = stockInLines.map { sil -> val antValues = stockInLines.map { sil ->
val pol = sil.purchaseOrderLine!! val pol = sil.purchaseOrderLine!!
val unitIdFromDataLog = (pol.m18DataLog?.dataLog?.get("unitId") as? Number)?.toLong()?.toInt()
GoodsReceiptNoteAntValue( GoodsReceiptNoteAntValue(
sourceType = "po", sourceType = "po",
sourceId = sourceId, sourceId = sourceId,
sourceLot = sil.lotNo ?: "",
sourceLot = pol.m18Lot ?: "",
proId = (sil.item?.m18Id ?: 0L).toInt(), proId = (sil.item?.m18Id ?: 0L).toInt(),
locId = 39, // TODO temp for M18 API
unitId = (pol.uom?.m18Id ?: 0L).toInt(),
locId = 155,
unitId = unitIdFromDataLog ?: (pol.uom?.m18Id ?: 0L).toInt(),
qty = sil.acceptedQty?.toDouble() ?: 0.0, qty = sil.acceptedQty?.toDouble() ?: 0.0,
up = pol.up?.toDouble() ?: 0.0, up = pol.up?.toDouble() ?: 0.0,
amt = CommonUtils.getAmt( amt = CommonUtils.getAmt(
up = pol.up ?: BigDecimal.ZERO, up = pol.up ?: BigDecimal.ZERO,
discount = pol.m18Discount ?: BigDecimal.ZERO, discount = pol.m18Discount ?: BigDecimal.ZERO,
qty = sil.acceptedQty ?: BigDecimal.ZERO qty = sil.acceptedQty ?: BigDecimal.ZERO
)
),
beId = beId, // same as header
flowTypeId = flowTypeId // same as header: TOA->1, PF->2, PP->3
) )
} }
val ant = GoodsReceiptNoteAnt(values = antValues) val ant = GoodsReceiptNoteAnt(values = antValues)
@@ -506,6 +521,10 @@ open class StockInLineService(
logger.info("[tryUpdatePurchaseOrderAndCreateGrnIfCompleted] DEBUG: Skipping M18 GRN - missing M18 ids for PO id=${savedPo.id} code=${savedPo.code}. m18BeId=${savedPo.m18BeId}, supplier.m18Id=${savedPo.supplier?.m18Id}, currency.m18Id=${savedPo.currency?.m18Id}") logger.info("[tryUpdatePurchaseOrderAndCreateGrnIfCompleted] DEBUG: Skipping M18 GRN - missing M18 ids for PO id=${savedPo.id} code=${savedPo.code}. m18BeId=${savedPo.m18BeId}, supplier.m18Id=${savedPo.supplier?.m18Id}, currency.m18Id=${savedPo.currency?.m18Id}")
return return
} }
if (m18GoodsReceiptNoteLogRepository.existsByPurchaseOrderIdAndStatusTrue(savedPo.id!!)) {
logger.info("[tryUpdatePurchaseOrderAndCreateGrnIfCompleted] Skipping M18 GRN - already created for PO id=${savedPo.id} code=${savedPo.code} (avoids core_201 duplicate)")
return
}
val grnRequest = buildGoodsReceiptNoteRequest(savedPo, linesForGrn) val grnRequest = buildGoodsReceiptNoteRequest(savedPo, linesForGrn)
val grnRequestJson = Gson().toJson(grnRequest) val grnRequestJson = Gson().toJson(grnRequest)
logger.info("[tryUpdatePurchaseOrderAndCreateGrnIfCompleted] M18 GRN API request (for discussion with M18) PO id=${savedPo.id} code=${savedPo.code}: $grnRequestJson") logger.info("[tryUpdatePurchaseOrderAndCreateGrnIfCompleted] M18 GRN API request (for discussion with M18) PO id=${savedPo.id} code=${savedPo.code}: $grnRequestJson")


Yükleniyor…
İptal
Kaydet