diff --git a/src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt b/src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt index f59ed5d..943f063 100644 --- a/src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt +++ b/src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt @@ -2,6 +2,7 @@ package com.ffii.fpsms.api.service import com.ffii.core.utils.JwtTokenUtil import com.ffii.fpsms.m18.M18Config +import com.ffii.fpsms.m18.service.M18TokenService import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Value @@ -15,14 +16,17 @@ import org.springframework.web.reactive.function.client.bodyToMono import reactor.core.publisher.Mono import kotlin.reflect.full.memberProperties import org.springframework.cloud.context.config.annotation.RefreshScope +import org.springframework.context.annotation.Lazy import org.springframework.http.HttpStatus +import org.springframework.http.HttpStatusCode import org.springframework.web.reactive.function.client.ClientRequest import org.springframework.web.reactive.function.client.WebClientResponseException import org.springframework.web.reactive.function.client.awaitBody @Service open class ApiCallerService( - val m18Config: M18Config + val m18Config: M18Config, + @Lazy val m18TokenService: M18TokenService, ) { val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) @@ -80,6 +84,9 @@ open class ApiCallerService( logger.error("WebClientResponseException") logger.error("Error Status: ${error.statusCode} - ${error.statusText}") logger.error("Error Message: ${error.message}") + if (error.statusCode == HttpStatusCode.valueOf(400)) { + m18TokenService.run() + } Mono.error(error) } .onErrorResume { error -> @@ -87,6 +94,7 @@ open class ApiCallerService( logger.error("Error Message: ${error.message}") Mono.error(error) } + .retry(5) } /** diff --git a/src/main/java/com/ffii/fpsms/m18/M18Config.kt b/src/main/java/com/ffii/fpsms/m18/M18Config.kt index d24d977..32c0f28 100644 --- a/src/main/java/com/ffii/fpsms/m18/M18Config.kt +++ b/src/main/java/com/ffii/fpsms/m18/M18Config.kt @@ -29,6 +29,7 @@ open class M18Config { // Supplier // @Value("\${m18.config.supplier-not.material-po}") +// var MATERIAL_PO_SUPPLIER_NOT: List = listOf("P06", "P07", "T62"); // If need oem type var MATERIAL_PO_SUPPLIER_NOT: List = listOf("P06", "P07"); // @Value("\${m18.config.supplier.shop-po}") @@ -58,13 +59,13 @@ open class M18Config { // BE // @Value("\${m18.config.beId.pp}") - var BEID_PP: Long = 27; + var BEID_PP: Long = 29; // @Value("\${m18.config.beId.pf}") - var BEID_PF: Long = 1; + var BEID_PF: Long = 27; // @Value("\${m18.config.beId.toa}") - var BEID_TOA: Long = 29; + var BEID_TOA: Long = 1; // Fetch var ACCESS_TOKEN: String? = null; diff --git a/src/main/java/com/ffii/fpsms/m18/entity/M18DataLog.kt b/src/main/java/com/ffii/fpsms/m18/entity/M18DataLog.kt index eb215ff..1525736 100644 --- a/src/main/java/com/ffii/fpsms/m18/entity/M18DataLog.kt +++ b/src/main/java/com/ffii/fpsms/m18/entity/M18DataLog.kt @@ -1,7 +1,10 @@ package com.ffii.fpsms.m18.entity import com.ffii.core.entity.BaseEntity +import com.ffii.fpsms.m18.enums.M18DataLogStatus +import com.ffii.fpsms.m18.enums.M18DataLogStatusConverter import jakarta.persistence.Column +import jakarta.persistence.Convert import jakarta.persistence.Entity import jakarta.persistence.Table import jakarta.validation.constraints.NotNull @@ -29,7 +32,8 @@ open class M18DataLog : BaseEntity() { @NotNull @Column(name = "status", nullable = false) - open var status: Boolean? = null + @Convert(converter = M18DataLogStatusConverter::class) + open var status: M18DataLogStatus? = null @NotNull @Column(name = "m18LastModifyDate", nullable = false) diff --git a/src/main/java/com/ffii/fpsms/m18/entity/M18DataLogRepository.kt b/src/main/java/com/ffii/fpsms/m18/entity/M18DataLogRepository.kt index 34bc288..12d3016 100644 --- a/src/main/java/com/ffii/fpsms/m18/entity/M18DataLogRepository.kt +++ b/src/main/java/com/ffii/fpsms/m18/entity/M18DataLogRepository.kt @@ -5,5 +5,6 @@ import org.springframework.stereotype.Repository @Repository interface M18DataLogRepository : AbstractRepository { - fun findFirstByM18IdAndRefTypeAndDeletedIsFalseOrderByM18LastModifyDateDesc(m18Id: Long, refType: String): M18DataLog? + // find latest m18 data log by m18 id & ref type & status is true & deleted is false (order by id asc limit 1) + fun findTopByM18IdAndRefTypeAndDeletedIsFalseAndStatusIsTrueOrderByIdDesc(m18Id: Long, refType: String): M18DataLog? } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/enums/M18DataLogEnum.kt b/src/main/java/com/ffii/fpsms/m18/enums/M18DataLogEnum.kt new file mode 100644 index 0000000..bacba4f --- /dev/null +++ b/src/main/java/com/ffii/fpsms/m18/enums/M18DataLogEnum.kt @@ -0,0 +1,7 @@ +package com.ffii.fpsms.m18.enums + +enum class M18DataLogStatus(val value: Int) { + FAIL(-1), + NOT_PROCESS(0), + SUCCESS(1), +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/enums/M18DataLogEnumConverter.kt b/src/main/java/com/ffii/fpsms/m18/enums/M18DataLogEnumConverter.kt new file mode 100644 index 0000000..60a776e --- /dev/null +++ b/src/main/java/com/ffii/fpsms/m18/enums/M18DataLogEnumConverter.kt @@ -0,0 +1,17 @@ +package com.ffii.fpsms.m18.enums + +import jakarta.persistence.AttributeConverter +import jakarta.persistence.Converter + +@Converter(autoApply = true) +class M18DataLogStatusConverter: AttributeConverter { + override fun convertToDatabaseColumn(status: M18DataLogStatus?): Int? { + return status?.value + } + + override fun convertToEntityAttribute(value: Int?): M18DataLogStatus? { + return value?.let { v -> + M18DataLogStatus.entries.find { it.value == v } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/model/M18DataLogRequest.kt b/src/main/java/com/ffii/fpsms/m18/model/M18DataLogRequest.kt index dfbec82..c34a09d 100644 --- a/src/main/java/com/ffii/fpsms/m18/model/M18DataLogRequest.kt +++ b/src/main/java/com/ffii/fpsms/m18/model/M18DataLogRequest.kt @@ -1,12 +1,14 @@ package com.ffii.fpsms.m18.model +import com.ffii.fpsms.m18.enums.M18DataLogStatus import java.time.LocalDateTime data class SaveM18DataLogRequest ( val id: Long?, - val refType: String?, - val m18Id: Long?, - val m18LastModifyDate: LocalDateTime?, - val dataLog: MutableMap?, - val status: Boolean? = true, + val refType: String? = null, + val m18Id: Long? = null, + val m18LastModifyDate: LocalDateTime? = null, + val dataLog: MutableMap? = null, + val status: Int? = 0, + val statusEnum: M18DataLogStatus? = null, ) \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/model/M18DataLogResponse.kt b/src/main/java/com/ffii/fpsms/m18/model/M18DataLogResponse.kt index 13ddda8..d8f8a05 100644 --- a/src/main/java/com/ffii/fpsms/m18/model/M18DataLogResponse.kt +++ b/src/main/java/com/ffii/fpsms/m18/model/M18DataLogResponse.kt @@ -4,5 +4,5 @@ data class M18DataLogResponse ( val id: Long?, val refType: String?, val m18Id: Long?, - val status: Boolean?, + val status: String?, ) \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/model/M18ErrorMessages.kt b/src/main/java/com/ffii/fpsms/m18/model/M18ErrorMessages.kt new file mode 100644 index 0000000..abe85f6 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/m18/model/M18ErrorMessages.kt @@ -0,0 +1,6 @@ +package com.ffii.fpsms.m18.model + +data class M18ErrorMessages ( + val msgDetail: String?, + val msgCode: String?, +) \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/model/M18MasterDataRequest.kt b/src/main/java/com/ffii/fpsms/m18/model/M18MasterDataRequest.kt index ebe7a2d..41ad625 100644 --- a/src/main/java/com/ffii/fpsms/m18/model/M18MasterDataRequest.kt +++ b/src/main/java/com/ffii/fpsms/m18/model/M18MasterDataRequest.kt @@ -7,6 +7,7 @@ enum class StSearchType(val value: String) { CUSTOMER("cus"), UNIT("unit"), CURRENCY("cur"), + BOM("udfbomforshop"), } /** M18 Common Master Data Request */ diff --git a/src/main/java/com/ffii/fpsms/m18/model/M18MasterDataResponse.kt b/src/main/java/com/ffii/fpsms/m18/model/M18MasterDataResponse.kt index ba4e46a..0ee93da 100644 --- a/src/main/java/com/ffii/fpsms/m18/model/M18MasterDataResponse.kt +++ b/src/main/java/com/ffii/fpsms/m18/model/M18MasterDataResponse.kt @@ -1,13 +1,6 @@ package com.ffii.fpsms.m18.model -import java.time.Instant -import java.time.LocalDateTime - -/** Error Messages */ -data class M18ErrorMessages ( - val msgDetail: String?, - val msgCode: String?, -) +import java.math.BigDecimal /** Product / Material Response */ data class M18ProductResponse ( @@ -43,6 +36,7 @@ data class M18ProductPrice ( /** Product / Material List Response */ data class M18ProductListResponse ( val values: List?, + val messages: List? ) data class M18ProductListValue ( @@ -79,6 +73,7 @@ data class M18VendorVen ( /** Vendor List Response */ data class M18VendorListResponse ( val values: List?, + val messages: List? ) data class M18VendorListValue ( @@ -89,6 +84,7 @@ data class M18VendorListValue ( /** Unit List Response */ data class M18UnitListResponse ( val values: List?, + val messages: List? ) data class M18UnitListValue ( @@ -100,7 +96,8 @@ data class M18UnitListValue ( /** Unit Response */ data class M18UnitResponse ( - val data: List + val data: M18UnitData?, + val messages: List? ) data class M18UnitData ( @@ -120,6 +117,7 @@ data class M18UnitUnit ( /** Currency List Response */ data class M18CurrencyListResponse ( val values: List?, + val messages: List? ) data class M18CurrencyListValue ( @@ -132,7 +130,8 @@ data class M18CurrencyListValue ( /** Currency Response */ data class M18CurrencyResponse ( - val data: List + val data: M18CurrencyData?, + val messages: List? ) data class M18CurrencyData ( @@ -147,4 +146,49 @@ data class M18CurrencyCur ( val sym: String, val desc: String, val status: String, +) + +/** Bom List Response */ +data class M18BomListResponse ( + val values: List?, + val messages: List? +) + +data class M18BomListValue ( + val id: Long, + val code: String, + val desc: String, +) + +/** Bom Response */ +data class M18BomResponse ( + val data: M18BomData?, + val messages: List? +) + +data class M18BomData ( + val udfbomforshop: List, + val udfproduct: List, +) + +data class M18BomUdfBomForShop ( + val id: Long, + val expiredDate: Long, + val lastModifyDate: Long, + val code: String, + val udfYieldratePP: BigDecimal, + val udfHarvestUnit: String, + val udfHarvest: String, + val udfUnit: Long, + val desc: String, + val status: String, +) + +data class M18BomUdfProduct ( + val id: Long, + val udfqty: BigDecimal, + val udfpurchaseUnit: Long, + val udfProduct: Long, + val udfIngredients: String, + val udfBaseUnit: String, ) \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/model/M18PurchaseOrderResponse.kt b/src/main/java/com/ffii/fpsms/m18/model/M18PurchaseOrderResponse.kt index e669732..972395d 100644 --- a/src/main/java/com/ffii/fpsms/m18/model/M18PurchaseOrderResponse.kt +++ b/src/main/java/com/ffii/fpsms/m18/model/M18PurchaseOrderResponse.kt @@ -7,12 +7,13 @@ import java.time.LocalDateTime /** Purchase Order Response */ data class M18PurchaseOrderResponse ( - val data: M18PurchaseOrderData + val data: M18PurchaseOrderData?, + val messages: List? ) data class M18PurchaseOrderData ( - val mainpo: List, - val pot: List + val mainpo: List?, + val pot: List?, ) data class M18PurchaseOrderMainPo ( @@ -24,7 +25,8 @@ data class M18PurchaseOrderMainPo ( val dDate: Long, /** Order Date */ val tDate: Long, - val lastModifyDate: Long + val lastModifyDate: Long, + val curId: Long, ) data class M18PurchaseOrderPot ( @@ -40,16 +42,16 @@ data class M18PurchaseOrderPot ( // val seriesId: Long?, val qty: BigDecimal, val amt: BigDecimal, - val curId: Long, ) /** Purchase Order List Response */ data class M18PurchaseOrderListResponseWithType ( - var valuesWithType: MutableList?>> + var valuesWithType: MutableList> ) data class M18PurchaseOrderListResponse ( - var values: List + var values: List?, + val messages: List? ) data class M18PurchaseOrderListValue ( diff --git a/src/main/java/com/ffii/fpsms/m18/model/M18PurchaseQuotationRequest.kt b/src/main/java/com/ffii/fpsms/m18/model/M18PurchaseQuotationRequest.kt new file mode 100644 index 0000000..152e48c --- /dev/null +++ b/src/main/java/com/ffii/fpsms/m18/model/M18PurchaseQuotationRequest.kt @@ -0,0 +1,14 @@ +package com.ffii.fpsms.m18.model + +data class M18PurchaseQuotationRequest( + val menuCode: String = "vqu", + val id: Long?, + val params: String? = null, + val conds: String? = null, +) + +data class M18PurchaseQuotationListRequest( + val stSearch: String = "vqu", + val params: String? = null, + val conds: String? = null, +) diff --git a/src/main/java/com/ffii/fpsms/m18/model/M18PurchaseQuotationResponse.kt b/src/main/java/com/ffii/fpsms/m18/model/M18PurchaseQuotationResponse.kt new file mode 100644 index 0000000..de48683 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/m18/model/M18PurchaseQuotationResponse.kt @@ -0,0 +1,52 @@ +package com.ffii.fpsms.m18.model + +// Purchase Quotation +data class M18PurchaseQuotationResponse( + val data: M18PurchaseQuotationData?, + val messages: List? +) + +data class M18PurchaseQuotationData( + val mainvqu: List, + val remvqu: List, + val vqut: List, +) + +data class M18PurchaseQuotationMainvqu( + val id: Long, + val expDate: Long, + val lastModifyDate: Long, + val tDate: Long, + val venId: Long, + val manId: Long, + val code: String, +) + +data class M18PurchaseQuotationRemvqu( + val id: Long, + val remarks: String, + val tradeTerm: String, +) + +data class M18PurchaseQuotationVqut( + val bDesc: String, + val id: Long, + val refCode: String, + val unitId: Long, + val proId: Long, +) + +// Purchase Quotation List +data class M18PurchaseQuotationListResponse( + val values: List?, + val messages: List? +) + +data class M18PurchaseQuotationValues( + val id: Long, + val code: String, + val tDate: String, // Effective date + val expDate: String, + val status: String, + val lastModifyDate: String, +) \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/service/M18DataLogService.kt b/src/main/java/com/ffii/fpsms/m18/service/M18DataLogService.kt index a019e2c..f0e27ab 100644 --- a/src/main/java/com/ffii/fpsms/m18/service/M18DataLogService.kt +++ b/src/main/java/com/ffii/fpsms/m18/service/M18DataLogService.kt @@ -2,8 +2,10 @@ package com.ffii.fpsms.m18.service import com.ffii.fpsms.m18.entity.M18DataLog import com.ffii.fpsms.m18.entity.M18DataLogRepository +import com.ffii.fpsms.m18.enums.M18DataLogStatus import com.ffii.fpsms.m18.model.M18DataLogResponse import com.ffii.fpsms.m18.model.SaveM18DataLogRequest +import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus import org.springframework.stereotype.Service import kotlin.jvm.optionals.getOrDefault @@ -12,20 +14,21 @@ class M18DataLogService( val m18DataLogRepository: M18DataLogRepository ) { fun findLatestM18DataLog(m18Id: Long, refType: String): M18DataLog? { - return m18DataLogRepository.findFirstByM18IdAndRefTypeAndDeletedIsFalseOrderByM18LastModifyDateDesc(m18Id, refType) + return m18DataLogRepository.findTopByM18IdAndRefTypeAndDeletedIsFalseAndStatusIsTrueOrderByIdDesc(m18Id, refType) } fun saveM18DataLog(request: SaveM18DataLogRequest): M18DataLogResponse { val id = request.id val m18DataLog = if (id != null && id > 0) m18DataLogRepository.findById(id).getOrDefault(M18DataLog()) else M18DataLog() + val status = request.statusEnum ?: request.status?.let { status -> M18DataLogStatus.entries.find { it.value == status } } m18DataLog.apply { - refType = request.refType - m18Id = request.m18Id - m18LastModifyDate = request.m18LastModifyDate - dataLog = request.dataLog - status = request.status + refType = request.refType ?: this.refType + m18Id = request.m18Id ?: this.m18Id + m18LastModifyDate = request.m18LastModifyDate ?: this.m18LastModifyDate + dataLog = request.dataLog ?: request.dataLog + this.status = status } val response = m18DataLogRepository.saveAndFlush(m18DataLog).let { dataLog -> @@ -33,7 +36,7 @@ class M18DataLogService( id = dataLog.id, refType = dataLog.refType, m18Id = dataLog.m18Id, - status = dataLog.status, + status = dataLog.status?.toString(), ) } diff --git a/src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt b/src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt index c01dd9f..c7bd024 100644 --- a/src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt +++ b/src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt @@ -12,6 +12,7 @@ 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.LocalDate import java.time.LocalDateTime import java.time.format.DateTimeFormatter @@ -25,10 +26,12 @@ open class M18MasterDataService( val uomConversionService: UomConversionService, val currencyService: CurrencyService, val itemUomService: ItemUomService, + val bomService: BomService, + val bomMaterialService: BomMaterialService, ) { - val commonUtils = CommonUtils() val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) + val commonUtils = CommonUtils() val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") // M18 Conditions @@ -37,9 +40,10 @@ open class M18MasterDataService( val seriesIdList = listOf(m18Config.SERIESID_SC, m18Config.SERIESID_SE, m18Config.SERIESID_SF, m18Config.SERIESID_SR) val seriesIdConds = - "(" + commonUtils.ListToString(seriesIdList.filterNotNull(), "seriesId=unequal=", "=or=") + ")" + "(" + 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.listToString(beIdList.filterNotNull(), "beId=equal=", "=or=") + ")" +// val beIdConds = commonUtils.BEID_CONDS // M18 API val M18_COMMON_FETCH_LIST_API = "/search/search" @@ -49,6 +53,7 @@ open class M18MasterDataService( 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}" // --------------------------------------------- Common Function --------------------------------------------- /// private inline fun getList( @@ -151,7 +156,7 @@ open class M18MasterDataService( countryOfOrigin = null, maxQty = null, m18Id = item.id, - m18LastModifyDate = commonUtils.InstantToLocalDateTime(pro.lastModifyDate) + m18LastModifyDate = commonUtils.timestampToLocalDateTime(pro.lastModifyDate) ) val savedItem = itemsService.saveItem(saveItemRequest) @@ -162,9 +167,10 @@ open class M18MasterDataService( // Delete the item uom logger.info("Deleting item uom...") - existingItemUoms?.filter { deleteItemUom -> - m18ItemUomIds.any { it != deleteItemUom.m18Id } - }?.mapNotNull { it.id }?.let { itemUomService.deleteItemUoms(it) } +// 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...") @@ -180,10 +186,10 @@ open class M18MasterDataService( price = null, currencyId = null, m18Id = it.id, - m18LastModifyDate = commonUtils.InstantToLocalDateTime(pro.lastModifyDate) + m18LastModifyDate = commonUtils.timestampToLocalDateTime(pro.lastModifyDate) ) - logger.info("saved item id: ${savedItem.id}") +// logger.info("saved item id: ${savedItem.id}") itemUomService.saveItemUom(itemUomRequest) } @@ -265,7 +271,7 @@ open class M18MasterDataService( district = null, type = ShopType.SUPPLIER.value, m18Id = vendor.id, - m18LastModifyDate = commonUtils.InstantToLocalDateTime(ven.lastModifyDate) + m18LastModifyDate = commonUtils.timestampToLocalDateTime(ven.lastModifyDate) ) shopService.saveShop(saveShopRequest) @@ -409,7 +415,7 @@ open class M18MasterDataService( // save currency values.forEach { currency -> try { - val currencyRequest = CurrencyRequest( + val currencyRequest = SaveCurrencyRequest( id = null, code = currency.code, name = currency.sym, @@ -440,4 +446,118 @@ open class M18MasterDataService( logger.info("--------------------------------------------End - Saving Currencies--------------------------------------------") } + + // --------------------------------------------- Bom --------------------------------------------- /// + open fun getBoms(): M18BomListResponse? { + return getList( + stSearch = StSearchType.BOM.value, + params = null, + conds = beIdConds + ) + } + + 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() { + logger.info("--------------------------------------------Start - Saving M18 Boms--------------------------------------------") + val boms = getBoms() + + 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 + logger.info("AAAAA") + 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) + ) + logger.info("BBBBB") + 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--------------------------------------------") + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/service/M18PurchaseOrderService.kt b/src/main/java/com/ffii/fpsms/m18/service/M18PurchaseOrderService.kt index 06c8323..620e574 100644 --- a/src/main/java/com/ffii/fpsms/m18/service/M18PurchaseOrderService.kt +++ b/src/main/java/com/ffii/fpsms/m18/service/M18PurchaseOrderService.kt @@ -3,8 +3,10 @@ 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.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 @@ -29,11 +31,16 @@ open class M18PurchaseOrderService( val purchaseOrderLineService: PurchaseOrderLineService, val itemsService: ItemsService, val shopService: ShopService, + val itemUomService: ItemUomService, ) { val commonUtils = CommonUtils() val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) - val lastModifyDate = LocalDateTime.now().minusMinutes(30) + 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}" @@ -47,9 +54,14 @@ open class M18PurchaseOrderService( // Material PO val materialPoBuyers = - commonUtils.ListToString(listOf(m18Config.BEID_PP, m18Config.BEID_PF), "beId=equal=", "=or=") - val materialPoSupplierNot = "venId=unequal=${m18Config.MATERIAL_PO_SUPPLIER_NOT}" - val materialPoConds = "${materialPoBuyers}=and=${materialPoSupplierNot}" + commonUtils.listToString(listOf(m18Config.BEID_PP, m18Config.BEID_PF), "beId=equal=", "=or=") + val materialPoSupplierNot = commonUtils.listToString( + shopService.findM18VendorIdsByCodeNotRegexp(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 @@ -61,17 +73,22 @@ open class M18PurchaseOrderService( apiCallerService.get( M18_FETCH_PURCHASE_ORDER_LIST_API, materialPoParams - ).block()?.values ?: mutableListOf() + ).block() ) } catch (e: Exception) { - logger.error("Error on Function - ${e.stackTrace}") + 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 = "venId=equal=${m18Config.SHOP_PO_SUPPLIER}" - val shopPoConds = "${shopPoBuyers}=and=${shopPoSupplier}" + 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 @@ -82,17 +99,22 @@ open class M18PurchaseOrderService( PurchaseOrderType.SHOP, apiCallerService.get( M18_FETCH_PURCHASE_ORDER_LIST_API, shopPoParams - ).block()?.values ?: mutableListOf() + ).block() ) } catch (e: Exception) { - logger.error("Error on Function - ${e.stackTrace}") + 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 = "venId=equal=${m18Config.OEM_PO_SUPPLIER}" - val oemPoConds = "${oemPoBuyers}=and=${oemPoSupplier}" + /* 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 @@ -103,12 +125,12 @@ open class M18PurchaseOrderService( PurchaseOrderType.OEM, apiCallerService.get( M18_FETCH_PURCHASE_ORDER_LIST_API, oemPoParams - ).block()?.values + ).block() ) } catch (e: Exception) { - logger.error("Error on Function - ${e.stackTrace}") + logger.error("(Getting OEM Po list) Error on Function - ${e.stackTrace}") logger.error(e.message) - } + } */ return purchaseOrders } @@ -126,7 +148,7 @@ open class M18PurchaseOrderService( purchaseOrderParams ).block() } catch (e: Exception) { - logger.error("Error on Function - ${e.stackTrace}") + logger.error("(Getting Po Detail) Error on Function - ${e.stackTrace}") logger.error(e.message) } @@ -150,10 +172,13 @@ open class M18PurchaseOrderService( // Loop for Purchase Orders (values) purchaseOrdersWithType.valuesWithType.forEach { purchaseOrderWithType -> val type = purchaseOrderWithType.first - val purchaseOrders = purchaseOrderWithType.second + // if success + val purchaseOrdersValues = purchaseOrderWithType.second?.values + // if fail + val purchaseOrdersMessages = purchaseOrderWithType.second?.messages - if (purchaseOrders != null) { - purchaseOrders.forEach { purchaseOrder -> + if (purchaseOrdersValues != null) { + purchaseOrdersValues.forEach { purchaseOrder -> val purchaseOrderDetail = getPurchaseOrder(purchaseOrder.id) var purchaseOrderId: Long? = null //FP-MTMS @@ -162,6 +187,7 @@ open class M18PurchaseOrderService( // 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) { @@ -169,7 +195,6 @@ open class M18PurchaseOrderService( logger.info("${poRefType}: Finding For Latest M18 Data Log...") val latestPurchaseOrderLog = m18DataLogService.findLatestM18DataLog(purchaseOrder.id, poRefType) -// logger.info("${poRefType}: Latest M18 Data Log ID: ${latestPurchaseOrderLog?.id}") // Save to m18_data_log table logger.info("${poRefType}: Saving for M18 Data Log...") @@ -181,9 +206,9 @@ open class M18PurchaseOrderService( id = null, refType = poRefType, m18Id = purchaseOrder.id, - m18LastModifyDate = commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate), - dataLog = mainpoJson, - status = true + m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainpo.lastModifyDate), +// dataLog = mainpoJson, + statusEnum = M18DataLogStatus.NOT_PROCESS ) val saveM18PurchaseOrderLog = @@ -194,18 +219,18 @@ open class M18PurchaseOrderService( // Find the purchase_order if exist logger.info("${poRefType}: Finding exising purchase order...") val existingPurchaseOrder = - latestPurchaseOrderLog?.id?.let { purchaseOrderService.findPurchaseOrderByM18Id(it) } + 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 supplierId = shopService.findByM18Id(mainpo.venId)?.id val savePurchaseOrderRequest = SavePurchaseOrderRequest( id = existingPurchaseOrder?.id, code = mainpo.code, - supplierId = supplierId, - orderDate = commonUtils.InstantToLocalDateTime(mainpo.tDate), - estimatedArrivalDate = commonUtils.InstantToLocalDateTime(mainpo.dDate), + m18SupplierId = mainpo.venId, + m18CurrencyId = mainpo.curId, + orderDate = commonUtils.timestampToLocalDateTime(mainpo.tDate), + estimatedArrivalDate = commonUtils.timestampToLocalDateTime(mainpo.dDate), completeDate = null, status = PurchaseOrderStatus.PENDING.value, type = type.value, @@ -216,6 +241,16 @@ open class M18PurchaseOrderService( purchaseOrderService.savePurchaseOrder(savePurchaseOrderRequest) purchaseOrderId = savePurchaseOrderResponse.id + // Update m18_data_log with success + val successSaveM18PurchaseOrderLogRequest = SaveM18DataLogRequest( + id = saveM18PurchaseOrderLogRequest.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}") @@ -227,11 +262,8 @@ open class M18PurchaseOrderService( val errorSaveM18PurchaseOrderLogRequest = SaveM18DataLogRequest( id = saveM18PurchaseOrderLogRequest.id, - refType = poRefType, - m18Id = purchaseOrder.id, - m18LastModifyDate = commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate), - dataLog = mainpoJson, - status = false + dataLog = mutableMapOf(Pair("Exception Message", e.message)), + statusEnum = M18DataLogStatus.FAIL ) m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLogRequest) @@ -239,15 +271,16 @@ open class M18PurchaseOrderService( } // 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 + // Find the latest m18 data log by m18 id & type logger.info("${poLineRefType}: Finding For Latest M18 Data Log...") val latestPurchaseOrderLineLog = m18DataLogService.findLatestM18DataLog(line.id, poLineRefType) -// logger.info("${poLineRefType}: Latest M18 Data Log ID: ${latestPurchaseOrderLineLog?.id}") + // logger.info("${poLineRefType}: Latest M18 Data Log ID: ${latestPurchaseOrderLineLog?.id}") // Save to m18_data_log table logger.info("${poLineRefType}: Saving for M18 Data Log...") @@ -262,15 +295,15 @@ open class M18PurchaseOrderService( id = null, refType = poLineRefType, m18Id = line.id, - m18LastModifyDate = commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate), - dataLog = lineJson, - status = true + 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}: 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}") @@ -285,14 +318,15 @@ open class M18PurchaseOrderService( // 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 = null, + uomId = itemUom?.uom?.id, purchaseOrderId = purchaseOrderId, qty = line.qty, price = line.amt, - m18CurrencyId = line.curId, +// m18CurrencyId = mainpo.curId, status = existingPurchaseOrderLine?.status?.value ?: PurchaseOrderLineStatus.PENDING.value, m18DataLogId = saveM18PurchaseOrderLineLog.id, @@ -300,6 +334,18 @@ open class M18PurchaseOrderService( val savePurchaseOrderLineResponse = purchaseOrderLineService.savePurchaseOrderLine(savePurchaseOrderLineRequest) + + // Update m18_data_log with success + val successSaveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( + id = saveM18PurchaseOrderLineLog.id, + dataLog = lineJson, + statusEnum = M18DataLogStatus.NOT_PROCESS + ) + + 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) { @@ -310,11 +356,8 @@ open class M18PurchaseOrderService( val errorSaveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( id = saveM18PurchaseOrderLineLog.id, - refType = "${poRefType}", - m18Id = line.id, - m18LastModifyDate = commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate), - dataLog = lineJson, - status = false + dataLog = mutableMapOf(Pair("Exception Message", e.message)), + statusEnum = M18DataLogStatus.FAIL ) m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLineLogRequest) @@ -328,9 +371,23 @@ open class M18PurchaseOrderService( id = null, refType = "${poLineRefType}", m18Id = purchaseOrder.id, - m18LastModifyDate = commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate), - dataLog = mutableMapOf(Pair("Error Message", "${poLineRefType} is null")), - status = false + 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) @@ -338,15 +395,29 @@ open class M18PurchaseOrderService( } } 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 = if(mainpo?.lastModifyDate != null) commonUtils.instantToLocalDateTime(mainpo.lastModifyDate) else LocalDateTime.now(), m18LastModifyDate = LocalDateTime.now(), - dataLog = mutableMapOf(Pair("Error Message", "${poRefType} is null")), - status = false + 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) @@ -363,14 +434,14 @@ open class M18PurchaseOrderService( // 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") - } +// 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") - } +// if (failDetailList.size > 0) { + logger.error("Total Fail (${poLineRefType}) (${failDetailList.size}): $failDetailList") +// } logger.info("--------------------------------------------End - Saving M18 Purchase Order--------------------------------------------") } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/service/M18PurchaseQuotationService.kt b/src/main/java/com/ffii/fpsms/m18/service/M18PurchaseQuotationService.kt new file mode 100644 index 0000000..f3b4e18 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/m18/service/M18PurchaseQuotationService.kt @@ -0,0 +1,192 @@ +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.M18PurchaseQuotationListRequest +import com.ffii.fpsms.m18.model.M18PurchaseQuotationListResponse +import com.ffii.fpsms.m18.model.M18PurchaseQuotationRequest +import com.ffii.fpsms.m18.model.M18PurchaseQuotationResponse +import com.ffii.fpsms.m18.utils.CommonUtils +import com.ffii.fpsms.modules.master.service.ItemUomService +import com.ffii.fpsms.modules.master.service.ItemsService +import com.ffii.fpsms.modules.purchaseQuotation.service.PurchaseQuotationLineService +import com.ffii.fpsms.modules.purchaseQuotation.service.PurchaseQuotationService +import com.ffii.fpsms.modules.purchaseQuotation.web.model.SavePurchaseQuotationLineRequest +import com.ffii.fpsms.modules.purchaseQuotation.web.model.SavePurchaseQuotationRequest +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Service + +@Service +open class M18PurchaseQuotationService( + val m18Config: M18Config, + val apiCallerService: ApiCallerService, + val itemsService: ItemsService, + val purchaseQuotationService: PurchaseQuotationService, + val purchaseQuotationLineService: PurchaseQuotationLineService, + 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}" + + // M18 Conditions + val beIdList = listOf(m18Config.BEID_PF, m18Config.BEID_PP, m18Config.BEID_TOA) + val beIdConds = "(" + commonUtils.listToString(beIdList.filterNotNull(), "beId=equal=", "=or=") + ")" + + // M18 API + val M18_LOAD_PURCHASE_QUOTATION_API = "/root/api/read/vqu" + val M18_FETCH_PURCHASE_QUOTATION_LIST_API = "/search/search" + + open fun getPurchaseQuotations(): M18PurchaseQuotationListResponse? { + val params = M18PurchaseQuotationListRequest( + conds = beIdConds + ) + + var purchaseQuotations: M18PurchaseQuotationListResponse? = null + + try { + purchaseQuotations = + apiCallerService.get( + M18_FETCH_PURCHASE_QUOTATION_LIST_API, + params + ).block() + } catch (e: Exception) { + logger.error("(Getting Purchase Quotation list) Error on Function - ${e.stackTrace}") + logger.error(e.message) + } + + return purchaseQuotations + } + + open fun getPurchaseQuotation(id: Long): M18PurchaseQuotationResponse? { + val params = M18PurchaseQuotationRequest( + id = id + ) + + var purchaseQuotation: M18PurchaseQuotationResponse? = null + + try { + purchaseQuotation = apiCallerService.get( + M18_LOAD_PURCHASE_QUOTATION_API, + params + ).block() + } catch (e: Exception) { + logger.error("(Getting Purchase Quotation Detail) Error on Function - ${e.stackTrace}") + logger.error(e.message) + } + + return purchaseQuotation + } + + open fun savePurchaseQuotations() { + logger.info("--------------------------------------------Start - Saving M18 Purchase Quotations--------------------------------------------") + val purchaseQuotations = getPurchaseQuotations() + + val pqRefType = "Purchase Quotation" + val pqLineRefType = "Purchase Quotation Line" + + val successList = mutableListOf() + val successDetailList = mutableListOf() + val failList = mutableListOf() + val failDetailList = mutableListOf() + + val values = purchaseQuotations?.values + val pqsMessages = purchaseQuotations?.messages?.get(0) + + if (values != null) { + values.forEach { purchaseQuotation -> + try { + val pqDetail = getPurchaseQuotation(purchaseQuotation.id) + val mainvqu = if(pqDetail?.data?.mainvqu?.isNotEmpty() == true) pqDetail.data.mainvqu[0] else null + val remvqu = if(pqDetail?.data?.remvqu?.isNotEmpty() == true) pqDetail.data.remvqu[0] else null + val vqut = if(pqDetail?.data?.vqut?.isNotEmpty() == true) pqDetail.data.vqut else null + val pqMessages = if(pqDetail?.messages?.isNotEmpty() == true) pqDetail.messages[0] else null + + var pqId: Long? = null + + if (mainvqu != null) { + // Save Purchase Quotation + try { + val savePqRequest = SavePurchaseQuotationRequest( + code = mainvqu.code, + expiryDate = commonUtils.timestampToLocalDateTime(mainvqu.expDate), + effectiveDate = commonUtils.timestampToLocalDateTime(mainvqu.tDate), + m18ShopId = mainvqu.venId, + remarks = remvqu?.remarks, + m18Id = mainvqu.id, + m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainvqu.lastModifyDate) + ) + + pqId = purchaseQuotationService.savePurchaseQuotation(savePqRequest).id + successList += mainvqu.id + logger.info("${pqRefType}: Saved purchase quotation. ID: ${pqId} | M18 ID: ${purchaseQuotation.id}") + } catch (e: Exception) { + failList.add(mainvqu.id) + logger.error("${pqRefType}: Saving Failure!") + logger.error("Error on Function - ${e.stackTrace} | Type: ${pqRefType} | M18 ID: ${purchaseQuotation.id}") + logger.error(e.message) + } + + // Save Purchase Quotation Line + if (vqut != null) { + vqut.forEach { line -> + try { + val savePqLineRequest = SavePurchaseQuotationLineRequest( + purchaseQuotationId = pqId, + m18ItemId = line.proId, + code = line.refCode, + description = line.bDesc, + m18Id = line.id, + m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainvqu.lastModifyDate) + ) + + val pqLineId = purchaseQuotationLineService.savePurchaseQuotationLine(savePqLineRequest).id + successDetailList += line.id + logger.info("${pqRefType}: Saved purchase quotation line. ID: ${pqLineId} | M18 ID: ${purchaseQuotation.id} | M18 Line ID: ${line.id}") + } catch (e: Exception) { + failDetailList.add(line.id) + logger.error("${pqLineRefType}: Saving Failure!") + logger.error("Error on Function - ${e.stackTrace} | Type: ${pqLineRefType} | M18 ID: ${purchaseQuotation.id} | M18 Line ID: ${line.id}") + logger.error(e.message) + } + } + } else { + logger.error("Purchase Quotation Line is null. May occur errors.") + } + } else { + logger.error("Purchase Quotation is null. May occur errors.") + logger.error("Error code: ${pqMessages?.msgDetail}") + logger.error("Error messages: ${pqMessages?.msgDetail}") + } + } catch (e: Exception) { + failList.add(purchaseQuotation.id) + logger.error("${pqRefType} / ${pqLineRefType}: Saving Failure!") + logger.error("Error on Function - ${e.stackTrace} | Type: ${pqRefType} / ${pqLineRefType} | M18 ID: ${purchaseQuotation.id}") + logger.error(e.message) + } + } + } else { + logger.error("Purchase Quotation List is null. May occur errors.") + logger.error("Error code: ${pqsMessages?.msgDetail}") + logger.error("Error messages: ${pqsMessages?.msgDetail}") + } + + logger.info("Total Purchase Quotation Save Success (${successList.size})") + logger.info("Total Purchase Quotation Save Detail Success (${successDetailList.size})") + + if (failList.size > 0) { + logger.error("Total Purchase Quotation Fail (${failList.size}): $failList") + } + + if (failDetailList.size > 0) { + logger.error("Total Purchase Quotation Detail Fail (${failDetailList.size}): $failDetailList") + } + logger.info("--------------------------------------------End - Saving M18 Purchase Quotations--------------------------------------------") + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/service/M18TokenService.kt b/src/main/java/com/ffii/fpsms/m18/service/M18TokenService.kt index 8f62914..8983339 100644 --- a/src/main/java/com/ffii/fpsms/m18/service/M18TokenService.kt +++ b/src/main/java/com/ffii/fpsms/m18/service/M18TokenService.kt @@ -15,7 +15,7 @@ open class M18TokenService( private val m18Config: M18Config ) { -// @Bean + @Bean fun run() { // val params: MutableMap = mutableMapOf( // "grant_type" to m18Config.GRANT_TYPE, diff --git a/src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt b/src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt index 060042c..0157374 100644 --- a/src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt +++ b/src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt @@ -1,20 +1,26 @@ package com.ffii.fpsms.m18.utils +import com.ffii.fpsms.m18.M18Config +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Lazy +import org.springframework.stereotype.Component import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId -open class CommonUtils() { - open fun InstantToLocalDateTime(timestamp: Long):LocalDateTime { +@Component +open class CommonUtils( + +) { + open fun timestampToLocalDateTime(timestamp: Long):LocalDateTime { val localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.of("Asia/Hong_Kong")) -// println("ZoneId: ${ZoneId.systemDefault()}") -// println("ZoneId: ${ZoneId.of("Asia/Hong_Kong")}") - println("Timestamp: $timestamp") - println("Local Date Time: $localDateTime") return localDateTime } - open fun ListToString(numbers: List, prefix: String, delimiter: String): String { + fun listToString(numbers: List?, prefix: String, delimiter: String): String { + if (numbers == null) { + return "" + } return numbers.joinToString(delimiter) { "$prefix$it" } } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/web/M18TestController.kt b/src/main/java/com/ffii/fpsms/m18/web/M18TestController.kt index 8cd2e36..4d3b334 100644 --- a/src/main/java/com/ffii/fpsms/m18/web/M18TestController.kt +++ b/src/main/java/com/ffii/fpsms/m18/web/M18TestController.kt @@ -4,10 +4,15 @@ import com.ffii.core.utils.JwtTokenUtil import com.ffii.fpsms.m18.M18Config import com.ffii.fpsms.m18.service.M18MasterDataService import com.ffii.fpsms.m18.service.M18PurchaseOrderService +import com.ffii.fpsms.m18.service.M18PurchaseQuotationService +import com.ffii.fpsms.modules.master.entity.ItemUom +import com.ffii.fpsms.modules.master.entity.Items import com.ffii.fpsms.modules.master.entity.Shop import com.ffii.fpsms.modules.master.entity.ShopRepository import com.ffii.fpsms.modules.master.entity.projections.SearchId import com.ffii.fpsms.modules.master.enums.ShopType +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 org.slf4j.Logger import org.slf4j.LoggerFactory @@ -22,22 +27,36 @@ import org.springframework.web.bind.annotation.RestController class M18TestController ( private val shopRepository: ShopRepository, private val shopService: ShopService, + private val itemsService: ItemsService, private val m18MasterDataService: M18MasterDataService, private val m18PurchaseOrderService: M18PurchaseOrderService, private val m18Config: M18Config, + private val itemUomService: ItemUomService, + private val m18PurchaseQuotationService: M18PurchaseQuotationService, ) { var logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) @GetMapping("/test1") - fun test1(): List? { - return shopService.findVendorIdsByCodeRegexp(listOf("P06", "P07")) + fun test1(@RequestParam name: String, @RequestParam m18UomId: Long): Items? { + val temp = itemsService.findByNameAndM18UomId(name, m18UomId) + println(name) + println(m18UomId) + println(temp?.id) + return temp } @GetMapping("/test2") fun test2(): List? { - return shopRepository.findIdsByCodeRegexpAndTypeAndDeletedIsFalse("P06|P07", ShopType.SUPPLIER.value) + return shopRepository.findM18IdsByCodeRegexpAndTypeAndDeletedIsFalse("P06|P07", ShopType.SUPPLIER.value) } + @GetMapping("/test3") + fun test3(@RequestParam m18ItemId: Long): ItemUom? { + val response = itemUomService.findPurchaseUnitByM18ItemId(m18ItemId) + println(response?.item?.id) + println(response?.uom?.id) + return response + } // --------------------------------------------- Master Data --------------------------------------------- /// @GetMapping("/product") fun m18Products() { @@ -63,10 +82,23 @@ class M18TestController ( m18MasterDataService.saveCurrencies() } + @GetMapping("/bom") + fun m18Bom() { + logger.info("Access token: ${m18Config.ACCESS_TOKEN}") + m18MasterDataService.saveBoms() + } + // --------------------------------------------- Purchase Order --------------------------------------------- /// @GetMapping("/po") fun m18PO() { logger.info("Access token: ${m18Config.ACCESS_TOKEN}") m18PurchaseOrderService.savePurchaseOrders() } + + // --------------------------------------------- Purchase Quotation --------------------------------------------- /// + @GetMapping("/pq") + fun m18PQ() { + logger.info("Access token: ${m18Config.ACCESS_TOKEN}") + m18PurchaseQuotationService.savePurchaseQuotations() + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/master/web/models/CurrencyRequest.kt b/src/main/java/com/ffii/fpsms/modules/master/web/models/CurrencyRequest.kt deleted file mode 100644 index 40c3548..0000000 --- a/src/main/java/com/ffii/fpsms/modules/master/web/models/CurrencyRequest.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.ffii.fpsms.modules.master.web.models - -import java.time.LocalDateTime - -data class CurrencyRequest ( - val id: Long?, - val code: String?, - val name: String?, - val description: String?, - val m18Id: Long?, - val m18LastModifyDate: LocalDateTime?, -) \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b6a038f..cb17e0f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -42,9 +42,9 @@ m18: supplier-not: material-po: P06, P07 beId: - toa: 29 - pp: 27 - pf: 1 + toa: 1 + pf: 27 + pp: 29 seriesId: pp: 26 pf: 33 diff --git a/src/main/resources/db/changelog/changes/20250515_01_cyril/01_update_bom.sql b/src/main/resources/db/changelog/changes/20250515_01_cyril/01_update_bom.sql new file mode 100644 index 0000000..0b064ac --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250515_01_cyril/01_update_bom.sql @@ -0,0 +1,9 @@ +-- liquibase formatted sql + +-- changeset cyril:update bom +ALTER TABLE `bom` + ADD COLUMN `itemId` INT NULL AFTER `deleted`, + ADD COLUMN `outputQtyUom` VARCHAR(50) NULL AFTER `outputQty`, + ADD COLUMN `yield` decimal(14, 2) NULL AFTER `outputQtyUom`, + ADD CONSTRAINT `FK_BOM_ON_ITEMID` FOREIGN KEY (`itemId`) REFERENCES `items` (`id`); +; \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20250515_01_cyril/02_create_purchase_quotation.sql b/src/main/resources/db/changelog/changes/20250515_01_cyril/02_create_purchase_quotation.sql new file mode 100644 index 0000000..44da5d2 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250515_01_cyril/02_create_purchase_quotation.sql @@ -0,0 +1,46 @@ +-- liquibase formatted sql + +-- changeset cyril:create bom & process table +CREATE TABLE `purchase_quotation` +( + `id` INT NOT NULL AUTO_INCREMENT, + `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `createdBy` VARCHAR(30) NULL DEFAULT NULL, + `version` INT NOT NULL DEFAULT '0', + `modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `modifiedBy` VARCHAR(30) NULL DEFAULT NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT '0', + `code` VARCHAR(30) NOT NULL, + `expiryDate` DATETIME NULL, + `effectiveDate` DATETIME NULL, + `shopId` INT NULL, + `currencyId` INT NULL, + `remarks` VARCHAR(500) NULL, + `m18Id` INT NULL, + `m18LastModifyDate` DATETIME NULL, + CONSTRAINT pk_purchase_quotation PRIMARY KEY (id), + CONSTRAINT `FK_PURCHASE_QUOTATION_ON_SHOPID` FOREIGN KEY (`shopId`) REFERENCES `shop` (`id`), + CONSTRAINT `FK_PURCHASE_QUOTATION_ON_CURRENCYID` FOREIGN KEY (`currencyId`) REFERENCES `currency` (`id`) +); + +CREATE TABLE `purchase_quotation_line` +( + `id` INT NOT NULL AUTO_INCREMENT, + `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `createdBy` VARCHAR(30) NULL DEFAULT NULL, + `version` INT NOT NULL DEFAULT '0', + `modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `modifiedBy` VARCHAR(30) NULL DEFAULT NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT '0', + `purchaseQuotationId` INT NULL, + `itemId` INT NULL, + `code` VARCHAR(30) NULL, + `description` VARCHAR(300) NULL, + `uomId` INT NULL, + `m18Id` INT NULL, + `m18LastModifyDate` DATETIME NULL, + CONSTRAINT pk_purchase_quotation_line PRIMARY KEY (id), + CONSTRAINT `FK_PURCHASE_QUOTATION_LINE_ON_PURCHASEQUOTATIONID` FOREIGN KEY (`purchaseQuotationId`) REFERENCES `purchase_quotation` (`id`), + CONSTRAINT `FK_PURCHASE_QUOTATION_LINE_ON_ITEMID` FOREIGN KEY (`itemId`) REFERENCES `items` (`id`), + CONSTRAINT `FK_PURCHASE_QUOTATION_LINE_ON_UOMID` FOREIGN KEY (`uomId`) REFERENCES `uom_conversion` (`id`) +); \ No newline at end of file