Pārlūkot izejas kodu

[M18 API - item + vendor + po] API Function for import M18 item + vendor + po to fpsmsdb

create_edit_user
cyril.tsui pirms 3 mēnešiem
vecāks
revīzija
8aacd3ab9c
11 mainītis faili ar 961 papildinājumiem un 4 dzēšanām
  1. +90
    -4
      src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt
  2. +53
    -0
      src/main/java/com/ffii/fpsms/m18/M18Config.kt
  3. +40
    -0
      src/main/java/com/ffii/fpsms/m18/model/M18MasterDataRequest.kt
  4. +75
    -0
      src/main/java/com/ffii/fpsms/m18/model/M18MasterDataResponse.kt
  5. +14
    -0
      src/main/java/com/ffii/fpsms/m18/model/M18PurchaseOrderRequest.kt
  6. +49
    -0
      src/main/java/com/ffii/fpsms/m18/model/M18PurchaseOrderResponse.kt
  7. +42
    -0
      src/main/java/com/ffii/fpsms/m18/service/M18DataLogService.kt
  8. +268
    -0
      src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt
  9. +268
    -0
      src/main/java/com/ffii/fpsms/m18/service/M18PurchaseOrderService.kt
  10. +20
    -0
      src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt
  11. +42
    -0
      src/main/java/com/ffii/fpsms/m18/web/M18TestController.kt

+ 90
- 4
src/main/java/com/ffii/fpsms/api/service/ApiCallerService.kt Parādīt failu

@@ -1,6 +1,9 @@
package com.ffii.fpsms.api.service

import com.ffii.core.utils.JwtTokenUtil
import com.ffii.fpsms.m18.M18Config
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
@@ -11,28 +14,50 @@ import org.springframework.web.reactive.function.client.WebClient
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.http.HttpStatus
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(
@Value("\${m18.config.base-url}") private val baseUrl: String,
private val m18Config: M18Config
open val m18Config: M18Config
) {
val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)

val webClient: WebClient = WebClient.builder()
.baseUrl(baseUrl)
.defaultHeaders { headers ->
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
headers.set(HttpHeaders.AUTHORIZATION, "Bearer ${m18Config.ACCESS_TOKEN}")
// headers.set(HttpHeaders.AUTHORIZATION, "Bearer ${m18Config.ACCESS_TOKEN}")
headers.set("client_id", m18Config.CLIENT_ID)
}
.filter { request, next ->
// Dynamically fetch the latest ACCESS_TOKEN
val updatedRequest = ClientRequest.from(request)
.header(HttpHeaders.AUTHORIZATION, "Bearer ${m18Config.ACCESS_TOKEN}")
.build()
next.exchange(updatedRequest)
}
.codecs { configurer -> configurer.defaultCodecs().maxInMemorySize(10 * 1024 * 1024) }
.build()

