瀏覽代碼

[m18] update m18_data_log, apis, add bom, purchase quotation

create_edit_user
cyril.tsui 3 月之前
父節點
當前提交
75f4b7cfef
共有 25 個檔案被更改,包括 759 行新增133 行删除
  1. +9
    -1
      src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt
  2. +4
    -3
      src/main/java/com/ffii/fpsms/m18/M18Config.kt
  3. +5
    -1
      src/main/java/com/ffii/fpsms/m18/entity/M18DataLog.kt
  4. +2
    -1
      src/main/java/com/ffii/fpsms/m18/entity/M18DataLogRepository.kt
  5. +7
    -0
      src/main/java/com/ffii/fpsms/m18/enums/M18DataLogEnum.kt
  6. +17
    -0
      src/main/java/com/ffii/fpsms/m18/enums/M18DataLogEnumConverter.kt
  7. +7
    -5
      src/main/java/com/ffii/fpsms/m18/model/M18DataLogRequest.kt
  8. +1
    -1
      src/main/java/com/ffii/fpsms/m18/model/M18DataLogResponse.kt
  9. +6
    -0
      src/main/java/com/ffii/fpsms/m18/model/M18ErrorMessages.kt
  10. +1
    -0
      src/main/java/com/ffii/fpsms/m18/model/M18MasterDataRequest.kt
  11. +54
    -10
      src/main/java/com/ffii/fpsms/m18/model/M18MasterDataResponse.kt
  12. +9
    -7
      src/main/java/com/ffii/fpsms/m18/model/M18PurchaseOrderResponse.kt
  13. +14
    -0
      src/main/java/com/ffii/fpsms/m18/model/M18PurchaseQuotationRequest.kt
  14. +52
    -0
      src/main/java/com/ffii/fpsms/m18/model/M18PurchaseQuotationResponse.kt
  15. +10
    -7
      src/main/java/com/ffii/fpsms/m18/service/M18DataLogService.kt
  16. +131
    -11
      src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt
  17. +131
    -60
      src/main/java/com/ffii/fpsms/m18/service/M18PurchaseOrderService.kt
  18. +192
    -0
      src/main/java/com/ffii/fpsms/m18/service/M18PurchaseQuotationService.kt
  19. +1
    -1
      src/main/java/com/ffii/fpsms/m18/service/M18TokenService.kt
  20. +13
    -7
      src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt
  21. +35
    -3
      src/main/java/com/ffii/fpsms/m18/web/M18TestController.kt
  22. +0
    -12
      src/main/java/com/ffii/fpsms/modules/master/web/models/CurrencyRequest.kt
  23. +3
    -3
      src/main/resources/application.yml
  24. +9
    -0
      src/main/resources/db/changelog/changes/20250515_01_cyril/01_update_bom.sql
  25. +46
    -0
      src/main/resources/db/changelog/changes/20250515_01_cyril/02_create_purchase_quotation.sql

+ 9
- 1
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.core.utils.JwtTokenUtil
import com.ffii.fpsms.m18.M18Config import com.ffii.fpsms.m18.M18Config
import com.ffii.fpsms.m18.service.M18TokenService
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value 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 reactor.core.publisher.Mono
import kotlin.reflect.full.memberProperties import kotlin.reflect.full.memberProperties
import org.springframework.cloud.context.config.annotation.RefreshScope import org.springframework.cloud.context.config.annotation.RefreshScope
import org.springframework.context.annotation.Lazy
import org.springframework.http.HttpStatus 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.ClientRequest
import org.springframework.web.reactive.function.client.WebClientResponseException import org.springframework.web.reactive.function.client.WebClientResponseException
import org.springframework.web.reactive.function.client.awaitBody import org.springframework.web.reactive.function.client.awaitBody


@Service @Service
open class ApiCallerService( open class ApiCallerService(
val m18Config: M18Config
val m18Config: M18Config,
@Lazy val m18TokenService: M18TokenService,
) { ) {
val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)


@@ -80,6 +84,9 @@ open class ApiCallerService(
logger.error("WebClientResponseException") logger.error("WebClientResponseException")
logger.error("Error Status: ${error.statusCode} - ${error.statusText}") logger.error("Error Status: ${error.statusCode} - ${error.statusText}")
logger.error("Error Message: ${error.message}") logger.error("Error Message: ${error.message}")
if (error.statusCode == HttpStatusCode.valueOf(400)) {
m18TokenService.run()
}
Mono.error(error) Mono.error(error)
} }
.onErrorResume { error -> .onErrorResume { error ->
@@ -87,6 +94,7 @@ open class ApiCallerService(
logger.error("Error Message: ${error.message}") logger.error("Error Message: ${error.message}")
Mono.error(error) Mono.error(error)
} }
.retry(5)
} }


