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.model.* import com.ffii.fpsms.m18.utils.CommonUtils import com.ffii.fpsms.m18.web.models.M18CommonRequest import com.ffii.fpsms.modules.master.entity.UomConversion import com.ffii.fpsms.modules.master.enums.ShopType import com.ffii.fpsms.modules.master.service.* import com.ffii.fpsms.modules.master.web.models.* import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.stereotype.Service import java.math.BigDecimal import java.time.LocalDateTime import java.time.format.DateTimeFormatter @Service open class M18MasterDataService( val m18Config: M18Config, val apiCallerService: ApiCallerService, val itemsService: ItemsService, val shopService: ShopService, val uomConversionService: UomConversionService, val currencyService: CurrencyService, val itemUomService: ItemUomService, val bomService: BomService, val bomMaterialService: BomMaterialService, ) { val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) val commonUtils = CommonUtils() val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") // M18 Conditions // val lastModifyDate = LocalDate.now().minusDays(1) // val lastModifyDateConds = "lastModifyDate=largerThan=$lastModifyDate" val seriesIdList = listOf(m18Config.SERIESID_SC, m18Config.SERIESID_SE, m18Config.SERIESID_SF, m18Config.SERIESID_SR) val seriesIdConds = "(" + commonUtils.listToString(seriesIdList.filterNotNull(), "seriesId=unequal=", "=or=") + ")" val beIdList = listOf(m18Config.BEID_PF, m18Config.BEID_PP, m18Config.BEID_TOA) val beIdConds = "(" + commonUtils.listToString(beIdList.filterNotNull(), "beId=equal=", "=or=") + ")" // val beIdConds = commonUtils.BEID_CONDS // M18 API val M18_COMMON_FETCH_LIST_API = "/search/search" val M18_COMMON_LOAD_LINE_API = "/root/api/read" val M18_LOAD_PRODUCT_API = "${M18_COMMON_LOAD_LINE_API}/${StSearchType.PRODUCT.value}" val M18_LOAD_VENDOR_API = "${M18_COMMON_LOAD_LINE_API}/${StSearchType.VENDOR.value}" val M18_LOAD_UNIT_API = "${M18_COMMON_LOAD_LINE_API}/${StSearchType.UNIT.value}" val M18_LOAD_CURRENCY_API = "${M18_COMMON_LOAD_LINE_API}/${StSearchType.CURRENCY.value}" val M18_LOAD_BOM_API = "${M18_COMMON_LOAD_LINE_API}/${StSearchType.BOM.value}" val M18_LOAD_BUSINESS_UNIT_API = "${M18_COMMON_LOAD_LINE_API}/${StSearchType.BUSINESS_UNIT.value}" // for shop po? // --------------------------------------------- Common Function --------------------------------------------- /// private inline fun getList( stSearch: String?, params: String? = null, conds: String? = null, request: M18CommonRequest, ): T? { val lastModifyDateFromConds = request.modifiedDateFrom?.let { "lastModifyDate=largerOrEqual=${it}" } val lastModifyDateToConds = request.modifiedDateTo?.let{ "lastModifyDate=lessOrEqual=${it}" } val haveFromAndTo = lastModifyDateFromConds != null && lastModifyDateToConds != null val finalConds = if (lastModifyDateFromConds == null && lastModifyDateToConds == null) { conds } else { conds + "=and=(${lastModifyDateFromConds ?: ""}${if(haveFromAndTo) "=and=" else ""}${lastModifyDateToConds ?: ""})" } val request = M18CommonListRequest( stSearch = stSearch, params = params, conds = finalConds ) val response = apiCallerService.get( M18_COMMON_FETCH_LIST_API, request ).block() return response } private inline fun getLine( id: Long, params: String?, api: String, ): T? { val request = M18CommonLineRequest( id = id, params = params, ) val response = apiCallerService.get( api, request ).block() return response } // --------------------------------------------- Product --------------------------------------------- /// open fun getProducts(request: M18CommonRequest): M18ProductListResponse? { // seems no beId return getList( stSearch = StSearchType.PRODUCT.value, params = null, conds = seriesIdConds, request = request ) // val itemsParams = M18CommonListRequest( // stSearch = StSearchType.PRODUCT.value, // params = null, // conds = seriesIdConds // ) // // val items = apiCallerService.get( // M18_COMMON_FETCH_LIST_API, // itemsParams // ).block() // // return items } open fun getProduct(id: Long): M18ProductResponse? { logger.info("M18 Product ID: $id") return getLine( id = id, params = null, api = M18_LOAD_PRODUCT_API ) } open fun saveProduct(id: Long): MessageResponse? { try { val itemDetail = getProduct(id) val pro = itemDetail?.data?.pro?.get(0) val price = itemDetail?.data?.price if (itemDetail != null && pro != null) { val existingItem = itemsService.findByM18Id(id) val saveItemRequest = NewItemRequest( code = pro.code, name = pro.desc, // type = if (pro.seriesId == m18Config.SERIESID_PF) ProductType.MATERIAL // else ItemType.PRODUCT, type = when (pro.udfProducttype) { M18ItemType.CONSUMABLES.type -> ItemType.CONSUMABLES M18ItemType.NONCONSUMABLES.type -> ItemType.NONCONSUMABLES M18ItemType.FG.type -> ItemType.FG M18ItemType.SFG.type -> ItemType.SFG M18ItemType.ITEM.type -> ItemType.ITEM else -> ItemType.MATERIAL }, id = existingItem?.id, description = pro.desc, remarks = null, shelfLife = null, countryOfOrigin = null, maxQty = null, m18Id = id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(pro.lastModifyDate) ) val savedItem = itemsService.saveItem(saveItemRequest) logger.info("Processing item uom...") // Find the item uom that ready to delete (not in m18) val existingItemUoms = savedItem.id?.let { itemUomService.findAllByItemsId(it) } val m18ItemUomIds = price?.map { it.id } ?: listOf() // Delete the 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 } ?.let { itemUomService.deleteItemUoms(it) } // Update the item uom logger.info("Updating item uom...") price?.forEach { val itemUomRequest = ItemUomRequest( m18UomId = it.unitId, itemId = savedItem.id, baseUnit = it.basicUnit, stockUnit = it.stkUnit, pickingUnit = it.pickUnit, salesUnit = it.saleUnit, purchaseUnit = it.purUnit, price = null, currencyId = null, m18Id = it.id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(pro.lastModifyDate), ratioD = it.ratioD, ratioN = it.ratioN, deleted = it.expired ) // logger.info("saved item id: ${savedItem.id}") itemUomService.saveItemUom(itemUomRequest) } logger.info("Success (M18 Item): ${id} | ${pro.code} | ${pro.desc}") return savedItem } else { logger.error("Fail Message: ${itemDetail?.messages?.get(0)?.msgDetail}") logger.error("Fail: Item ID - ${id} Not Found") return null } } catch (e: Exception) { logger.error("Exception") logger.error("Fail Message: ${e.message}") logger.error("Fail: Item ID - ${id}") return null } } open fun saveProducts(request: M18CommonRequest) { logger.info("--------------------------------------------Start - Saving M18 Products / Materials--------------------------------------------") val items = getProducts(request) val exampleProducts = listOf(10946L, 3825L) val successList = mutableListOf() val failList = mutableListOf() val values = items?.values?.sortedBy { it.id } if (values != null) { values.forEach { item -> // if (item.id in exampleProducts) { try { val itemDetail = getProduct(item.id) val pro = itemDetail?.data?.pro?.get(0) val price = itemDetail?.data?.price if (itemDetail != null && pro != null) { val existingItem = itemsService.findByM18Id(item.id) val saveItemRequest = NewItemRequest( code = pro.code, name = pro.desc, // type = if (pro.seriesId == m18Config.SERIESID_PF) ProductType.MATERIAL // else ItemType.PRODUCT, type = when (pro.udfProducttype) { M18ItemType.CONSUMABLES.type -> ItemType.CONSUMABLES M18ItemType.NONCONSUMABLES.type -> ItemType.NONCONSUMABLES M18ItemType.FG.type -> ItemType.FG M18ItemType.SFG.type -> ItemType.SFG M18ItemType.ITEM.type -> ItemType.ITEM else -> ItemType.MATERIAL }, id = existingItem?.id, description = pro.desc, remarks = null, shelfLife = null, countryOfOrigin = null, maxQty = null, m18Id = item.id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(pro.lastModifyDate) ) val savedItem = itemsService.saveItem(saveItemRequest) logger.info("Processing item uom...") // Find the item uom that ready to delete (not in m18) val existingItemUoms = savedItem.id?.let { itemUomService.findAllByItemsId(it) } val m18ItemUomIds = price?.map { it.id } ?: listOf() // Delete the 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 } ?.let { itemUomService.deleteItemUoms(it) } // Update the item uom logger.info("Updating item uom...") price?.forEach { val itemUomRequest = ItemUomRequest( m18UomId = it.unitId, itemId = savedItem.id, baseUnit = it.basicUnit, stockUnit = it.stkUnit, pickingUnit = it.pickUnit, salesUnit = it.saleUnit, purchaseUnit = it.purUnit, price = null, currencyId = null, m18Id = it.id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(pro.lastModifyDate), ratioD = it.ratioD, ratioN = it.ratioN, deleted = it.expired ) // logger.info("saved item id: ${savedItem.id}") itemUomService.saveItemUom(itemUomRequest) } successList.add(item.id) logger.info("Success Count ${successList.size}: ${item.id} | ${pro.code} | ${pro.desc}") } else { failList.add(item.id) logger.error("Fail Message: ${itemDetail?.messages?.get(0)?.msgDetail}") logger.error("Fail Count ${failList.size}: Item ID - ${item.id} Not Found") } } catch (e: Exception) { failList.add(item.id) logger.error("Exception") logger.error("Fail Message: ${e.message}") logger.error("Fail Count ${failList.size}: Item ID - ${item.id}") } } } else { logger.error("Items List is null. May occur errors.") } logger.info("Total Success (${successList.size})") if (failList.size > 0) { logger.error("Total Fail (${failList.size}): $failList") } logger.info("--------------------------------------------End - Saving M18 Products / Materials--------------------------------------------") } // --------------------------------------------- Vendor --------------------------------------------- /// open fun getVendors(request: M18CommonRequest): M18VendorListResponse? { return getList( stSearch = StSearchType.VENDOR.value, params = null, conds = beIdConds, request = request ) } open fun getVendor(id: Long): M18VendorResponse? { logger.info("M18 Vendor ID: $id") return getLine( id = id, params = null, api = M18_LOAD_VENDOR_API ) } open fun saveVendors(request: M18CommonRequest) { logger.info("--------------------------------------------Start - Saving M18 Vendors--------------------------------------------") val vendors = getVendors(request) val exampleVendors = listOf(191L) val successList = mutableListOf() val failList = mutableListOf() val values = vendors?.values?.sortedBy { it.id } if (values != null) { values.forEach { vendor -> // if (vendor.id in exampleVendors) { try { val vendorDetail = getVendor(vendor.id) if (vendorDetail != null && vendorDetail.data?.ven != null) { val ven = vendorDetail.data.ven[0] val saveShopRequest = SaveShopRequest( id = null, code = ven.code, name = ven.desc.ifEmpty { ven.`desc_zh-TW` }, brNo = null, contactNo = ven.tel, contactEmail = ven.email, contactName = null, addr1 = ven.ad1, addr2 = ven.ad2, addr3 = ven.ad3, addr4 = ven.ad4, district = null, type = ShopType.SUPPLIER.value, m18Id = vendor.id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(ven.lastModifyDate) ) shopService.saveShop(saveShopRequest) successList.add(vendor.id) logger.info("Success Count ${successList.size}: ${vendor.id} | ${ven.code} | ${ven.desc}") } else { failList.add(vendor.id) logger.error("Fail Message: ${vendorDetail?.messages?.get(0)?.msgDetail}") logger.error("Fail Count ${failList.size}: Vendor ID - ${vendor.id} Not Found") } } catch (e: Exception) { failList.add(vendor.id) logger.error("Exception") logger.error("Fail Message: ${e.message}") logger.error("Fail Count ${failList.size}: Vendor ID - ${vendor.id}") } // } } } else { logger.error("Vendor List is null. May occur errors.") } logger.info("Total Success (${successList.size})") if (failList.size > 0) { logger.error("Total Fail (${failList.size}): $failList") } logger.info("--------------------------------------------End - Saving M18 Vendors--------------------------------------------") } // --------------------------------------------- Unit (UoM) --------------------------------------------- /// open fun getUnits(request: M18CommonRequest): M18UnitListResponse? { // seems no beId return getList( stSearch = StSearchType.UNIT.value, params = null, conds = null, request = request ) } open fun getUnit(id: Long): M18UnitResponse? { logger.info("M18 Unit ID: $id") return getLine( id = id, params = null, api = M18_LOAD_UNIT_API ) } open fun saveUnits(request: M18CommonRequest) { logger.info("--------------------------------------------Start - Saving M18 Units--------------------------------------------") val units = getUnits(request) val successTransformList = mutableListOf() val successSaveList = mutableListOf() val failTransformList = mutableListOf() val failSaveList = mutableListOf() val values = units?.values?.sortedBy { it.id } if (values != null) { val finalUnitList = arrayListOf() // transform unit values.forEach { unit -> try { val tempObject = UomConversionService.BomObject().apply { code = unit.code udfudesc = unit.udfudesc lastModifyDate = unit.lastModifyDate id = unit.id } finalUnitList += uomConversionService.transformItem(tempObject) successTransformList += unit.id logger.info("Transform Success (M18): ${unit.id}") } catch (e: Exception) { failTransformList.add(unit.id) logger.error("Transform Exception") logger.error("Transform Fail Message: ${e.message}") logger.error("Transform Fail Count ${failTransformList.size}: Unit ID - ${unit.id}") } } uomConversionService.calculateSizeInGram(finalUnitList) finalUnitList.forEach { try { uomConversionService.saveUomConversion(it) successSaveList += it.m18Id logger.info("Save Success (M18): ${it.m18Id}") } catch (e: Exception) { failSaveList.add(it.m18Id) logger.error("Save Exception") logger.error("Save Fail Message: ${e.message}") logger.error("Save Fail Count ${failTransformList.size}: Unit ID - ${it.m18Id}") } } } else { logger.error("Unit List is null. May occur errors.") } logger.info("Total Transform Success (${successTransformList.size})") logger.info("Total Save Success (${successSaveList.size})") if (failTransformList.size > 0) { logger.error("Total Transform Fail (${failTransformList.size}): $failTransformList") } if (failSaveList.size > 0) { logger.error("Total Save Fail (${failSaveList.size}): $failSaveList") } logger.info("--------------------------------------------End - Saving M18 Units--------------------------------------------") } // --------------------------------------------- Currency --------------------------------------------- /// open fun getCurrencies(request: M18CommonRequest): M18CurrencyListResponse? { return getList( stSearch = StSearchType.CURRENCY.value, params = null, conds = null, request = request ) } open fun getCurrency(id: Long): M18CurrencyResponse? { logger.info("M18 Currency ID: $id") return getLine( id = id, params = null, api = M18_LOAD_CURRENCY_API ) } open fun saveCurrencies(request: M18CommonRequest) { logger.info("--------------------------------------------Start - Saving M18 Currencies--------------------------------------------") val currencies = getCurrencies(request) val successList = mutableListOf() val failList = mutableListOf() val values = currencies?.values?.sortedBy { it.id } if (values != null) { // save currency values.forEach { currency -> try { val currencyRequest = SaveCurrencyRequest( id = null, code = currency.code, name = currency.sym, description = currency.curDesc, m18Id = currency.id, m18LastModifyDate = LocalDateTime.parse(currency.lastModifyDate, formatter) ) currencyService.saveCurrency(currencyRequest) successList += currency.id logger.info("Save Success (M18): ${currency.id}") } catch (e: Exception) { failList += currency.id logger.error("Exception") logger.error("Fail Message: ${e.message}") logger.error("Fail Count ${failList.size}: Unit ID - ${currency.id}") } } } else { logger.error("Currency List is null. May occur errors.") } logger.info("Total Save Success (${successList.size})") if (failList.size > 0) { logger.error("Total Fail (${failList.size}): $failList") } logger.info("--------------------------------------------End - Saving Currencies--------------------------------------------") } // --------------------------------------------- Bom --------------------------------------------- /// open fun getBoms(request: M18CommonRequest): M18BomListResponse? { return getList( stSearch = StSearchType.BOM.value, params = null, conds = beIdConds, request = request ) } open fun getBom(id: Long): M18BomResponse? { logger.info("M18 Bom ID: $id") return getLine( id = id, params = null, api = M18_LOAD_BOM_API ) } open fun saveBoms(request: M18CommonRequest) { logger.info("--------------------------------------------Start - Saving M18 Boms--------------------------------------------") val boms = getBoms(request) val successList = mutableListOf() val successDetailList = mutableListOf() val failList = mutableListOf() val failDetailList = mutableListOf>>() var failDetailCount = 0 val values = boms?.values?.sortedBy { it.id } if (values != null) { values.forEach { bom -> try { val bomDetail = getBom(bom.id) val bomUdfBomForShop = bomDetail?.data?.udfbomforshop?.get(0) val bomUdfProduct = bomDetail?.data?.udfproduct logger.info(bomUdfBomForShop.toString()) logger.info(bomUdfProduct.toString()) if (bomUdfBomForShop != null && bomUdfProduct != null) { // Save Bom val saveBomRequest = SaveBomRequest( // itemId = itemsService.findByNameAndM18UomId(bomUdfBomForShop.desc, bomUdfBomForShop.udfUnit)?.id, code = bomUdfBomForShop.code, name = bomUdfBomForShop.desc, description = bomUdfBomForShop.desc, outputQty = if (bomUdfBomForShop.udfHarvest.trim().toBigDecimalOrNull() != null) bomUdfBomForShop.udfHarvest.trim().toBigDecimal() else BigDecimal(0), outputQtyUom = bomUdfBomForShop.udfHarvestUnit, yield = bomUdfBomForShop.udfYieldratePP, m18UomId = bomUdfBomForShop.udfUnit, m18Id = bomUdfBomForShop.id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(bomUdfBomForShop.lastModifyDate) ) val bomId = bomService.saveBom(saveBomRequest).id successList += bom.id // Save Bom Material logger.info("Start saving bom material...") val tempFailList = mutableListOf() bomUdfProduct.forEach { bomMaterial -> try { val saveBomMaterialRequest = SaveBomMaterialRequest( m18ItemId = bomMaterial.udfProduct, itemName = bomMaterial.udfIngredients, qty = bomMaterial.udfqty, m18UomId = bomMaterial.udfpurchaseUnit, uomName = bomMaterial.udfBaseUnit, bomId = bomId, m18Id = bomMaterial.id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(bomUdfBomForShop.lastModifyDate) ) bomMaterialService.saveBomMaterial(saveBomMaterialRequest) successDetailList += bomMaterial.id } catch (e: Exception) { tempFailList += bomMaterial.id logger.error("(Bom Material) Exception") logger.error("(Bom Material) Fail Message: ${e.message}") logger.error("(Bom Material) Fail Count ${++failDetailCount}: Bom Material ID - ${bomMaterial.id} | Bom ID - ${bom.id}") } } failDetailList += Pair(bom.id, tempFailList) logger.info("Save Success (M18): ${bom.id}") } else { failList.add(bom.id) logger.error("(Bom) Fail Message: ${bomDetail?.messages?.get(0)?.msgDetail}") logger.error("(Bom) Fail Count ${failList.size}: Bom ID - ${bom.id} Not Found") } } catch (e: Exception) { failList += bom.id logger.error("(Bom) Exception") logger.error("(Bom) Fail Message: ${e.message}") logger.error("(Bom) Fail Count ${failList.size}: Bom ID - ${bom.id}") } } } else { logger.error("Currency List is null. May occur errors.") } logger.info("Total Bom Save Success (${successList.size})") logger.info("Total Bom Save Detail Success (${successDetailList.size})") if (failList.size > 0) { logger.error("Total Bom Fail (${failList.size}): $failList") } if (failDetailCount > 0) { logger.error("Total Bom Detail Fail (${failDetailCount}): $failDetailList") } logger.info("--------------------------------------------End - Saving Boms--------------------------------------------") } // --------------------------------------------- Business Unit (Shop) --------------------------------------------- /// open fun getBusinessUnits(request: M18CommonRequest): M18BusinessUnitListResponse? { // seems no beId return getList( stSearch = StSearchType.BUSINESS_UNIT.value, params = null, // conds = beIdConds request = request ) } open fun getBusinessUnit(id: Long): M18BusinessUnitResponse? { logger.info("M18 Business Unit ID: $id") return getLine( id = id, params = null, api = M18_LOAD_BUSINESS_UNIT_API ) } open fun saveBusinessUnits(request: M18CommonRequest) { logger.info("--------------------------------------------Start - Saving M18 Business Units (Shops)--------------------------------------------") val businessUnits = getBusinessUnits(request) val successList = mutableListOf() val failList = mutableListOf() val values = businessUnits?.values?.sortedBy { it.id } val busMessages = if(businessUnits?.messages?.isNotEmpty() == true) businessUnits.messages[0] else null if (values != null) { values.forEach { businessUnit -> // if (vendor.id in exampleVendors) { try { val businessUnitDetail = getBusinessUnit(businessUnit.id) val virdept = businessUnitDetail?.data?.virdept?.get(0) val buMessages = if(businessUnitDetail?.messages?.isNotEmpty() == true) businessUnitDetail?.messages[0] else null if (virdept != null) { val saveShopRequest = SaveShopRequest( id = null, code = virdept.code, name = virdept.desc.ifEmpty { virdept.`desc_zh-TW` }, brNo = null, contactNo = virdept.tel, contactEmail = virdept.email, contactName = null, addr1 = virdept.addr.ifEmpty { virdept.addr_en }, addr2 = virdept.addr2.ifEmpty { virdept.addr2_en }, addr3 = virdept.addr3.ifEmpty { virdept.addr3_en }, addr4 = null, district = null, type = ShopType.SHOP.value, m18Id = businessUnit.id, m18LastModifyDate = commonUtils.timestampToLocalDateTime(virdept.lastModifyDate) ) shopService.saveShop(saveShopRequest) successList.add(businessUnit.id) logger.info("Success Count ${successList.size}: ${businessUnit.id} | ${virdept.code} | ${virdept.desc}") } else { failList.add(businessUnit.id) logger.error("(Business Unit) Fail Message: ${buMessages?.msgDetail}") logger.error("(Business Unit) Fail Count ${failList.size}: Business Unit ID - ${businessUnit.id} Not Found") } } catch (e: Exception) { failList.add(businessUnit.id) logger.error("(Business Unit) Exception") logger.error("(Business Unit) Fail Message: ${e.message}") logger.error("(Business Unit) Fail Count ${failList.size}: Business Unit ID - ${businessUnit.id}") } // } } } else { logger.error("(Business Unit) Business Unit List is null. May occur errors.") logger.error("(Business Unit)) Fail Message: ${busMessages?.msgDetail}") logger.error("(Business Unit) Business Unit List is null. May occur errors.") } logger.info("Total Success (${successList.size})") if (failList.size > 0) { logger.error("Total Fail (${failList.size}): $failList") } logger.info("--------------------------------------------End - Saving M18 Business Units--------------------------------------------") } }