@@ -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) | |||
} | |||
/** | |||
@@ -29,6 +29,7 @@ open class M18Config { | |||
// Supplier | |||
// @Value("\${m18.config.supplier-not.material-po}") | |||
// var MATERIAL_PO_SUPPLIER_NOT: List<String> = listOf("P06", "P07", "T62"); // If need oem type | |||
var MATERIAL_PO_SUPPLIER_NOT: List<String> = 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; | |||
@@ -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<Long>() { | |||
@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) | |||
@@ -5,5 +5,6 @@ import org.springframework.stereotype.Repository | |||
@Repository | |||
interface M18DataLogRepository : AbstractRepository<M18DataLog, Long> { | |||
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? | |||
} |
@@ -0,0 +1,7 @@ | |||
package com.ffii.fpsms.m18.enums | |||
enum class M18DataLogStatus(val value: Int) { | |||
FAIL(-1), | |||
NOT_PROCESS(0), | |||
SUCCESS(1), | |||
} |
@@ -0,0 +1,17 @@ | |||
package com.ffii.fpsms.m18.enums | |||
import jakarta.persistence.AttributeConverter | |||
import jakarta.persistence.Converter | |||
@Converter(autoApply = true) | |||
class M18DataLogStatusConverter: AttributeConverter<M18DataLogStatus, Int> { | |||
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 } | |||
} | |||
} | |||
} |
@@ -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<String, Any?>?, | |||
val status: Boolean? = true, | |||
val refType: String? = null, | |||
val m18Id: Long? = null, | |||
val m18LastModifyDate: LocalDateTime? = null, | |||
val dataLog: MutableMap<String, Any?>? = null, | |||
val status: Int? = 0, | |||
val statusEnum: M18DataLogStatus? = null, | |||
) |
@@ -4,5 +4,5 @@ data class M18DataLogResponse ( | |||
val id: Long?, | |||
val refType: String?, | |||
val m18Id: Long?, | |||
val status: Boolean?, | |||
val status: String?, | |||
) |
@@ -0,0 +1,6 @@ | |||
package com.ffii.fpsms.m18.model | |||
data class M18ErrorMessages ( | |||
val msgDetail: String?, | |||
val msgCode: String?, | |||
) |
@@ -7,6 +7,7 @@ enum class StSearchType(val value: String) { | |||
CUSTOMER("cus"), | |||
UNIT("unit"), | |||
CURRENCY("cur"), | |||
BOM("udfbomforshop"), | |||
} | |||
/** M18 Common Master Data Request */ | |||
@@ -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<M18ProductListValue>?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18ProductListValue ( | |||
@@ -79,6 +73,7 @@ data class M18VendorVen ( | |||
/** Vendor List Response */ | |||
data class M18VendorListResponse ( | |||
val values: List<M18VendorListValue>?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18VendorListValue ( | |||
@@ -89,6 +84,7 @@ data class M18VendorListValue ( | |||
/** Unit List Response */ | |||
data class M18UnitListResponse ( | |||
val values: List<M18UnitListValue>?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18UnitListValue ( | |||
@@ -100,7 +96,8 @@ data class M18UnitListValue ( | |||
/** Unit Response */ | |||
data class M18UnitResponse ( | |||
val data: List<M18UnitData> | |||
val data: M18UnitData?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18UnitData ( | |||
@@ -120,6 +117,7 @@ data class M18UnitUnit ( | |||
/** Currency List Response */ | |||
data class M18CurrencyListResponse ( | |||
val values: List<M18CurrencyListValue>?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18CurrencyListValue ( | |||
@@ -132,7 +130,8 @@ data class M18CurrencyListValue ( | |||
/** Currency Response */ | |||
data class M18CurrencyResponse ( | |||
val data: List<M18CurrencyData> | |||
val data: M18CurrencyData?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
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<M18BomListValue>?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18BomListValue ( | |||
val id: Long, | |||
val code: String, | |||
val desc: String, | |||
) | |||
/** Bom Response */ | |||
data class M18BomResponse ( | |||
val data: M18BomData?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18BomData ( | |||
val udfbomforshop: List<M18BomUdfBomForShop>, | |||
val udfproduct: List<M18BomUdfProduct>, | |||
) | |||
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, | |||
) |
@@ -7,12 +7,13 @@ import java.time.LocalDateTime | |||
/** Purchase Order Response */ | |||
data class M18PurchaseOrderResponse ( | |||
val data: M18PurchaseOrderData | |||
val data: M18PurchaseOrderData?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18PurchaseOrderData ( | |||
val mainpo: List<M18PurchaseOrderMainPo>, | |||
val pot: List<M18PurchaseOrderPot> | |||
val mainpo: List<M18PurchaseOrderMainPo>?, | |||
val pot: List<M18PurchaseOrderPot>?, | |||
) | |||
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<Pair<PurchaseOrderType, List<M18PurchaseOrderListValue>?>> | |||
var valuesWithType: MutableList<Pair<PurchaseOrderType, M18PurchaseOrderListResponse?>> | |||
) | |||
data class M18PurchaseOrderListResponse ( | |||
var values: List<M18PurchaseOrderListValue> | |||
var values: List<M18PurchaseOrderListValue>?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18PurchaseOrderListValue ( | |||
@@ -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, | |||
) |
@@ -0,0 +1,52 @@ | |||
package com.ffii.fpsms.m18.model | |||
// Purchase Quotation | |||
data class M18PurchaseQuotationResponse( | |||
val data: M18PurchaseQuotationData?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18PurchaseQuotationData( | |||
val mainvqu: List<M18PurchaseQuotationMainvqu>, | |||
val remvqu: List<M18PurchaseQuotationRemvqu>, | |||
val vqut: List<M18PurchaseQuotationVqut>, | |||
) | |||
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<M18PurchaseQuotationValues>?, | |||
val messages: List<M18ErrorMessages>? | |||
) | |||
data class M18PurchaseQuotationValues( | |||
val id: Long, | |||
val code: String, | |||
val tDate: String, // Effective date | |||
val expDate: String, | |||
val status: String, | |||
val lastModifyDate: String, | |||
) |
@@ -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(), | |||
) | |||
} | |||
@@ -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 <reified T : Any> 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<M18BomListResponse>( | |||
stSearch = StSearchType.BOM.value, | |||
params = null, | |||
conds = beIdConds | |||
) | |||
} | |||
open fun getBom(id: Long): M18BomResponse? { | |||
logger.info("M18 Bom ID: $id") | |||
return getLine<M18BomResponse>( | |||
id = id, | |||
params = null, | |||
api = M18_LOAD_BOM_API | |||
) | |||
} | |||
open fun saveBoms() { | |||
logger.info("--------------------------------------------Start - Saving M18 Boms--------------------------------------------") | |||
val boms = getBoms() | |||
val successList = mutableListOf<Long>() | |||
val successDetailList = mutableListOf<Long>() | |||
val failList = mutableListOf<Long>() | |||
val failDetailList = mutableListOf<Pair<Long, MutableList<Long>>>() | |||
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<Long>() | |||
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--------------------------------------------") | |||
} | |||
} |
@@ -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<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>( | |||
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<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>( | |||
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<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>( | |||
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--------------------------------------------") | |||
} | |||
} |
@@ -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<M18PurchaseQuotationListResponse, M18PurchaseQuotationListRequest>( | |||
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<M18PurchaseQuotationResponse, M18PurchaseQuotationRequest>( | |||
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<Long>() | |||
val successDetailList = mutableListOf<Long>() | |||
val failList = mutableListOf<Long>() | |||
val failDetailList = mutableListOf<Long>() | |||
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--------------------------------------------") | |||
} | |||
} |
@@ -15,7 +15,7 @@ open class M18TokenService( | |||
private val m18Config: M18Config | |||
) { | |||
// @Bean | |||
@Bean | |||
fun run() { | |||
// val params: MutableMap<String, String> = mutableMapOf( | |||
// "grant_type" to m18Config.GRANT_TYPE, | |||
@@ -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<Long>, prefix: String, delimiter: String): String { | |||
fun listToString(numbers: List<Long>?, prefix: String, delimiter: String): String { | |||
if (numbers == null) { | |||
return "" | |||
} | |||
return numbers.joinToString(delimiter) { "$prefix$it" } | |||
} | |||
} |
@@ -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<Long>? { | |||
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<Long>? { | |||
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() | |||
} | |||
} |
@@ -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?, | |||
) |
@@ -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 | |||
@@ -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`); | |||
; |
@@ -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`) | |||
); |