| @@ -14,6 +14,7 @@ import com.ffii.fpsms.modules.deliveryOrder.service.DeliveryOrderLineService | |||||
| import com.ffii.fpsms.modules.deliveryOrder.service.DeliveryOrderService | import com.ffii.fpsms.modules.deliveryOrder.service.DeliveryOrderService | ||||
| import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderLineRequest | import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderLineRequest | ||||
| import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderRequest | import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderRequest | ||||
| import com.ffii.fpsms.modules.master.entity.ItemUom | |||||
| import com.ffii.fpsms.modules.master.service.ItemUomService | import com.ffii.fpsms.modules.master.service.ItemUomService | ||||
| import com.ffii.fpsms.modules.master.service.ItemsService | import com.ffii.fpsms.modules.master.service.ItemsService | ||||
| import com.ffii.fpsms.modules.master.service.ShopService | import com.ffii.fpsms.modules.master.service.ShopService | ||||
| @@ -106,7 +107,7 @@ open class M18DeliveryOrderService( | |||||
| shopPoConds += "=and=(${dDateEqualConds})" | shopPoConds += "=and=(${dDateEqualConds})" | ||||
| } | } | ||||
| println("shopPoConds: ${shopPoConds}") | |||||
| logger.info("shopPoConds: ${shopPoConds}") | |||||
| val shopPoParams = M18PurchaseOrderListRequest( | val shopPoParams = M18PurchaseOrderListRequest( | ||||
| params = null, | params = null, | ||||
| @@ -159,6 +160,9 @@ open class M18DeliveryOrderService( | |||||
| val failList = mutableListOf<Long>() | val failList = mutableListOf<Long>() | ||||
| val failDetailList = mutableListOf<Long>() | val failDetailList = mutableListOf<Long>() | ||||
| val failItemDetailList = mutableListOf<Long>() | val failItemDetailList = mutableListOf<Long>() | ||||
| val uomByM18IdCache = mutableMapOf<Long, ItemUom?>() | |||||
| val itemIdCache = mutableMapOf<Long, Long?>() | |||||
| val stockUomIdCache = mutableMapOf<Pair<Long, Long>, Long?>() | |||||
| val doRefType = "Delivery Order" | val doRefType = "Delivery Order" | ||||
| val doLineRefType = "Delivery Order Line" | val doLineRefType = "Delivery Order Line" | ||||
| @@ -191,7 +195,7 @@ open class M18DeliveryOrderService( | |||||
| // logger.info("${doRefType}: Finding For Latest M18 Data Log...") | // logger.info("${doRefType}: Finding For Latest M18 Data Log...") | ||||
| val latestDeliveryOrderLog = | val latestDeliveryOrderLog = | ||||
| m18DataLogService.findLatestM18DataLogWithSuccess(deliveryOrder.id, doRefType) | m18DataLogService.findLatestM18DataLogWithSuccess(deliveryOrder.id, doRefType) | ||||
| logger.info(latestDeliveryOrderLog.toString()) | |||||
| //logger.info(latestDeliveryOrderLog.toString()) | |||||
| // Save to m18_data_log table | // Save to m18_data_log table | ||||
| // logger.info("${doRefType}: Saving for M18 Data Log...") | // logger.info("${doRefType}: Saving for M18 Data Log...") | ||||
| val mainpoJson = | val mainpoJson = | ||||
| @@ -305,14 +309,23 @@ open class M18DeliveryOrderService( | |||||
| // logger.info("${doLineRefType}: Saved M18 Data Log. ID: ${saveM18DeliveryOrderLineLog.id}") | // logger.info("${doLineRefType}: Saved M18 Data Log. ID: ${saveM18DeliveryOrderLineLog.id}") | ||||
| // logger.info("${doLineRefType}: Finding item...") | // logger.info("${doLineRefType}: Finding item...") | ||||
| val item = itemsService.findByM18Id(line.proId) | |||||
| var itemId: Long? = null | |||||
| if (item == null) { | |||||
| itemId = m18MasterDataService.saveProduct(line.proId)?.id | |||||
| } else { | |||||
| itemId = item.id | |||||
| val itemId: Long? = itemIdCache.getOrPut(line.proId) { | |||||
| val item = itemsService.findByM18Id(line.proId) | |||||
| if (item == null) { | |||||
| m18MasterDataService.saveProduct(line.proId)?.id | |||||
| } else { | |||||
| item.id | |||||
| } | |||||
| } | } | ||||
| val stockUomId: Long? = if (itemId != null) { | |||||
| val key = line.proId to line.unitId // safe key | |||||
| stockUomIdCache.getOrPut(key) { | |||||
| val uom = itemUomService.findByM18Id(line.unitId) | |||||
| itemUomService.findStockUnitByItemId(itemId)?.uom?.id | |||||
| } | |||||
| } else null | |||||
| // logger.info("${doLineRefType}: Item ID: ${itemId} | M18 Item ID: ${line.proId}") | // logger.info("${doLineRefType}: Item ID: ${itemId} | M18 Item ID: ${line.proId}") | ||||
| try { | try { | ||||
| @@ -325,12 +338,15 @@ open class M18DeliveryOrderService( | |||||
| // Save to delivery_order_line table | // Save to delivery_order_line table | ||||
| // logger.info("${doLineRefType}: Saving delivery order line...") | // logger.info("${doLineRefType}: Saving delivery order line...") | ||||
| val itemUom = itemUomService.findByM18Id(line.unitId) | |||||
| val itemUom = uomByM18IdCache.getOrPut(line.unitId) { | |||||
| itemUomService.findByM18Id(line.unitId) | |||||
| } | |||||
| val saveDeliveryOrderLineRequest = SaveDeliveryOrderLineRequest( | val saveDeliveryOrderLineRequest = SaveDeliveryOrderLineRequest( | ||||
| id = existingDeliveryOrderLine?.id, | id = existingDeliveryOrderLine?.id, | ||||
| itemId = itemId, | itemId = itemId, | ||||
| uomIdM18 = itemUom?.uom?.id, | uomIdM18 = itemUom?.uom?.id, | ||||
| uomId= itemUomService.findStockUnitByItemId(itemId?: 0)?.uom?.id, | |||||
| uomId= stockUomId, | |||||
| deliveryOrderId = deliveryOrderId, | deliveryOrderId = deliveryOrderId, | ||||
| qtyM18 = line.qty, | qtyM18 = line.qty, | ||||
| qty = itemUomService.convertQtyToStockQty(itemId?:0, itemUom?.uom?.id?: 0, line.qty), | qty = itemUomService.convertQtyToStockQty(itemId?:0, itemUom?.uom?.id?: 0, line.qty), | ||||
| @@ -359,7 +375,7 @@ open class M18DeliveryOrderService( | |||||
| // log success info | // log success info | ||||
| successDetailList.add(line.id) | successDetailList.add(line.id) | ||||
| // logger.info("${doLineRefType}: Delivery order ID: ${deliveryOrderId} | M18 ID: ${deliveryOrder.id}") | // logger.info("${doLineRefType}: Delivery order ID: ${deliveryOrderId} | M18 ID: ${deliveryOrder.id}") | ||||
| logger.info("${doLineRefType}: Saved delivery order line. ID: ${saveDeliveryOrderLineResponse.id} | M18 Line ID: ${line.id} | Delivery order ID: ${deliveryOrderId} | M18 ID: ${deliveryOrder.id}") | |||||
| //logger.info("${doLineRefType}: Saved delivery order line. ID: ${saveDeliveryOrderLineResponse.id} | M18 Line ID: ${line.id} | Delivery order ID: ${deliveryOrderId} | M18 ID: ${deliveryOrder.id}") | |||||
| } catch (e: SQLException) { | } catch (e: SQLException) { | ||||
| failDetailList.add(line.id) | failDetailList.add(line.id) | ||||
| failItemDetailList.add(line.proId) | failItemDetailList.add(line.proId) | ||||
| @@ -17,6 +17,7 @@ import java.math.BigDecimal | |||||
| import java.time.LocalDateTime | import java.time.LocalDateTime | ||||
| import java.time.format.DateTimeFormatter | import java.time.format.DateTimeFormatter | ||||
| import com.ffii.fpsms.m18.model.SyncResult | import com.ffii.fpsms.m18.model.SyncResult | ||||
| import com.ffii.fpsms.modules.master.entity.Items | |||||
| import java.time.Instant | import java.time.Instant | ||||
| import java.time.LocalDate | import java.time.LocalDate | ||||
| import java.time.ZoneId | import java.time.ZoneId | ||||
| @@ -233,30 +234,38 @@ open class M18MasterDataService( | |||||
| } | } | ||||
| } | } | ||||
| open fun saveProducts(request: M18CommonRequest) : SyncResult{ | |||||
| open fun saveProducts(request: M18CommonRequest): SyncResult { | |||||
| logger.info("--------------------------------------------Start - Saving M18 Products / Materials--------------------------------------------") | logger.info("--------------------------------------------Start - Saving M18 Products / Materials--------------------------------------------") | ||||
| val items = getProducts(request) | val items = getProducts(request) | ||||
| val exampleProducts = listOf<Long>(10946L, 3825L) | val exampleProducts = listOf<Long>(10946L, 3825L) | ||||
| // ── New: cache for findByM18Id ───────────────────────────────────────── | |||||
| // M18 item.id → internal Item entity (or just the id if you only need id) | |||||
| val itemCache = mutableMapOf<Long, Items?>() | |||||
| val successList = mutableListOf<Long>() | val successList = mutableListOf<Long>() | ||||
| val failList = mutableListOf<Long>() | val failList = mutableListOf<Long>() | ||||
| val values = items?.values?.sortedBy { it.id } | val values = items?.values?.sortedBy { it.id } | ||||
| if (values != null) { | if (values != null) { | ||||
| values.forEach { item -> | values.forEach { item -> | ||||
| // if (item.id in exampleProducts) { | |||||
| // if (item.id in exampleProducts) { // keep your debug filter if needed | |||||
| try { | try { | ||||
| val itemDetail = getProduct(item.id) | val itemDetail = getProduct(item.id) | ||||
| val pro = itemDetail?.data?.pro?.get(0) | val pro = itemDetail?.data?.pro?.get(0) | ||||
| val price = itemDetail?.data?.price | val price = itemDetail?.data?.price | ||||
| if (itemDetail != null && pro != null) { | if (itemDetail != null && pro != null) { | ||||
| val existingItem = itemsService.findByM18Id(item.id) | |||||
| // ── Use cache instead of direct call ──────────────────────── | |||||
| val existingItem = itemCache.getOrPut(item.id) { | |||||
| itemsService.findByM18Id(item.id) | |||||
| } | |||||
| val saveItemRequest = NewItemRequest( | val saveItemRequest = NewItemRequest( | ||||
| code = pro.code, | code = pro.code, | ||||
| name = pro.desc, | name = pro.desc, | ||||
| // type = if (pro.seriesId == m18Config.SERIESID_PF) ProductType.MATERIAL | |||||
| // else ItemType.PRODUCT, | |||||
| type = when (pro.udfProducttype) { | type = when (pro.udfProducttype) { | ||||
| M18ItemType.CONSUMABLES.type -> ItemType.CONSUMABLES.type | M18ItemType.CONSUMABLES.type -> ItemType.CONSUMABLES.type | ||||
| M18ItemType.NONCONSUMABLES.type -> ItemType.NONCONSUMABLES.type | M18ItemType.NONCONSUMABLES.type -> ItemType.NONCONSUMABLES.type | ||||
| @@ -287,18 +296,19 @@ open class M18MasterDataService( | |||||
| val savedItem = itemsService.saveItem(saveItemRequest) | val savedItem = itemsService.saveItem(saveItemRequest) | ||||
| logger.info("Processing item uom...") | logger.info("Processing item uom...") | ||||
| // Find the item uom that ready to delete (not in m18) | |||||
| // Optional: cache findAllByItemsId if you think it might be called multiple times | |||||
| // (usually not needed here because each savedItem.id is unique) | |||||
| val existingItemUoms = savedItem.id?.let { itemUomService.findAllByItemsId(it) } | val existingItemUoms = savedItem.id?.let { itemUomService.findAllByItemsId(it) } | ||||
| val m18ItemUomIds = price?.map { it.id } ?: listOf() | val m18ItemUomIds = price?.map { it.id } ?: listOf() | ||||
| // Delete the item uom | |||||
| // Delete old UOMs not present in M18 | |||||
| logger.info("Deleting item uom...") | logger.info("Deleting item uom...") | ||||
| // logger.info("Item Uom: ${existingItemUoms?.map { it.m18Id }}") | |||||
| // logger.info("M18: ${m18ItemUomIds}") | |||||
| existingItemUoms?.filter { it.m18Id !in m18ItemUomIds }?.mapNotNull { it.id } | existingItemUoms?.filter { it.m18Id !in m18ItemUomIds }?.mapNotNull { it.id } | ||||
| ?.let { itemUomService.deleteItemUoms(it) } | ?.let { itemUomService.deleteItemUoms(it) } | ||||
| // Update the item uom | |||||
| // Update / create UOMs from M18 | |||||
| logger.info("Updating item uom...") | logger.info("Updating item uom...") | ||||
| price?.forEach { | price?.forEach { | ||||
| val endMillis = it.endDate | val endMillis = it.endDate | ||||
| @@ -319,11 +329,9 @@ open class M18MasterDataService( | |||||
| m18LastModifyDate = commonUtils.timestampToLocalDateTime(pro.lastModifyDate), | m18LastModifyDate = commonUtils.timestampToLocalDateTime(pro.lastModifyDate), | ||||
| ratioD = it.ratioD, | ratioD = it.ratioD, | ||||
| ratioN = it.ratioN, | ratioN = it.ratioN, | ||||
| //deleted = it.expired | |||||
| deleted = endInstant.isBefore(now) | deleted = endInstant.isBefore(now) | ||||
| ) | ) | ||||
| // logger.info("saved item id: ${savedItem.id}") | |||||
| itemUomService.saveItemUom(itemUomRequest) | itemUomService.saveItemUom(itemUomRequest) | ||||
| } | } | ||||
| @@ -340,13 +348,13 @@ open class M18MasterDataService( | |||||
| logger.error("Fail Message: ${e.message}") | logger.error("Fail Message: ${e.message}") | ||||
| logger.error("Fail Count ${failList.size}: Item ID - ${item.id}") | logger.error("Fail Count ${failList.size}: Item ID - ${item.id}") | ||||
| } | } | ||||
| // } // end of exampleProducts filter | |||||
| } | } | ||||
| } else { | } else { | ||||
| logger.error("Items List is null. May occur errors.") | logger.error("Items List is null. May occur errors.") | ||||
| } | } | ||||
| logger.info("Total Success (${successList.size})") | logger.info("Total Success (${successList.size})") | ||||
| if (failList.size > 0) { | if (failList.size > 0) { | ||||
| logger.error("Total Fail (${failList.size}): $failList") | logger.error("Total Fail (${failList.size}): $failList") | ||||
| } | } | ||||
| @@ -106,51 +106,51 @@ class M18TestController ( | |||||
| @GetMapping("/product/{id}") | @GetMapping("/product/{id}") | ||||
| fun m18Product(@PathVariable id: Long) { | fun m18Product(@PathVariable id: Long) { | ||||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| //logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| m18MasterDataService.saveProduct(id) | m18MasterDataService.saveProduct(id) | ||||
| } | } | ||||
| @PostMapping("/vendor") | @PostMapping("/vendor") | ||||
| fun m18Vendor(@Valid @RequestBody request: M18CommonRequest) { | fun m18Vendor(@Valid @RequestBody request: M18CommonRequest) { | ||||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| //logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| m18MasterDataService.saveVendors(request) | m18MasterDataService.saveVendors(request) | ||||
| } | } | ||||
| @PostMapping("/unit") | @PostMapping("/unit") | ||||
| fun m18Unit(@Valid @RequestBody request: M18CommonRequest) { | fun m18Unit(@Valid @RequestBody request: M18CommonRequest) { | ||||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| //logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| m18MasterDataService.saveUnits(request) | m18MasterDataService.saveUnits(request) | ||||
| } | } | ||||
| @PostMapping("/currency") | @PostMapping("/currency") | ||||
| fun m18Currency(@Valid @RequestBody request: M18CommonRequest) { | fun m18Currency(@Valid @RequestBody request: M18CommonRequest) { | ||||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| //logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| m18MasterDataService.saveCurrencies(request) | m18MasterDataService.saveCurrencies(request) | ||||
| } | } | ||||
| @PostMapping("/bom") | @PostMapping("/bom") | ||||
| fun m18Bom(@Valid @RequestBody request: M18CommonRequest) { | fun m18Bom(@Valid @RequestBody request: M18CommonRequest) { | ||||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| //logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| m18MasterDataService.saveBoms(request) | m18MasterDataService.saveBoms(request) | ||||
| } | } | ||||
| @PostMapping("/businessUnit") | @PostMapping("/businessUnit") | ||||
| fun m18BusinessUnit(@Valid @RequestBody request: M18CommonRequest) { | fun m18BusinessUnit(@Valid @RequestBody request: M18CommonRequest) { | ||||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| //logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| m18MasterDataService.saveBusinessUnits(request) | m18MasterDataService.saveBusinessUnits(request) | ||||
| } | } | ||||
| // --------------------------------------------- Purchase Order --------------------------------------------- /// | // --------------------------------------------- Purchase Order --------------------------------------------- /// | ||||
| @PostMapping("/po") | @PostMapping("/po") | ||||
| fun m18PO(@Valid @RequestBody request: M18CommonRequest) { | fun m18PO(@Valid @RequestBody request: M18CommonRequest) { | ||||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| //logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| m18PurchaseOrderService.savePurchaseOrders(request) | m18PurchaseOrderService.savePurchaseOrders(request) | ||||
| } | } | ||||
| // --------------------------------------------- Delivery Order --------------------------------------------- /// | // --------------------------------------------- Delivery Order --------------------------------------------- /// | ||||
| @PostMapping("/do") | @PostMapping("/do") | ||||
| fun m18DO(@Valid @RequestBody request: M18CommonRequest) { | fun m18DO(@Valid @RequestBody request: M18CommonRequest) { | ||||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| //logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||||
| m18DeliveryOrderService.saveDeliveryOrders(request) | m18DeliveryOrderService.saveDeliveryOrders(request) | ||||
| } | } | ||||
| @@ -0,0 +1,37 @@ | |||||
| spring: | |||||
| datasource: | |||||
| jdbc-url: jdbc:mysql://127.0.0.1:3306/fpsmsdb?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8 | |||||
| username: root | |||||
| password: secret | |||||
| m18: | |||||
| config: | |||||
| grant-type: password | |||||
| client-id: M2Y1OGYxMmQtZDRiOS00OTA4LTgyNTktZDRkNzEzNWVkMzRm | |||||
| client-secret: N2IzMjY5ZTEtZDIyYy00M2FlLWJhZjktZWU0ODBhYzAyNDA3 | |||||
| username: MTMS2 | |||||
| password: ea5bfbd761dd1b97bc08354d66169155f11ddaf1 | |||||
| base-url: https://toa.m18saas.com/jsf/rfws | |||||
| base-url-uat: https://toauat.m18saas.com/jsf/rfws | |||||
| base-password: 1648414877 | |||||
| supplier: | |||||
| shop-po: P06, P07 | |||||
| oem-po: T62 | |||||
| supplier-not: | |||||
| material-po: P06, P07 | |||||
| beId: | |||||
| toa: 1 | |||||
| pf: 27 | |||||
| pp: 29 | |||||
| seriesId: | |||||
| pp: 26 | |||||
| pf: 33 | |||||
| fa: 2 | |||||
| fb: 3 | |||||
| fc: 4 | |||||
| fd: 5 | |||||
| ff: 6 | |||||
| sc: 27 | |||||
| se: 28 | |||||
| sf: 70 | |||||
| sr: 29 | |||||