package com.ffii.fpsms.m18.service import com.ffii.core.utils.JwtTokenUtil import com.ffii.fpsms.api.service.ApiCallerService import com.ffii.fpsms.m18.M18Config import com.ffii.fpsms.m18.enums.M18DataLogStatus import com.ffii.fpsms.m18.model.* import com.ffii.fpsms.m18.utils.CommonUtils import com.ffii.fpsms.m18.web.models.M18TestPoRequest import com.ffii.fpsms.modules.master.service.ItemUomService import com.ffii.fpsms.modules.master.service.ItemsService import com.ffii.fpsms.modules.master.service.ShopService import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderType import com.ffii.fpsms.modules.purchaseOrder.service.PurchaseOrderLineService import com.ffii.fpsms.modules.purchaseOrder.service.PurchaseOrderService import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderLineRequest import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderRequest import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.stereotype.Service import java.time.LocalDateTime import kotlin.reflect.full.memberProperties @Service open class M18PurchaseOrderService( val m18Config: M18Config, val apiCallerService: ApiCallerService, val m18DataLogService: M18DataLogService, val purchaseOrderService: PurchaseOrderService, val purchaseOrderLineService: PurchaseOrderLineService, val itemsService: ItemsService, val shopService: ShopService, val itemUomService: ItemUomService, ) { val commonUtils = CommonUtils() val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) val lastModifyDateStart = "2025-05-14 14:00:00" val lastModifyDateEnd = "2025-05-14 14:30:00" // val lastModifyDateConds = // "lastModifyDate=largerOrEqual=${lastModifyDateStart}=and=lastModifyDate=lessOrEqual=${lastModifyDateEnd}" // val lastModifyDate = LocalDateTime.now().minusMinutes(30) // val commonConds = // "(beId=equal=${m18Config.BEID_PF}=or=beId=equal=${m18Config.BEID_PP}=or=beId=equal=${m18Config.BEID_TOA})=and=lastModifyDate=largerOrEqual=${lastModifyDate}" // M18 API val M18_LOAD_PURCHASE_ORDER_API = "/root/api/read/po" val M18_FETCH_PURCHASE_ORDER_LIST_API = "/search/search" // Include material po, shop po, oem po open fun getPurchaseOrdersWithType(request: M18TestPoRequest): M18PurchaseOrderListResponseWithType? { val purchaseOrders = M18PurchaseOrderListResponseWithType(mutableListOf()) val lastModifyDateConds = "lastModifyDate=largerOrEqual=${request.modifiedDateFrom ?: lastModifyDateStart}=and=lastModifyDate=lessOrEqual=${request.modifiedDateTo ?: lastModifyDateEnd}" // Material PO val materialPoBuyers = commonUtils.listToString(listOf(m18Config.BEID_PP, m18Config.BEID_PF), "beId=equal=", "=or=") val materialPoSupplierNot = commonUtils.listToString( shopService.findM18VendorIdsByCodeRegexp(m18Config.MATERIAL_PO_SUPPLIER_NOT), "venId=unequal=", "=or=" ) val materialPoConds = "(${materialPoBuyers})=and=(${materialPoSupplierNot})=and=(${lastModifyDateConds})" println("materialPoConds: ${materialPoConds}") val materialPoParams = M18PurchaseOrderListRequest( params = null, conds = materialPoConds ) try { purchaseOrders.valuesWithType += Pair( PurchaseOrderType.MATERIAL, apiCallerService.get( M18_FETCH_PURCHASE_ORDER_LIST_API, materialPoParams ).block() ) } catch (e: Exception) { logger.error("(Getting Material Po list) Error on Function - ${e.stackTrace}") logger.error(e.message) } // Shop PO val shopPoBuyers = commonUtils.listToString(listOf(m18Config.BEID_TOA), "beId=equal=", "=or=") val shopPoSupplier = commonUtils.listToString( shopService.findM18VendorIdsByCodeRegexp(m18Config.SHOP_PO_SUPPLIER), "venId=equal=", "=or=" ) val shopPoConds = "(${shopPoBuyers})=and=(${shopPoSupplier})=and=(${lastModifyDateConds})" println("shopPoConds: ${shopPoConds}") val shopPoParams = M18PurchaseOrderListRequest( params = null, conds = shopPoConds ) try { purchaseOrders.valuesWithType += Pair( PurchaseOrderType.SHOP, apiCallerService.get( M18_FETCH_PURCHASE_ORDER_LIST_API, shopPoParams ).block() ) } catch (e: Exception) { logger.error("(Getting Shop Po list) Error on Function - ${e.stackTrace}") logger.error(e.message) } // OEM PO /* val oemPoBuyers = commonUtils.listToString(listOf(m18Config.BEID_PF, m18Config.BEID_PP), "beId=equal=", "=or=") val oemPoSupplier = commonUtils.listToString( shopService.findM18VendorIdsByCodeRegexp(m18Config.OEM_PO_SUPPLIER), "venId=equal=", "=or=" ) val oemPoConds = "(${oemPoBuyers})=and=(${oemPoSupplier})=and=(${lastModifyDateConds})" println("oemPoConds: ${oemPoConds}") val oemPoParams = M18PurchaseOrderListRequest( params = null, conds = oemPoConds ) try { purchaseOrders.valuesWithType += Pair( PurchaseOrderType.OEM, apiCallerService.get( M18_FETCH_PURCHASE_ORDER_LIST_API, oemPoParams ).block() ) } catch (e: Exception) { logger.error("(Getting OEM Po list) Error on Function - ${e.stackTrace}") logger.error(e.message) } */ return purchaseOrders } open fun getPurchaseOrder(id: Long): M18PurchaseOrderResponse? { val purchaseOrderParams = M18PurchaseOrderRequest( id = id ) var purchaseOrder: M18PurchaseOrderResponse? = null try { purchaseOrder = apiCallerService.get( M18_LOAD_PURCHASE_ORDER_API, purchaseOrderParams ).block() } catch (e: Exception) { logger.error("(Getting Po Detail) Error on Function - ${e.stackTrace}") logger.error(e.message) } return purchaseOrder } open fun savePurchaseOrders(request: M18TestPoRequest) { logger.info("--------------------------------------------Start - Saving M18 Purchase Order--------------------------------------------") val purchaseOrdersWithType = getPurchaseOrdersWithType(request) val examplePurchaseOrders = listOf(4764034L) val successList = mutableListOf() val successDetailList = mutableListOf() val failList = mutableListOf() val failDetailList = mutableListOf() val poRefType = "Purchase Order" val poLineRefType = "Purchase Order Line" if (purchaseOrdersWithType != null) { // Loop for Purchase Orders (values) purchaseOrdersWithType.valuesWithType.forEach { purchaseOrderWithType -> val type = purchaseOrderWithType.first // if success val purchaseOrdersValues = purchaseOrderWithType.second?.values // if fail val purchaseOrdersMessages = purchaseOrderWithType.second?.messages if (purchaseOrdersValues != null) { purchaseOrdersValues.forEach { purchaseOrder -> val purchaseOrderDetail = getPurchaseOrder(purchaseOrder.id) var purchaseOrderId: Long? = null //FP-MTMS // Process for Purchase Order (mainpo) // Assume only one PO in the PO (search by PO ID) val mainpo = purchaseOrderDetail?.data?.mainpo?.get(0) val pot = purchaseOrderDetail?.data?.pot val purchaseOrderLineMessage = purchaseOrderDetail?.messages // purchase_order + m18_data_log table if (mainpo != null) { // Find the latest m18 data log by m18 id & type logger.info("${poRefType}: Finding For Latest M18 Data Log...") val latestPurchaseOrderLog = m18DataLogService.findLatestM18DataLogWithSuccess(purchaseOrder.id, poRefType) logger.info(latestPurchaseOrderLog.toString()) // Save to m18_data_log table logger.info("${poRefType}: Saving for M18 Data Log...") val mainpoJson = mainpo::class.memberProperties.associate { prop -> prop.name to prop.getter.call(mainpo) } .toMutableMap() val saveM18PurchaseOrderLogRequest = SaveM18DataLogRequest( id = null, refType = poRefType, m18Id = purchaseOrder.id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainpo.lastModifyDate), // dataLog = mainpoJson, statusEnum = M18DataLogStatus.NOT_PROCESS ) val saveM18PurchaseOrderLog = m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLogRequest) // logger.info("${poRefType}: Saved M18 Data Log. ID: ${saveM18PurchaseOrderLog.id}") try { // Find the purchase_order if exist logger.info("${poRefType}: Finding exising purchase order...") val existingPurchaseOrder = latestPurchaseOrderLog?.id?.let { purchaseOrderService.findByM18DataLogId(it) } logger.info("${poRefType}: Exising purchase order ID: ${existingPurchaseOrder?.id}") // Save to purchase_order table logger.info("${poRefType}: Saving purchase order...") val savePurchaseOrderRequest = SavePurchaseOrderRequest( id = existingPurchaseOrder?.id, code = mainpo.code, m18SupplierId = mainpo.venId, m18ShopId = mainpo.virDeptId, m18CurrencyId = mainpo.curId, orderDate = commonUtils.timestampToLocalDateTime(mainpo.tDate), estimatedArrivalDate = commonUtils.timestampToLocalDateTime(mainpo.dDate), completeDate = null, status = PurchaseOrderStatus.PENDING.value, type = type.value, m18DataLogId = saveM18PurchaseOrderLog.id, ) val savePurchaseOrderResponse = purchaseOrderService.savePurchaseOrder(savePurchaseOrderRequest) purchaseOrderId = savePurchaseOrderResponse.id // Update m18_data_log with success val successSaveM18PurchaseOrderLogRequest = SaveM18DataLogRequest( id = saveM18PurchaseOrderLog.id, dataLog = mainpoJson, statusEnum = M18DataLogStatus.SUCCESS ) m18DataLogService.saveM18DataLog(successSaveM18PurchaseOrderLogRequest) // log success info successList.add(purchaseOrder.id) logger.info("${poRefType}: Saved purchase order. ID: ${savePurchaseOrderResponse.id} | M18 ${poRefType} ID: ${purchaseOrder.id}") } catch (e: Exception) { failList.add(purchaseOrder.id) logger.error("${poRefType}: Saving Failure!") logger.error("Error on Function - ${e.stackTrace} | Type: ${poRefType} | M18 ID: ${purchaseOrder.id} | Different? ${mainpo.id}") logger.error(e.message) val errorSaveM18PurchaseOrderLogRequest = SaveM18DataLogRequest( id = saveM18PurchaseOrderLog.id, dataLog = mutableMapOf(Pair("Exception Message", e.message)), statusEnum = M18DataLogStatus.FAIL ) m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLogRequest) logger.error("${poRefType}: M18 Data Log Updated! Please see the error. ID: ${saveM18PurchaseOrderLogRequest.id}") } // purchase_order_line + m18_data_log // TODO: check deleted po line? if (pot != null) { // Loop for Purchase Order Lines (pot) pot.forEach { line -> // Find the latest m18 data log by m18 id & type logger.info("${poLineRefType}: Finding For Latest M18 Data Log...") val latestPurchaseOrderLineLog = m18DataLogService.findLatestM18DataLogWithSuccess(line.id, poLineRefType) // logger.info("${poLineRefType}: Latest M18 Data Log ID: ${latestPurchaseOrderLineLog?.id}") // Save to m18_data_log table logger.info("${poLineRefType}: Saving for M18 Data Log...") val lineJson = line::class.memberProperties.associate { prop -> prop.name to prop.getter.call( line ) } .toMutableMap() val saveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( id = null, refType = poLineRefType, m18Id = line.id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainpo.lastModifyDate), // dataLog = lineJson, statusEnum = M18DataLogStatus.NOT_PROCESS ) val saveM18PurchaseOrderLineLog = m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLineLogRequest) // logger.info("${poLineRefType}: Saved M18 Data Log. ID: ${saveM18PurchaseOrderLineLog.id}") logger.info("${poLineRefType}: Finding item...") val item = itemsService.findByM18Id(line.proId) logger.info("${poLineRefType}: Item ID: ${item?.id} | M18 Item ID: ${line.proId}") try { // Find the purchase_order_line if exist logger.info("${poLineRefType}: Finding exising purchase order line...") val existingPurchaseOrderLine = latestPurchaseOrderLineLog?.id?.let { purchaseOrderLineService.findPurchaseOrderLineByM18Id(it) } logger.info("${poLineRefType}: Exising purchase order line ID: ${existingPurchaseOrderLine?.id}") // Save to purchase_order_line table logger.info("${poLineRefType}: Saving purchase order line...") val itemUom = item?.id?.let { itemUomService.findPurchaseUnitByItemId(it) } val savePurchaseOrderLineRequest = SavePurchaseOrderLineRequest( id = existingPurchaseOrderLine?.id, itemId = item?.id, uomId = itemUom?.uom?.id, purchaseOrderId = purchaseOrderId, qty = line.qty, price = line.amt, // m18CurrencyId = mainpo.curId, status = existingPurchaseOrderLine?.status?.value ?: PurchaseOrderLineStatus.PENDING.value, m18DataLogId = saveM18PurchaseOrderLineLog.id, ) val savePurchaseOrderLineResponse = purchaseOrderLineService.savePurchaseOrderLine(savePurchaseOrderLineRequest) // Update m18_data_log with success val successSaveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( id = saveM18PurchaseOrderLineLog.id, dataLog = lineJson, statusEnum = M18DataLogStatus.SUCCESS ) m18DataLogService.saveM18DataLog(successSaveM18PurchaseOrderLineLogRequest) // log success info successDetailList.add(line.id) logger.info("${poLineRefType}: Purchase order ID: ${purchaseOrderId} | M18 ID: ${purchaseOrder.id}") logger.info("${poLineRefType}: Saved purchase order line. ID: ${savePurchaseOrderLineResponse.id} | M18 Line ID: ${line.id}") } catch (e: Exception) { failDetailList.add(line.id) logger.error("${poLineRefType}: Saving Failure!") logger.error("Error on Function - ${e.stackTrace} | Type: ${poLineRefType} | M18 ID: ${line.id}") logger.error(e.message) val errorSaveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( id = saveM18PurchaseOrderLineLog.id, dataLog = mutableMapOf(Pair("Exception Message", e.message)), statusEnum = M18DataLogStatus.FAIL ) m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLineLogRequest) logger.error("${poLineRefType}: M18 Data Log Updated! Please see the error. ID: ${saveM18PurchaseOrderLineLog.id}") } } } else { // pot logger.error("${poLineRefType}: Saving Failure!") val saveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( id = null, refType = "${poLineRefType}", m18Id = purchaseOrder.id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainpo.lastModifyDate), // dataLog = mutableMapOf(Pair("Error Message", "${poLineRefType} is null")), dataLog = mutableMapOf( Pair( "${poLineRefType} Error Message", "pot is null" ), Pair( "${poLineRefType} Error Code", purchaseOrderLineMessage?.get(0)?.msgCode ?: "No Msg Code from M18" ), Pair( "${poLineRefType} Error Detail", purchaseOrderLineMessage?.get(0)?.msgDetail ?: "No Msg Detail from M18" ), ), statusEnum = M18DataLogStatus.FAIL ) val errorLog = m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLineLogRequest) logger.error("${poLineRefType}: M18 Data Log Updated! Please see the error. ID: ${errorLog.id}") } } else { // mainpo failList.add(purchaseOrder.id) logger.error("${poRefType}: Saving Failure!") val saveM18DataLogRequest = SaveM18DataLogRequest( id = null, refType = "${poRefType}", m18Id = purchaseOrder.id, // m18LastModifyDate = if(mainpo?.lastModifyDate != null) commonUtils.instantToLocalDateTime(mainpo.lastModifyDate) else LocalDateTime.now(), m18LastModifyDate = LocalDateTime.now(), dataLog = mutableMapOf( Pair( "${poRefType} Error", "mainpo is null" ), Pair( "${poRefType} Error Code", purchaseOrdersMessages?.get(0)?.msgCode ?: "No Msg Code from M18" ), Pair( "${poRefType} Error Detail", purchaseOrdersMessages?.get(0)?.msgDetail ?: "No Msg Detail from M18" ), ), statusEnum = M18DataLogStatus.FAIL ) val errorLog = m18DataLogService.saveM18DataLog(saveM18DataLogRequest) logger.error("${poLineRefType}: M18 Data Log Updated! Please see the error. ID: ${errorLog.id}") } } } else { logger.error("${poRefType} List is null. May occur errors.") } } } else { logger.error("${poRefType} List is null. May occur errors.") } // End of save. Check result logger.info("Total Success (${poRefType}) (${successList.size}): $successList") // if (failList.size > 0) { logger.error("Total Fail (${poRefType}) (${failList.size}): $failList") // } logger.info("Total Success (${poLineRefType}) (${successDetailList.size}): $successDetailList") // if (failDetailList.size > 0) { logger.error("Total Fail (${poLineRefType}) (${failDetailList.size}): $failDetailList") // } logger.info("--------------------------------------------End - Saving M18 Purchase Order--------------------------------------------") } }