/**
* Performs a GET HTTP request to the specified URL path.
*
* @param urlPath The path to send the GET request to (after /jsf/rfws)
* @param params Optional query parameters to include in the request
* @param customHeaders Optional custom headers to include in the request. The default header includes CONTENT_TYPE, AUTHORIZATION, client_id
* @return A Mono that emits the response body converted to type T
*/
inline fun <reified T : Any> get(
urlPath: String,
params: MultiValueMap<String, String>,
customHeaders: Map<String, String>?
): Mono<T> {

println("ACCESS TOKEN: ${m18Config.ACCESS_TOKEN}")
return webClient.get()
.uri { uriBuilder ->
uriBuilder
@@ -49,8 +74,30 @@ open class ApiCallerService(
}
.retrieve()
.bodyToMono(T::class.java)
.doOnError { error ->
println("Error occurred: ${error.message}")
}
.onErrorResume(WebClientResponseException::class.java) { error ->
logger.error("WebClientResponseException")
logger.error("Error Status: ${error.statusCode} - ${error.statusText}")
logger.error("Error Message: ${error.message}")
Mono.error(error)
}
.onErrorResume { error ->
logger.error("Exception")
logger.error("Error Message: ${error.message}")
Mono.error(error)
}
}

/**
* Performs a GET HTTP request to the specified URL path.
*
* @param urlPath The path to send the GET request to (after /jsf/rfws)
* @param params Optional query parameters to include in the request
* @param customHeaders Optional custom headers to include in the request. The default header includes CONTENT_TYPE, AUTHORIZATION, client_id
* @return A Mono that emits the response body converted to type T
*/
inline fun <reified T : Any> get(
urlPath: String,
params: Map<String, Any>?,
@@ -72,7 +119,29 @@ open class ApiCallerService(
return get<T>(urlPath, queryParams, customHeaders)
}

// T: Response, U: Request
/**
* Performs a GET HTTP request to the specified URL path.
*
* @param urlPath The path to send the GET request to (after /jsf/rfws)
* @param params Optional query parameters to include in the request
* @return A Mono that emits the response body converted to type T
*/
inline fun <reified T : Any> get(
urlPath: String,
params: Map<String, Any>?
): Mono<T> {
return get<T>(urlPath, params, null)
}

/**
* Performs a GET HTTP request to the specified URL path.
* T: Response, U: Request
*
* @param urlPath The path to send the GET request to (after /jsf/rfws)
* @param params Optional query parameters to include in the request
* @param customHeaders Optional custom headers to include in the request. The default header includes CONTENT_TYPE, AUTHORIZATION, client_id
* @return A Mono that emits the response body converted to type T
*/
inline fun <reified T : Any, reified U : Any> get(
urlPath: String,
params: U?,
@@ -95,4 +164,21 @@ open class ApiCallerService(

return get<T>(urlPath, queryParams, customHeaders)
}

/**
* Performs a GET HTTP request to the specified URL path.
* T: Response, U: Request
*
* @param urlPath The path to send the GET request to (after /jsf/rfws)
* @param params Optional query parameters to include in the request
* @return A Mono that emits the response body converted to type T
*/
inline fun <reified T : Any, reified U : Any> get(
urlPath: String,
params: U?,
): Mono<T> {

return get<T, U>(urlPath, params, null)
}

}

+ 53
- 0
src/main/java/com/ffii/fpsms/m18/M18Config.kt Parādīt failu

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

import org.springframework.beans.factory.annotation.Value
import org.springframework.cloud.context.config.annotation.RefreshScope
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration


@Configuration
open class M18Config {

// Account
@Value("\${m18.config.grant-type}")
lateinit var GRANT_TYPE: String;

@@ -22,5 +25,55 @@ open class M18Config {
@Value("\${m18.config.password}")
lateinit var PASSWORD: String;

// Series
@Value("\${m18.config.seriesId.pp}")
var SERIESID_PP: Long? = null;

@Value("\${m18.config.seriesId.pf}")
var SERIESID_PF: Long? = null;

@Value("\${m18.config.seriesId.sc}")
var SERIESID_SC: Long? = null;

@Value("\${m18.config.seriesId.se}")
var SERIESID_SE: Long? = null;

@Value("\${m18.config.seriesId.sf}")
var SERIESID_SF: Long? = null;

@Value("\${m18.config.seriesId.sr}")
var SERIESID_SR: Long? = null;
// BE
@Value("\${m18.config.beId.pp}")
var BEID_PP: Long? = null;

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

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

// Fetch
var ACCESS_TOKEN: String? = null;

/**
* Condition Detail
* Conds Format:
* Id=lessThan=5=and=id=largerOrEqual=3=or=(name=contains =ss=or=name=contains=bb)
* Which means:
* Id<5 and id >=3 or (name like ‘%ss%’ or name like ‘%bb%’)
* **Please use these formats to write the conds: **
* ("equal", "="),
* ("unequal", "<>"),
* ("largerThan", ">"),
* ("lessThan", "<"),
* ("largerOrEqual", ">="),
* ("lessOrEqual", "<="),
* ("contains", "like"),
* ("doseNotContain", "notlike"),
* ("in", "in"),
* ("notIn", "notin"),
* ("startWith", "like"),
* ("endWith", "like");
*/
}

+ 40
- 0
src/main/java/com/ffii/fpsms/m18/model/M18MasterDataRequest.kt Parādīt failu

@@ -0,0 +1,40 @@
package com.ffii.fpsms.m18.model

/** Product / Material Request */
data class M18ItemRequest (
val id: Long,
val params: String? = null,
)

/** Product / Material List Request */
data class M18ItemListRequest (
val stSearch: String = "pro",
val params: String? = null,
val conds: String? = null,
)

/** Vendor Request */
data class M18VendorRequest (
val id: Long,
val params: String? = null,
)

/** Vendor List Request */
data class M18VendorListRequest (
val stSearch: String = "ven",
val params: String? = null,
val conds: String? = null,
)

/** Customer Request */
data class M18CustomerRequest (
val id: Long,
val params: String? = null,
)

/** Customer List Request */
data class M18CustomerListRequest (
val stSearch: String = "cus",
val params: String? = null,
val conds: String? = null,
)

+ 75
- 0
src/main/java/com/ffii/fpsms/m18/model/M18MasterDataResponse.kt Parādīt failu

@@ -0,0 +1,75 @@
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?,
)

/** Product / Material Response */
data class M18ItemResponse (
val data: M18ItemData?,
val messages: List<M18ErrorMessages>?
)

data class M18ItemData (
val pro: List<M18ItemPro>?
)

data class M18ItemPro (
val id: Long,
val code: String,
val desc: String,
val unitId: Long,
val seriesId: Long,
val lastModifyDate: Long,
)

/** Product / Material List Response */
data class M18ItemListResponse (
val values: List<M18ItemListValue>?,
)

data class M18ItemListValue (
val id: Long,
val lastModifyDate: String?,
)

/** Vendor Response */
data class M18VendorResponse (
val data: M18VendorData?,
val messages: List<M18ErrorMessages>?
)

data class M18VendorData (
val ven: List<M18VendorVen>?
)

data class M18VendorVen (
val id: Long,
val code: String,
/** name */
val desc: String,
val `desc_zh-TW`: String,
/** contactNo */
val tel: String,
val email: String,
val ad1: String,
val ad2: String,
val ad3: String,
val ad4: String,
val lastModifyDate: Long,
)

/** Vendor List Response */
data class M18VendorListResponse (
val values: List<M18VendorListValue>?,
)

data class M18VendorListValue (
val id: Long,
val lastModifyDate: String?,
)

+ 14
- 0
src/main/java/com/ffii/fpsms/m18/model/M18PurchaseOrderRequest.kt Parādīt failu

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

data class M18PurchaseOrderRequest(
val menuCode: String = "po",
val id: Long?,
val params: String? = null,
val conds: String? = null,
)

data class M18PurchaseOrderListRequest(
val stSearch: String = "po",
val params: String? = null,
val conds: String? = null,
)

+ 49
- 0
src/main/java/com/ffii/fpsms/m18/model/M18PurchaseOrderResponse.kt Parādīt failu

@@ -0,0 +1,49 @@
package com.ffii.fpsms.m18.model

import java.math.BigDecimal
import java.time.Instant
import java.time.LocalDateTime

/** Purchase Order Response */
data class M18PurchaseOrderResponse (
val data: M18PurchaseOrderData
)

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

data class M18PurchaseOrderMainPo (
val id: Long,
val code: String,
/** Supplier Id */
val venId: Long,
/** ETA */
val dDate: Long,
/** Order Date */
val tDate: Long,
val lastModifyDate: Long
)

data class M18PurchaseOrderPot (
val id: Long,
val hId: Long,
val code: String,
val desc: String,
val unitId: Long,
val seriesId: Long,
val qty: BigDecimal,
val amt: BigDecimal,
)

/** Purchase Order List Response */
data class M18PurchaseOrderListResponse (
val values: List<M18PurchaseOrderListValue>
)

data class M18PurchaseOrderListValue (
val id: Long,
val code: String,
val lastModifyDate: String,
)

+ 42
- 0
src/main/java/com/ffii/fpsms/m18/service/M18DataLogService.kt Parādīt failu

@@ -0,0 +1,42 @@
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.model.M18DataLogResponse
import com.ffii.fpsms.m18.model.SaveM18DataLogRequest
import org.springframework.stereotype.Service
import kotlin.jvm.optionals.getOrDefault

@Service
class M18DataLogService(
val m18DataLogRepository: M18DataLogRepository
) {
fun findLatestM18DataLog(m18Id: Long, refType: String): M18DataLog? {
return m18DataLogRepository.findFirstByM18IdAndRefTypeAndDeletedIsFalseOrderByM18LastModifyDateDesc(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()

m18DataLog.apply {
refType = request.refType
m18Id = request.m18Id
m18LastModifyDate = request.m18LastModifyDate
dataLog = request.dataLog
status = request.status
}

val response = m18DataLogRepository.saveAndFlush(m18DataLog).let { dataLog ->
M18DataLogResponse(
id = dataLog.id,
refType = dataLog.refType,
m18Id = dataLog.m18Id,
status = dataLog.status,
)
}

return response
}
}

+ 268
- 0
src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt Parādīt failu

@@ -0,0 +1,268 @@
package com.ffii.fpsms.m18.service

import com.ffii.core.utils.JwtTokenUtil
import com.ffii.fpsms.api.service.ApiCallerService
import com.ffii.fpsms.m18.M18Config
import com.ffii.fpsms.m18.model.*
import com.ffii.fpsms.m18.utils.CommonUtils
import com.ffii.fpsms.modules.master.enums.ShopType
import com.ffii.fpsms.modules.master.service.ItemsService
import com.ffii.fpsms.modules.master.service.ShopService
import com.ffii.fpsms.modules.master.web.models.ItemType
import com.ffii.fpsms.modules.master.web.models.NewItemRequest
import com.ffii.fpsms.modules.master.web.models.SaveShopRequest
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.time.LocalDate
import java.time.format.DateTimeFormatter

@Service
open class M18MasterDataService(
val m18Config: M18Config,
val apiCallerService: ApiCallerService,
val itemsService: ItemsService,
val shopService: ShopService,
) {

val commonUtils = CommonUtils()
val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)

// Everyday update the master data
val lastModifyDate = LocalDate.now().minusDays(1)
val lastModifyDateConds = "lastModifyDate=largerThan=$lastModifyDate"
val seriesIdList =
listOf(m18Config.SERIESID_SC, m18Config.SERIESID_SE, m18Config.SERIESID_SF, m18Config.SERIESID_SR)
val seriesIdConds = "(" + commonUtils.ListToString(seriesIdList.filterNotNull(), "seriesId=unequal=", "=or=") + ")"
val beIdList = listOf(m18Config.BEID_PF, m18Config.BEID_PP, m18Config.BEID_TOA)
val beIdConds = "(" + commonUtils.ListToString(beIdList.filterNotNull(), "beId=equal=", "=or=") + ")"

// val commonConds =seriesIdConds + beIdConds
// "(beId=equal=${m18Config.BEID_PF}=or=beId=equal=${m18Config.BEID_PP}=or=beId=equal=${m18Config.BEID_TOA})"
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")

// M18 API
val M18_LOAD_ITEM_API = "/root/api/read/pro"
val M18_FETCH_ITEM_LIST_API = "/search/search"
val M18_LOAD_VENDOR_API = "/root/api/read/ven"
val M18_FETCH_VENDOR_LIST_API = "/search/search"

// --------------------------------------------- Item --------------------------------------------- ///
open fun getItems(): M18ItemListResponse? {
// seems no beId
val itemsParams = M18ItemListRequest(
params = null,
conds=seriesIdConds
// conds=commonConds
// conds = "lastModifyDate=largerThan=$lastModifyDate"
)

val items = apiCallerService.get<M18ItemListResponse, M18ItemListRequest>(
M18_FETCH_ITEM_LIST_API,
itemsParams
).block()

return items
}

open fun getItem(id: Long): M18ItemResponse? {
logger.info("M18 Item ID: $id")

val itemParams = M18ItemRequest(
id = id,
params = null,
)

val item = apiCallerService.get<M18ItemResponse, M18ItemRequest>(
M18_LOAD_ITEM_API,
itemParams
).block()

return item
}

open fun saveItems() {

val items = getItems()
val exampleItems = listOf<Long>(10946L, 3825L)

val successList = mutableListOf<Long>()
val failList = mutableListOf<Long>()

if (items?.values != null) {
items.values.forEach { item ->
// if (item.id in exampleItems) {
try {
val itemDetail = getItem(item.id)
if (itemDetail != null && itemDetail.data?.pro != null) {
val pro = itemDetail.data.pro[0]

val saveItemRequest = NewItemRequest(
code = pro.code,
name = pro.desc,
// type = if (pro.seriesId == m18Config.SERIESID_PF) ItemType.MATERIAL
// else ItemType.PRODUCT,
type = ItemType.MATERIAL,
id = null,
description = pro.desc,
remarks = null,
shelfLife = null,
countryOfOrigin = null,
maxQty = null,
m18Id = item.id,
m18LastModifyDate = commonUtils.InstantToLocalDateTime(pro.lastModifyDate)
)

itemsService.saveItem(saveItemRequest)
successList.add(item.id)
logger.info("Success Count ${successList.size}: ${item.id} | ${pro.code} | ${pro.desc}")
} else {
failList.add(item.id)
logger.error("Fail Message: ${itemDetail?.messages?.get(0)?.msgDetail}")
logger.error("Fail Count ${failList.size}: Item ID ${item.id} Not Found")
}
} catch (e: Exception) {
failList.add(item.id)
logger.error("M18 Item Data: ${e.message}")
logger.error("Fail Count ${failList.size}: Item ID ${item.id} Not Found")
}
// val itemParams = M18ItemRequest(
// id = item.id,
// params = null
// )

// apiCallerService.get<M18ItemResponse, M18ItemRequest>(
// M18_LOAD_ITEM_API,
// itemParams
// ).subscribe(
// { response ->
// val pro = response.data.pro[0]
//// when (pro.seriesId) {
//// m18Config.SERIESID_PF, m18Config.SERIESID_PP -> {
// val saveItemRequest = NewItemRequest(
// code = pro.code,
// name = pro.desc,
// type = if (pro.seriesId == m18Config.SERIESID_PF) ItemType.MATERIAL
// else ItemType.PRODUCT,
// id = null,
// description = null,
// remarks = null,
// shelfLife = null,
// countryOfOrigin = null,
// maxQty = null,
// m18Id = pro.id
// )
//
// itemsService.saveItem(saveItemRequest)
//// }
//// }
//
// logger.info("Count ${++count}: ${pro.id} | ${pro.code} | ${pro.desc}")
// },
// { error -> logger.error("WebClient Error: ${error.message}") }
// )
// }
}
} else {
logger.error("Items List is null. May occur errors.")
}

logger.info("Total Success (${successList.size}): $successList")

if (failList.size > 0) {
logger.error("Total Fail (${failList.size}): $failList")
}
}

// --------------------------------------------- Vendor --------------------------------------------- ///
open fun getVendors(): M18VendorListResponse? {
val vendorsParams = M18VendorListRequest(
params = null,
conds = beIdConds
// conds = "lastModifyDate=largerThan=$lastModifyDate"
)

val vendors = apiCallerService.get<M18VendorListResponse, M18VendorListRequest>(
M18_FETCH_VENDOR_LIST_API,
vendorsParams
).block()

return vendors
}

open fun getVendor(id: Long): M18VendorResponse? {
logger.info("M18 Vendor ID: $id")

val vendorParams = M18VendorRequest(
id = id,
params = null,
)

val vendor = apiCallerService.get<M18VendorResponse, M18VendorRequest>(
M18_LOAD_VENDOR_API,
vendorParams
).block()

return vendor
}

open fun saveVendors() {
val vendors = getVendors()
val exampleVendors = listOf<Long>(191L)

val successList = mutableListOf<Long>()
val failList = mutableListOf<Long>()

if (vendors?.values != null) {
vendors.values.forEach { vendor ->
// if (vendor.id in exampleVendors) {
try {
val vendorDetail = getVendor(vendor.id)

if (vendorDetail != null && vendorDetail.data?.ven != null) {
val ven = vendorDetail.data.ven[0]

val saveShopRequest = SaveShopRequest(
id = null,
code = ven.code,
name = ven.desc.ifEmpty { ven.`desc_zh-TW` },
brNo = null,
contactNo = ven.tel,
contactEmail = ven.email,
contactName = null,
addr1 = ven.ad1,
addr2 = ven.ad2,
addr3 = ven.ad3,
addr4 = ven.ad4,
district = null,
type = ShopType.SUPPLIER.value,
m18Id = vendor.id,
m18LastModifyDate = commonUtils.InstantToLocalDateTime(ven.lastModifyDate)
)

shopService.saveShop(saveShopRequest)
successList.add(vendor.id)
logger.info("Success Count ${successList.size}: ${vendor.id} | ${ven.code} | ${ven.desc}")
} else {
failList.add(vendor.id)
logger.error("Fail Message: ${vendorDetail?.messages?.get(0)?.msgDetail}")
logger.error("Fail Count ${failList.size}: Vendor ID ${vendor.id} Not Found")
}
} catch (e: Exception) {
failList.add(vendor.id)
logger.error("M18 Vendor Data: ${e.message}")
logger.error("Fail Count ${failList.size}: Vendor ID ${vendor.id} Not Found")
}
// }
}
} else {
logger.error("Items List is null. May occur errors.")
}

logger.info("Total Success (${successList.size}): $successList")

if (failList.size > 0) {
logger.error("Total Fail (${failList.size}): $failList")
}
}
}

+ 268
- 0
src/main/java/com/ffii/fpsms/m18/service/M18PurchaseOrderService.kt Parādīt failu

@@ -0,0 +1,268 @@
package com.ffii.fpsms.m18.service

import com.ffii.core.utils.JwtTokenUtil
import com.ffii.fpsms.api.service.ApiCallerService
import com.ffii.fpsms.m18.M18Config
import com.ffii.fpsms.m18.model.*
import com.ffii.fpsms.m18.utils.CommonUtils
import com.ffii.fpsms.modules.master.service.ItemsService
import com.ffii.fpsms.modules.master.service.ShopService
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus
import com.ffii.fpsms.modules.purchaseOrder.service.PurchaseOrderLineService
import com.ffii.fpsms.modules.purchaseOrder.service.PurchaseOrderService
import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderLineRequest
import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderRequest
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.time.LocalDate
import java.time.LocalDateTime
import kotlin.reflect.full.memberProperties

@Service
open class M18PurchaseOrderService(
val m18Config: M18Config,
val apiCallerService: ApiCallerService,
val m18DataLogService: M18DataLogService,
val purchaseOrderService: PurchaseOrderService,
val purchaseOrderLineService: PurchaseOrderLineService,
val itemsService: ItemsService,
val shopService: ShopService,
) {
val dateTimeConverter = CommonUtils()
val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)

val lastModifyDate = LocalDate.now().minusDays(1)
val commonConds="(beId=equal=${m18Config.BEID_PF}=or=beId=equal=${m18Config.BEID_PP}=or=beId=equal=${m18Config.BEID_TOA})=and=lastModifyDate=largerOrEqual=${lastModifyDate}"

// M18 API
val M18_LOAD_PURCHASE_ORDER_API = "/root/api/read/po"
val M18_FETCH_PURCHASE_ORDER_LIST_API = "/search/search"

open fun getPurchaseOrders(): M18PurchaseOrderListResponse? {
val purchaseOrdersParams = M18PurchaseOrderListRequest(
params = null,
conds = commonConds
)
var purchaseOrders: M18PurchaseOrderListResponse? = null

try {
purchaseOrders = apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>(
M18_FETCH_PURCHASE_ORDER_LIST_API,
purchaseOrdersParams
).block()
} catch (e: Exception) {
logger.error("Error on Function - ${e.stackTrace}")
logger.error(e.message)
}

return purchaseOrders
}

open fun getPurchaseOrder(id: Long): M18PurchaseOrderResponse? {
val purchaseOrderParams = M18PurchaseOrderRequest(
id = id
)

var purchaseOrder: M18PurchaseOrderResponse? = null

try {
purchaseOrder = apiCallerService.get<M18PurchaseOrderResponse, M18PurchaseOrderRequest>(
M18_LOAD_PURCHASE_ORDER_API,
purchaseOrderParams
).block()
} catch (e: Exception) {
logger.error("Error on Function - ${e.stackTrace}")
logger.error(e.message)
}

return purchaseOrder
}

open fun savePurchaseOrders() {
val purchaseOrders = getPurchaseOrders()
val examplePurchaseOrders = listOf<Long>(4764034L)

val successList = mutableListOf<Long>()
val successDetailList = mutableListOf<Long>()
val failList = mutableListOf<Long>()
val failDetailList = mutableListOf<Long>()

if (purchaseOrders != null) {
// Loop for Purchase Orders (values)
purchaseOrders.values.forEach { purchaseOrder ->
val purchaseOrderDetail = getPurchaseOrder(purchaseOrder.id)

var purchaseOrderId: Long? = null //FP-MTMS

// Process for Purchase Order (mainPo)
// Assume only one PO in the PO (search by PO ID)
val mainPo = purchaseOrderDetail?.data?.mainPo?.get(0)
val pot = purchaseOrderDetail?.data?.pot

// purchase_order + m18_data_log table
if (mainPo != null) {
val poRefType = "Purchase Order"

// Find the latest m18 data log by m18 id & type
val latestM18DataLog = m18DataLogService.findLatestM18DataLog(purchaseOrder.id, poRefType)

// Save to m18_data_log table
val mainPoJson =
mainPo::class.memberProperties.associate { prop -> prop.name to prop.getter.call(mainPo) }
.toMutableMap()

val saveM18PurchaseOrderLogRequest = SaveM18DataLogRequest(
id = null,
refType = poRefType,
m18Id = purchaseOrder.id,
m18LastModifyDate = dateTimeConverter.InstantToLocalDateTime(mainPo.lastModifyDate),
dataLog = mainPoJson,
status = true
)

val saveM18PurchaseOrderLog = m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLogRequest)

try {
// Find the purchase_order if exist
val existingPurchaseOrder = latestM18DataLog?.id?.let { purchaseOrderService.findPurchaseOrderByM18Id(it) }

// Save to purchase_order table
val supplierId = shopService.findByM18Id(mainPo.venId)?.id
val savePurchaseOrderRequest = SavePurchaseOrderRequest(
id = existingPurchaseOrder?.id,
code = mainPo.code,
supplierId = supplierId,
orderDate = dateTimeConverter.InstantToLocalDateTime(mainPo.tDate),
estimatedArrivalDate = dateTimeConverter.InstantToLocalDateTime(mainPo.dDate),
completeDate = null,
status = PurchaseOrderStatus.PENDING.value,
m18DataLogId = saveM18PurchaseOrderLog.id,
)

val savePurchaseOrderResponse = purchaseOrderService.savePurchaseOrder(savePurchaseOrderRequest)
purchaseOrderId = savePurchaseOrderResponse.id

successList.add(purchaseOrder.id)
} catch (e: Exception) {
failList.add(purchaseOrder.id)
logger.error("Error on Function - ${e.stackTrace} | Type: Purchase Order | M18 ID: ${purchaseOrder.id} | Different? ${mainPo.id}")
logger.error(e.message)

val errorSaveM18PurchaseOrderLogRequest = SaveM18DataLogRequest(
id = saveM18PurchaseOrderLogRequest.id,
refType = "Purchase Order",
m18Id = purchaseOrder.id,
m18LastModifyDate = dateTimeConverter.InstantToLocalDateTime(mainPo.lastModifyDate),
dataLog = mainPoJson,
status = false
)

m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLogRequest)
}

// purchase_order_line + m18_data_log
if (pot != null) {
// Loop for Purchase Order Lines (pot)
pot.forEach { line ->
val poLineRefType = "Purchase Order Line"

// Find the latest m18 data log by m18 id & type
val latestM18DataLog = m18DataLogService.findLatestM18DataLog(line.id, poLineRefType)

// Save to m18_data_log table
val lineJson =
line::class.memberProperties.associate { prop -> prop.name to prop.getter.call(line) }
.toMutableMap()
val saveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest(
id = null,
refType = poLineRefType,
m18Id = line.id,
m18LastModifyDate = dateTimeConverter.InstantToLocalDateTime(mainPo.lastModifyDate),
dataLog = lineJson,
status = true
)

val saveM18PurchaseOrderLineLog = m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLineLogRequest)

val item = itemsService.findByM18Id(line.id)
logger.info("Item ID: ${item?.id}")

try {
// Find the purchase_order_line if exist
val existingPurchaseOrderLine = latestM18DataLog?.id?.let { purchaseOrderLineService.findPurchaseOrderLineByM18Id(it) }

// Save to purchase_order_line table
val savePurchaseOrderLineRequest = SavePurchaseOrderLineRequest(
id = existingPurchaseOrderLine?.id,
itemId = item?.id,
uomId = null,
purchaseOrderId = purchaseOrderId,
qty = line.qty,
price = line.amt,
priceUnit = null,
status = existingPurchaseOrderLine?.status?.value ?: PurchaseOrderLineStatus.PENDING.value,
m18DataLogId = saveM18PurchaseOrderLineLog.id,
)

purchaseOrderLineService.savePurchaseOrderLine(savePurchaseOrderLineRequest)
} catch (e: Exception) {
failDetailList.add(line.id)
logger.error("Error on Function - ${e.stackTrace} | Type: Purchase Order Line | M18 ID: ${line.id}")
logger.error(e.message)

val errorSaveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest(
id = saveM18PurchaseOrderLineLog.id,
refType = "Purchase Order",
m18Id = line.id,
m18LastModifyDate = dateTimeConverter.InstantToLocalDateTime(mainPo.lastModifyDate),
dataLog = lineJson,
status = false
)

m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLineLogRequest)
}
}
} else {
val saveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest(
id = null,
refType = "Purchase Order Line",
m18Id = purchaseOrder.id,
m18LastModifyDate = dateTimeConverter.InstantToLocalDateTime(mainPo.lastModifyDate),
dataLog = mutableMapOf(Pair("Error Message", "Purchase Order Line is null")),
status = false
)

m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLineLogRequest)
}
} else {
val saveM18DataLogRequest = SaveM18DataLogRequest(
id = null,
refType = "Purchase Order",
m18Id = purchaseOrder.id,
// m18LastModifyDate = if(mainPo?.lastModifyDate != null) dateTimeConverter.InstantToLocalDateTime(mainPo.lastModifyDate) else LocalDateTime.now(),
m18LastModifyDate = LocalDateTime.now(),
dataLog = mutableMapOf(Pair("Error Message", "Purchase Order is null")),
status = false
)

m18DataLogService.saveM18DataLog(saveM18DataLogRequest)
}
}
} else {
logger.error("Purchase Order List is null. May occur errors.")
}