/** /**


+ 4
- 3
src/main/java/com/ffii/fpsms/m18/M18Config.kt 查看文件

@@ -29,6 +29,7 @@ open class M18Config {


// Supplier // Supplier
// @Value("\${m18.config.supplier-not.material-po}") // @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"); var MATERIAL_PO_SUPPLIER_NOT: List<String> = listOf("P06", "P07");


// @Value("\${m18.config.supplier.shop-po}") // @Value("\${m18.config.supplier.shop-po}")
@@ -58,13 +59,13 @@ open class M18Config {


// BE // BE
// @Value("\${m18.config.beId.pp}") // @Value("\${m18.config.beId.pp}")
var BEID_PP: Long = 27;
var BEID_PP: Long = 29;


// @Value("\${m18.config.beId.pf}") // @Value("\${m18.config.beId.pf}")
var BEID_PF: Long = 1;
var BEID_PF: Long = 27;


// @Value("\${m18.config.beId.toa}") // @Value("\${m18.config.beId.toa}")
var BEID_TOA: Long = 29;
var BEID_TOA: Long = 1;


// Fetch // Fetch
var ACCESS_TOKEN: String? = null; var ACCESS_TOKEN: String? = null;


+ 5
- 1
src/main/java/com/ffii/fpsms/m18/entity/M18DataLog.kt 查看文件

@@ -1,7 +1,10 @@
package com.ffii.fpsms.m18.entity package com.ffii.fpsms.m18.entity


import com.ffii.core.entity.BaseEntity 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.Column
import jakarta.persistence.Convert
import jakarta.persistence.Entity import jakarta.persistence.Entity
import jakarta.persistence.Table import jakarta.persistence.Table
import jakarta.validation.constraints.NotNull import jakarta.validation.constraints.NotNull
@@ -29,7 +32,8 @@ open class M18DataLog : BaseEntity<Long>() {


@NotNull @NotNull
@Column(name = "status", nullable = false) @Column(name = "status", nullable = false)
open var status: Boolean? = null
@Convert(converter = M18DataLogStatusConverter::class)
open var status: M18DataLogStatus? = null


@NotNull @NotNull
@Column(name = "m18LastModifyDate", nullable = false) @Column(name = "m18LastModifyDate", nullable = false)


+ 2
- 1
src/main/java/com/ffii/fpsms/m18/entity/M18DataLogRepository.kt 查看文件

@@ -5,5 +5,6 @@ import org.springframework.stereotype.Repository


@Repository @Repository
interface M18DataLogRepository : AbstractRepository<M18DataLog, Long> { 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?
} }

+ 7
- 0
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),
}

+ 17
- 0
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<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 }
}
}
}

+ 7
- 5
src/main/java/com/ffii/fpsms/m18/model/M18DataLogRequest.kt 查看文件

@@ -1,12 +1,14 @@
package com.ffii.fpsms.m18.model package com.ffii.fpsms.m18.model


import com.ffii.fpsms.m18.enums.M18DataLogStatus
import java.time.LocalDateTime import java.time.LocalDateTime


data class SaveM18DataLogRequest ( data class SaveM18DataLogRequest (
val id: Long?, 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,
) )

+ 1
- 1
src/main/java/com/ffii/fpsms/m18/model/M18DataLogResponse.kt 查看文件

@@ -4,5 +4,5 @@ data class M18DataLogResponse (
val id: Long?, val id: Long?,
val refType: String?, val refType: String?,
val m18Id: Long?, val m18Id: Long?,
val status: Boolean?,
val status: String?,
) )

+ 6
- 0
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?,
)

+ 1
- 0
src/main/java/com/ffii/fpsms/m18/model/M18MasterDataRequest.kt 查看文件

@@ -7,6 +7,7 @@ enum class StSearchType(val value: String) {
CUSTOMER("cus"), CUSTOMER("cus"),
UNIT("unit"), UNIT("unit"),
CURRENCY("cur"), CURRENCY("cur"),
BOM("udfbomforshop"),
} }


/** M18 Common Master Data Request */ /** M18 Common Master Data Request */


+ 54
- 10
src/main/java/com/ffii/fpsms/m18/model/M18MasterDataResponse.kt 查看文件

@@ -1,13 +1,6 @@
package com.ffii.fpsms.m18.model 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 */ /** Product / Material Response */
data class M18ProductResponse ( data class M18ProductResponse (
@@ -43,6 +36,7 @@ data class M18ProductPrice (
/** Product / Material List Response */ /** Product / Material List Response */
data class M18ProductListResponse ( data class M18ProductListResponse (
val values: List<M18ProductListValue>?, val values: List<M18ProductListValue>?,
val messages: List<M18ErrorMessages>?
) )


data class M18ProductListValue ( data class M18ProductListValue (
@@ -79,6 +73,7 @@ data class M18VendorVen (
/** Vendor List Response */ /** Vendor List Response */
data class M18VendorListResponse ( data class M18VendorListResponse (
val values: List<M18VendorListValue>?, val values: List<M18VendorListValue>?,
val messages: List<M18ErrorMessages>?
) )


data class M18VendorListValue ( data class M18VendorListValue (
@@ -89,6 +84,7 @@ data class M18VendorListValue (
/** Unit List Response */ /** Unit List Response */
data class M18UnitListResponse ( data class M18UnitListResponse (
val values: List<M18UnitListValue>?, val values: List<M18UnitListValue>?,
val messages: List<M18ErrorMessages>?
) )


data class M18UnitListValue ( data class M18UnitListValue (
@@ -100,7 +96,8 @@ data class M18UnitListValue (


/** Unit Response */ /** Unit Response */
data class M18UnitResponse ( data class M18UnitResponse (
val data: List<M18UnitData>
val data: M18UnitData?,
val messages: List<M18ErrorMessages>?
) )


data class M18UnitData ( data class M18UnitData (
@@ -120,6 +117,7 @@ data class M18UnitUnit (
/** Currency List Response */ /** Currency List Response */
data class M18CurrencyListResponse ( data class M18CurrencyListResponse (
val values: List<M18CurrencyListValue>?, val values: List<M18CurrencyListValue>?,
val messages: List<M18ErrorMessages>?
) )


data class M18CurrencyListValue ( data class M18CurrencyListValue (
@@ -132,7 +130,8 @@ data class M18CurrencyListValue (


/** Currency Response */ /** Currency Response */
data class M18CurrencyResponse ( data class M18CurrencyResponse (
val data: List<M18CurrencyData>
val data: M18CurrencyData?,
val messages: List<M18ErrorMessages>?
) )


data class M18CurrencyData ( data class M18CurrencyData (
@@ -147,4 +146,49 @@ data class M18CurrencyCur (
val sym: String, val sym: String,
val desc: String, val desc: String,
val status: 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,
) )

+ 9
- 7
src/main/java/com/ffii/fpsms/m18/model/M18PurchaseOrderResponse.kt 查看文件

@@ -7,12 +7,13 @@ import java.time.LocalDateTime


/** Purchase Order Response */ /** Purchase Order Response */
data class M18PurchaseOrderResponse ( data class M18PurchaseOrderResponse (
val data: M18PurchaseOrderData
val data: M18PurchaseOrderData?,
val messages: List<M18ErrorMessages>?
) )


data class M18PurchaseOrderData ( data class M18PurchaseOrderData (
val mainpo: List<M18PurchaseOrderMainPo>,
val pot: List<M18PurchaseOrderPot>
val mainpo: List<M18PurchaseOrderMainPo>?,
val pot: List<M18PurchaseOrderPot>?,
) )


data class M18PurchaseOrderMainPo ( data class M18PurchaseOrderMainPo (
@@ -24,7 +25,8 @@ data class M18PurchaseOrderMainPo (
val dDate: Long, val dDate: Long,
/** Order Date */ /** Order Date */
val tDate: Long, val tDate: Long,
val lastModifyDate: Long
val lastModifyDate: Long,
val curId: Long,
) )


data class M18PurchaseOrderPot ( data class M18PurchaseOrderPot (
@@ -40,16 +42,16 @@ data class M18PurchaseOrderPot (
// val seriesId: Long?, // val seriesId: Long?,
val qty: BigDecimal, val qty: BigDecimal,
val amt: BigDecimal, val amt: BigDecimal,
val curId: Long,
) )


/** Purchase Order List Response */ /** Purchase Order List Response */
data class M18PurchaseOrderListResponseWithType ( data class M18PurchaseOrderListResponseWithType (
var valuesWithType: MutableList<Pair<PurchaseOrderType, List<M18PurchaseOrderListValue>?>>
var valuesWithType: MutableList<Pair<PurchaseOrderType, M18PurchaseOrderListResponse?>>
) )


data class M18PurchaseOrderListResponse ( data class M18PurchaseOrderListResponse (
var values: List<M18PurchaseOrderListValue>
var values: List<M18PurchaseOrderListValue>?,
val messages: List<M18ErrorMessages>?
) )


data class M18PurchaseOrderListValue ( data class M18PurchaseOrderListValue (


+ 14
- 0
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,
)

+ 52
- 0
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<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,
)

+ 10
- 7
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.M18DataLog
import com.ffii.fpsms.m18.entity.M18DataLogRepository 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.M18DataLogResponse
import com.ffii.fpsms.m18.model.SaveM18DataLogRequest import com.ffii.fpsms.m18.model.SaveM18DataLogRequest
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import kotlin.jvm.optionals.getOrDefault import kotlin.jvm.optionals.getOrDefault


@@ -12,20 +14,21 @@ class M18DataLogService(
val m18DataLogRepository: M18DataLogRepository val m18DataLogRepository: M18DataLogRepository
) { ) {
fun findLatestM18DataLog(m18Id: Long, refType: String): M18DataLog? { fun findLatestM18DataLog(m18Id: Long, refType: String): M18DataLog? {
return m18DataLogRepository.findFirstByM18IdAndRefTypeAndDeletedIsFalseOrderByM18LastModifyDateDesc(m18Id, refType)
return m18DataLogRepository.findTopByM18IdAndRefTypeAndDeletedIsFalseAndStatusIsTrueOrderByIdDesc(m18Id, refType)
} }


fun saveM18DataLog(request: SaveM18DataLogRequest): M18DataLogResponse { fun saveM18DataLog(request: SaveM18DataLogRequest): M18DataLogResponse {
val id = request.id val id = request.id
val m18DataLog = val m18DataLog =
if (id != null && id > 0) m18DataLogRepository.findById(id).getOrDefault(M18DataLog()) else 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 { 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 -> val response = m18DataLogRepository.saveAndFlush(m18DataLog).let { dataLog ->
@@ -33,7 +36,7 @@ class M18DataLogService(
id = dataLog.id, id = dataLog.id,
refType = dataLog.refType, refType = dataLog.refType,
m18Id = dataLog.m18Id, m18Id = dataLog.m18Id,
status = dataLog.status,
status = dataLog.status?.toString(),
) )
} }




+ 131
- 11
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.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import java.math.BigDecimal
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -25,10 +26,12 @@ open class M18MasterDataService(
val uomConversionService: UomConversionService, val uomConversionService: UomConversionService,
val currencyService: CurrencyService, val currencyService: CurrencyService,
val itemUomService: ItemUomService, val itemUomService: ItemUomService,
val bomService: BomService,
val bomMaterialService: BomMaterialService,
) { ) {


val commonUtils = CommonUtils()
val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)
val commonUtils = CommonUtils()
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")


// M18 Conditions // M18 Conditions
@@ -37,9 +40,10 @@ open class M18MasterDataService(
val seriesIdList = val seriesIdList =
listOf(m18Config.SERIESID_SC, m18Config.SERIESID_SE, m18Config.SERIESID_SF, m18Config.SERIESID_SR) listOf(m18Config.SERIESID_SC, m18Config.SERIESID_SE, m18Config.SERIESID_SF, m18Config.SERIESID_SR)
val seriesIdConds = 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 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 // M18 API
val M18_COMMON_FETCH_LIST_API = "/search/search" 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_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_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_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 --------------------------------------------- /// // --------------------------------------------- Common Function --------------------------------------------- ///
private inline fun <reified T : Any> getList( private inline fun <reified T : Any> getList(
@@ -151,7 +156,7 @@ open class M18MasterDataService(
countryOfOrigin = null, countryOfOrigin = null,
maxQty = null, maxQty = null,
m18Id = item.id, m18Id = item.id,
m18LastModifyDate = commonUtils.InstantToLocalDateTime(pro.lastModifyDate)
m18LastModifyDate = commonUtils.timestampToLocalDateTime(pro.lastModifyDate)
) )


val savedItem = itemsService.saveItem(saveItemRequest) val savedItem = itemsService.saveItem(saveItemRequest)
@@ -162,9 +167,10 @@ open class M18MasterDataService(


// Delete the item uom // Delete the item uom
logger.info("Deleting 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 // Update the item uom
logger.info("Updating item uom...") logger.info("Updating item uom...")
@@ -180,10 +186,10 @@ open class M18MasterDataService(
price = null, price = null,
currencyId = null, currencyId = null,
m18Id = it.id, 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) itemUomService.saveItemUom(itemUomRequest)
} }


@@ -265,7 +271,7 @@ open class M18MasterDataService(
district = null, district = null,
type = ShopType.SUPPLIER.value, type = ShopType.SUPPLIER.value,
m18Id = vendor.id, m18Id = vendor.id,
m18LastModifyDate = commonUtils.InstantToLocalDateTime(ven.lastModifyDate)
m18LastModifyDate = commonUtils.timestampToLocalDateTime(ven.lastModifyDate)
) )


shopService.saveShop(saveShopRequest) shopService.saveShop(saveShopRequest)
@@ -409,7 +415,7 @@ open class M18MasterDataService(
// save currency // save currency
values.forEach { currency -> values.forEach { currency ->
try { try {
val currencyRequest = CurrencyRequest(
val currencyRequest = SaveCurrencyRequest(
id = null, id = null,
code = currency.code, code = currency.code,
name = currency.sym, name = currency.sym,
@@ -440,4 +446,118 @@ open class M18MasterDataService(


logger.info("--------------------------------------------End - Saving Currencies--------------------------------------------") 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--------------------------------------------")
}
} }

+ 131
- 60
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.core.utils.JwtTokenUtil
import com.ffii.fpsms.api.service.ApiCallerService import com.ffii.fpsms.api.service.ApiCallerService
import com.ffii.fpsms.m18.M18Config import com.ffii.fpsms.m18.M18Config
import com.ffii.fpsms.m18.enums.M18DataLogStatus
import com.ffii.fpsms.m18.model.* import com.ffii.fpsms.m18.model.*
import com.ffii.fpsms.m18.utils.CommonUtils 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.ItemsService
import com.ffii.fpsms.modules.master.service.ShopService import com.ffii.fpsms.modules.master.service.ShopService
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus
@@ -29,11 +31,16 @@ open class M18PurchaseOrderService(
val purchaseOrderLineService: PurchaseOrderLineService, val purchaseOrderLineService: PurchaseOrderLineService,
val itemsService: ItemsService, val itemsService: ItemsService,
val shopService: ShopService, val shopService: ShopService,
val itemUomService: ItemUomService,
) { ) {
val commonUtils = CommonUtils() val commonUtils = CommonUtils()
val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) 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 = // val commonConds =
// "(beId=equal=${m18Config.BEID_PF}=or=beId=equal=${m18Config.BEID_PP}=or=beId=equal=${m18Config.BEID_TOA})=and=lastModifyDate=largerOrEqual=${lastModifyDate}" // "(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 // Material PO
val materialPoBuyers = 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( val materialPoParams = M18PurchaseOrderListRequest(
params = null, params = null,
conds = materialPoConds conds = materialPoConds
@@ -61,17 +73,22 @@ open class M18PurchaseOrderService(
apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>( apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>(
M18_FETCH_PURCHASE_ORDER_LIST_API, M18_FETCH_PURCHASE_ORDER_LIST_API,
materialPoParams materialPoParams
).block()?.values ?: mutableListOf()
).block()
) )
} catch (e: Exception) { } 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) logger.error(e.message)
} }


// Shop PO // 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( val shopPoParams = M18PurchaseOrderListRequest(
params = null, params = null,
conds = shopPoConds conds = shopPoConds
@@ -82,17 +99,22 @@ open class M18PurchaseOrderService(
PurchaseOrderType.SHOP, apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>( PurchaseOrderType.SHOP, apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>(
M18_FETCH_PURCHASE_ORDER_LIST_API, M18_FETCH_PURCHASE_ORDER_LIST_API,
shopPoParams shopPoParams
).block()?.values ?: mutableListOf()
).block()
) )
} catch (e: Exception) { } 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) logger.error(e.message)
} }


// OEM PO // 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( val oemPoParams = M18PurchaseOrderListRequest(
params = null, params = null,
conds = oemPoConds conds = oemPoConds
@@ -103,12 +125,12 @@ open class M18PurchaseOrderService(
PurchaseOrderType.OEM, apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>( PurchaseOrderType.OEM, apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>(
M18_FETCH_PURCHASE_ORDER_LIST_API, M18_FETCH_PURCHASE_ORDER_LIST_API,
oemPoParams oemPoParams
).block()?.values
).block()
) )
} catch (e: Exception) { } 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) logger.error(e.message)
}
} */


return purchaseOrders return purchaseOrders
} }
@@ -126,7 +148,7 @@ open class M18PurchaseOrderService(
purchaseOrderParams purchaseOrderParams
).block() ).block()
} catch (e: Exception) { } catch (e: Exception) {
logger.error("Error on Function - ${e.stackTrace}")
logger.error("(Getting Po Detail) Error on Function - ${e.stackTrace}")
logger.error(e.message) logger.error(e.message)
} }


@@ -150,10 +172,13 @@ open class M18PurchaseOrderService(
// Loop for Purchase Orders (values) // Loop for Purchase Orders (values)
purchaseOrdersWithType.valuesWithType.forEach { purchaseOrderWithType -> purchaseOrdersWithType.valuesWithType.forEach { purchaseOrderWithType ->
val type = purchaseOrderWithType.first 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) val purchaseOrderDetail = getPurchaseOrder(purchaseOrder.id)


var purchaseOrderId: Long? = null //FP-MTMS var purchaseOrderId: Long? = null //FP-MTMS
@@ -162,6 +187,7 @@ open class M18PurchaseOrderService(
// Assume only one PO in the PO (search by PO ID) // Assume only one PO in the PO (search by PO ID)
val mainpo = purchaseOrderDetail?.data?.mainpo?.get(0) val mainpo = purchaseOrderDetail?.data?.mainpo?.get(0)
val pot = purchaseOrderDetail?.data?.pot val pot = purchaseOrderDetail?.data?.pot
val purchaseOrderLineMessage = purchaseOrderDetail?.messages


// purchase_order + m18_data_log table // purchase_order + m18_data_log table
if (mainpo != null) { if (mainpo != null) {
@@ -169,7 +195,6 @@ open class M18PurchaseOrderService(
logger.info("${poRefType}: Finding For Latest M18 Data Log...") logger.info("${poRefType}: Finding For Latest M18 Data Log...")
val latestPurchaseOrderLog = val latestPurchaseOrderLog =
m18DataLogService.findLatestM18DataLog(purchaseOrder.id, poRefType) m18DataLogService.findLatestM18DataLog(purchaseOrder.id, poRefType)
// logger.info("${poRefType}: Latest M18 Data Log ID: ${latestPurchaseOrderLog?.id}")


// Save to m18_data_log table // Save to m18_data_log table
logger.info("${poRefType}: Saving for M18 Data Log...") logger.info("${poRefType}: Saving for M18 Data Log...")
@@ -181,9 +206,9 @@ open class M18PurchaseOrderService(
id = null, id = null,
refType = poRefType, refType = poRefType,
m18Id = purchaseOrder.id, 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 = val saveM18PurchaseOrderLog =
@@ -194,18 +219,18 @@ open class M18PurchaseOrderService(
// Find the purchase_order if exist // Find the purchase_order if exist
logger.info("${poRefType}: Finding exising purchase order...") logger.info("${poRefType}: Finding exising purchase order...")
val existingPurchaseOrder = val existingPurchaseOrder =
latestPurchaseOrderLog?.id?.let { purchaseOrderService.findPurchaseOrderByM18Id(it) }
latestPurchaseOrderLog?.id?.let { purchaseOrderService.findByM18DataLogId(it) }
logger.info("${poRefType}: Exising purchase order ID: ${existingPurchaseOrder?.id}") logger.info("${poRefType}: Exising purchase order ID: ${existingPurchaseOrder?.id}")


// Save to purchase_order table // Save to purchase_order table
logger.info("${poRefType}: Saving purchase order...") logger.info("${poRefType}: Saving purchase order...")
val supplierId = shopService.findByM18Id(mainpo.venId)?.id
val savePurchaseOrderRequest = SavePurchaseOrderRequest( val savePurchaseOrderRequest = SavePurchaseOrderRequest(
id = existingPurchaseOrder?.id, id = existingPurchaseOrder?.id,
code = mainpo.code, 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, completeDate = null,
status = PurchaseOrderStatus.PENDING.value, status = PurchaseOrderStatus.PENDING.value,
type = type.value, type = type.value,
@@ -216,6 +241,16 @@ open class M18PurchaseOrderService(
purchaseOrderService.savePurchaseOrder(savePurchaseOrderRequest) purchaseOrderService.savePurchaseOrder(savePurchaseOrderRequest)
purchaseOrderId = savePurchaseOrderResponse.id 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) successList.add(purchaseOrder.id)
logger.info("${poRefType}: Saved purchase order. ID: ${savePurchaseOrderResponse.id} | M18 ${poRefType} ID: ${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( val errorSaveM18PurchaseOrderLogRequest = SaveM18DataLogRequest(
id = saveM18PurchaseOrderLogRequest.id, 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) m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLogRequest)
@@ -239,15 +271,16 @@ open class M18PurchaseOrderService(
} }


// purchase_order_line + m18_data_log // purchase_order_line + m18_data_log
// TODO: check deleted po line?
if (pot != null) { if (pot != null) {
// Loop for Purchase Order Lines (pot) // Loop for Purchase Order Lines (pot)
pot.forEach { line -> 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...") logger.info("${poLineRefType}: Finding For Latest M18 Data Log...")
val latestPurchaseOrderLineLog = val latestPurchaseOrderLineLog =
m18DataLogService.findLatestM18DataLog(line.id, poLineRefType) 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 // Save to m18_data_log table
logger.info("${poLineRefType}: Saving for M18 Data Log...") logger.info("${poLineRefType}: Saving for M18 Data Log...")
@@ -262,15 +295,15 @@ open class M18PurchaseOrderService(
id = null, id = null,
refType = poLineRefType, refType = poLineRefType,
m18Id = line.id, 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 = val saveM18PurchaseOrderLineLog =
m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLineLogRequest) 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...") logger.info("${poLineRefType}: Finding item...")
val item = itemsService.findByM18Id(line.proId) val item = itemsService.findByM18Id(line.proId)
logger.info("${poLineRefType}: Item ID: ${item?.id} | M18 Item ID: ${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 // Save to purchase_order_line table
logger.info("${poLineRefType}: Saving purchase order line...") logger.info("${poLineRefType}: Saving purchase order line...")
val itemUom = item?.id?.let { itemUomService.findPurchaseUnitByItemId(it) }
val savePurchaseOrderLineRequest = SavePurchaseOrderLineRequest( val savePurchaseOrderLineRequest = SavePurchaseOrderLineRequest(
id = existingPurchaseOrderLine?.id, id = existingPurchaseOrderLine?.id,
itemId = item?.id, itemId = item?.id,
uomId = null,
uomId = itemUom?.uom?.id,
purchaseOrderId = purchaseOrderId, purchaseOrderId = purchaseOrderId,
qty = line.qty, qty = line.qty,
price = line.amt, price = line.amt,
m18CurrencyId = line.curId,
// m18CurrencyId = mainpo.curId,
status = existingPurchaseOrderLine?.status?.value status = existingPurchaseOrderLine?.status?.value
?: PurchaseOrderLineStatus.PENDING.value, ?: PurchaseOrderLineStatus.PENDING.value,
m18DataLogId = saveM18PurchaseOrderLineLog.id, m18DataLogId = saveM18PurchaseOrderLineLog.id,
@@ -300,6 +334,18 @@ open class M18PurchaseOrderService(


val savePurchaseOrderLineResponse = val savePurchaseOrderLineResponse =
purchaseOrderLineService.savePurchaseOrderLine(savePurchaseOrderLineRequest) 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}: Purchase order ID: ${purchaseOrderId} | M18 ID: ${purchaseOrder.id}")
logger.info("${poLineRefType}: Saved purchase order line. ID: ${savePurchaseOrderLineResponse.id} | M18 Line ID: ${line.id}") logger.info("${poLineRefType}: Saved purchase order line. ID: ${savePurchaseOrderLineResponse.id} | M18 Line ID: ${line.id}")
} catch (e: Exception) { } catch (e: Exception) {
@@ -310,11 +356,8 @@ open class M18PurchaseOrderService(


val errorSaveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( val errorSaveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest(
id = saveM18PurchaseOrderLineLog.id, 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) m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLineLogRequest)
@@ -328,9 +371,23 @@ open class M18PurchaseOrderService(
id = null, id = null,
refType = "${poLineRefType}", refType = "${poLineRefType}",
m18Id = purchaseOrder.id, 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) val errorLog = m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLineLogRequest)
@@ -338,15 +395,29 @@ open class M18PurchaseOrderService(
} }
} else { } else {
// mainpo // mainpo
failList.add(purchaseOrder.id)
logger.error("${poRefType}: Saving Failure!") logger.error("${poRefType}: Saving Failure!")
val saveM18DataLogRequest = SaveM18DataLogRequest( val saveM18DataLogRequest = SaveM18DataLogRequest(
id = null, id = null,
refType = "${poRefType}", refType = "${poRefType}",
m18Id = purchaseOrder.id, 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(), 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) val errorLog = m18DataLogService.saveM18DataLog(saveM18DataLogRequest)
@@ -363,14 +434,14 @@ open class M18PurchaseOrderService(


// End of save. Check result // End of save. Check result
logger.info("Total Success (${poRefType}) (${successList.size}): $successList") 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") 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--------------------------------------------") logger.info("--------------------------------------------End - Saving M18 Purchase Order--------------------------------------------")
} }
} }

+ 192
- 0
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<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--------------------------------------------")
}
}

+ 1
- 1
src/main/java/com/ffii/fpsms/m18/service/M18TokenService.kt 查看文件

@@ -15,7 +15,7 @@ open class M18TokenService(
private val m18Config: M18Config private val m18Config: M18Config
) { ) {


// @Bean
@Bean
fun run() { fun run() {
// val params: MutableMap<String, String> = mutableMapOf( // val params: MutableMap<String, String> = mutableMapOf(
// "grant_type" to m18Config.GRANT_TYPE, // "grant_type" to m18Config.GRANT_TYPE,


+ 13
- 7
src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt 查看文件

@@ -1,20 +1,26 @@
package com.ffii.fpsms.m18.utils 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.Instant
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.ZoneId 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")) 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 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" } return numbers.joinToString(delimiter) { "$prefix$it" }
} }
} }

+ 35
- 3
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.M18Config
import com.ffii.fpsms.m18.service.M18MasterDataService import com.ffii.fpsms.m18.service.M18MasterDataService
import com.ffii.fpsms.m18.service.M18PurchaseOrderService 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.Shop
import com.ffii.fpsms.modules.master.entity.ShopRepository import com.ffii.fpsms.modules.master.entity.ShopRepository
import com.ffii.fpsms.modules.master.entity.projections.SearchId import com.ffii.fpsms.modules.master.entity.projections.SearchId
import com.ffii.fpsms.modules.master.enums.ShopType 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 com.ffii.fpsms.modules.master.service.ShopService
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@@ -22,22 +27,36 @@ import org.springframework.web.bind.annotation.RestController
class M18TestController ( class M18TestController (
private val shopRepository: ShopRepository, private val shopRepository: ShopRepository,
private val shopService: ShopService, private val shopService: ShopService,
private val itemsService: ItemsService,
private val m18MasterDataService: M18MasterDataService, private val m18MasterDataService: M18MasterDataService,
private val m18PurchaseOrderService: M18PurchaseOrderService, private val m18PurchaseOrderService: M18PurchaseOrderService,
private val m18Config: M18Config, private val m18Config: M18Config,
private val itemUomService: ItemUomService,
private val m18PurchaseQuotationService: M18PurchaseQuotationService,
) { ) {
var logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) var logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)


@GetMapping("/test1") @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") @GetMapping("/test2")
fun test2(): List<Long>? { 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 --------------------------------------------- /// // --------------------------------------------- Master Data --------------------------------------------- ///
@GetMapping("/product") @GetMapping("/product")
fun m18Products() { fun m18Products() {
@@ -63,10 +82,23 @@ class M18TestController (
m18MasterDataService.saveCurrencies() m18MasterDataService.saveCurrencies()
} }


@GetMapping("/bom")
fun m18Bom() {
logger.info("Access token: ${m18Config.ACCESS_TOKEN}")
m18MasterDataService.saveBoms()
}

// --------------------------------------------- Purchase Order --------------------------------------------- /// // --------------------------------------------- Purchase Order --------------------------------------------- ///
@GetMapping("/po") @GetMapping("/po")
fun m18PO() { fun m18PO() {
logger.info("Access token: ${m18Config.ACCESS_TOKEN}") logger.info("Access token: ${m18Config.ACCESS_TOKEN}")
m18PurchaseOrderService.savePurchaseOrders() m18PurchaseOrderService.savePurchaseOrders()
} }

// --------------------------------------------- Purchase Quotation --------------------------------------------- ///
@GetMapping("/pq")
fun m18PQ() {
logger.info("Access token: ${m18Config.ACCESS_TOKEN}")
m18PurchaseQuotationService.savePurchaseQuotations()
}
} }

+ 0
- 12
src/main/java/com/ffii/fpsms/modules/master/web/models/CurrencyRequest.kt 查看文件

@@ -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?,
)

+ 3
- 3
src/main/resources/application.yml 查看文件

@@ -42,9 +42,9 @@ m18:
supplier-not: supplier-not:
material-po: P06, P07 material-po: P06, P07
beId: beId:
toa: 29
pp: 27
pf: 1
toa: 1
pf: 27
pp: 29
seriesId: seriesId:
pp: 26 pp: 26
pf: 33 pf: 33


+ 9
- 0
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`);
;

+ 46
- 0
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`)
);

Loading…
取消
儲存