// End of save. Check result
logger.info("Total Success (Purchase Order) (${successList.size}): $successList")
if (failList.size > 0) {
logger.error("Total Fail (Purchase Order) (${failList.size}): $failList")
}

logger.info("Total Success (Purchase Order Line) (${successDetailList.size}): $successDetailList")
if (failDetailList.size > 0) {
logger.error("Total Fail (Purchase Order Line) (${failDetailList.size}): $failDetailList")
}
}
}

+ 20
- 0
src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt Parādīt failu

@@ -0,0 +1,20 @@
package com.ffii.fpsms.m18.utils

import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId

open class CommonUtils() {
open fun InstantToLocalDateTime(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 {
return numbers.joinToString(delimiter) { "$prefix$it" }
}
}

+ 42
- 0
src/main/java/com/ffii/fpsms/m18/web/M18TestController.kt Parādīt failu

@@ -0,0 +1,42 @@
package com.ffii.fpsms.m18.web

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 org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/m18")
class M18TestController (
private val m18MasterDataService: M18MasterDataService,
private val m18PurchaseOrderService: M18PurchaseOrderService,
private val m18Config: M18Config,
) {
var logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)

// --------------------------------------------- Master Data --------------------------------------------- ///
@GetMapping("/item")
fun m18Items() {
logger.info("Access token: ${m18Config.ACCESS_TOKEN}")
m18MasterDataService.saveItems()
}

@GetMapping("/vendor")
fun m18Vendor() {
logger.info("Access token: ${m18Config.ACCESS_TOKEN}")
m18MasterDataService.saveVendors()
}

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

Notiek ielāde…
Atcelt
Saglabāt