@@ -30,6 +30,8 @@ dependencies { | |||
implementation 'org.liquibase:liquibase-core' | |||
implementation 'com.google.code.gson:gson:2.8.5' | |||
implementation group: 'org.springframework.cloud', name: 'spring-cloud-context', version: '4.2.1' | |||
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0' | |||
implementation group: 'org.apache.poi', name: 'poi', version: '5.2.3' | |||
implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '5.2.3' | |||
@@ -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) | |||
} | |||
} |
@@ -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"); | |||
*/ | |||
} |
@@ -1,4 +1,4 @@ | |||
package com.ffii.fpsms.modules.stock.entity | |||
package com.ffii.fpsms.m18.entity | |||
import com.ffii.core.entity.BaseEntity | |||
import jakarta.persistence.Column | |||
@@ -8,26 +8,30 @@ import jakarta.validation.constraints.NotNull | |||
import jakarta.validation.constraints.Size | |||
import org.hibernate.annotations.JdbcTypeCode | |||
import org.hibernate.type.SqlTypes | |||
import java.time.LocalDateTime | |||
@Entity | |||
@Table(name = "m18_data_log") | |||
open class M18DataLog : BaseEntity<Long>() { | |||
@Size(max = 10) | |||
@Size(max = 1000) | |||
@NotNull | |||
@Column(name = "refType", nullable = false, length = 10) | |||
@Column(name = "refType", nullable = false, length = 1000) | |||
open var refType: String? = null | |||
@NotNull | |||
@Column(name = "m18Id", nullable = false) | |||
open var m18Id: Int? = null | |||
open var m18Id: Long? = null | |||
@NotNull | |||
@JdbcTypeCode(SqlTypes.JSON) | |||
@Column(name = "dataLog", nullable = false) | |||
open var dataLog: MutableMap<String, Any>? = null | |||
open var dataLog: MutableMap<String, Any?>? = null | |||
@Size(max = 5) | |||
@NotNull | |||
@Column(name = "status", nullable = false, length = 5) | |||
open var status: String? = null | |||
@Column(name = "status", nullable = false) | |||
open var status: Boolean? = null | |||
@NotNull | |||
@Column(name = "m18LastModifyDate", nullable = false) | |||
open var m18LastModifyDate: LocalDateTime? = null | |||
} |
@@ -1,8 +1,9 @@ | |||
package com.ffii.fpsms.modules.stock.entity | |||
package com.ffii.fpsms.m18.entity | |||
import com.ffii.core.support.AbstractRepository | |||
import org.springframework.stereotype.Repository | |||
@Repository | |||
interface M18DataLogRepository : AbstractRepository<M18DataLog, Long> { | |||
fun findFirstByM18IdAndRefTypeAndDeletedIsFalseOrderByM18LastModifyDateDesc(m18Id: Long, refType: String): M18DataLog? | |||
} |
@@ -0,0 +1,12 @@ | |||
package com.ffii.fpsms.m18.model | |||
import java.time.LocalDateTime | |||
data class SaveM18DataLogRequest ( | |||
val id: Long?, | |||
val refType: String?, | |||
val m18Id: Long?, | |||
val m18LastModifyDate: LocalDateTime?, | |||
val dataLog: MutableMap<String, Any?>?, | |||
val status: Boolean? = true, | |||
) |
@@ -0,0 +1,8 @@ | |||
package com.ffii.fpsms.m18.model | |||
data class M18DataLogResponse ( | |||
val id: Long?, | |||
val refType: String?, | |||
val m18Id: Long?, | |||
val status: Boolean?, | |||
) |
@@ -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, | |||
) |
@@ -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?, | |||
) |
@@ -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, | |||
) |
@@ -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, | |||
) |
@@ -1,4 +1,4 @@ | |||
package com.ffii.fpsms.m18.modals | |||
package com.ffii.fpsms.m18.model | |||
data class M18TokenRequest( | |||
val grant_type: String, |
@@ -1,4 +1,4 @@ | |||
package com.ffii.fpsms.m18.modals | |||
package com.ffii.fpsms.m18.model | |||
data class M18TokenResponse( | |||
val access_token: String, |
@@ -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 | |||
} | |||
} |
@@ -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") | |||
} | |||
} | |||
} |
@@ -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") | |||
} | |||
} | |||
} |
@@ -2,11 +2,10 @@ package com.ffii.fpsms.m18.service | |||
import com.ffii.fpsms.api.service.ApiCallerService | |||
import com.ffii.fpsms.m18.M18Config | |||
import com.ffii.fpsms.m18.modals.M18TokenRequest | |||
import com.ffii.fpsms.m18.modals.M18TokenResponse | |||
import com.ffii.fpsms.m18.model.M18TokenRequest | |||
import com.ffii.fpsms.m18.model.M18TokenResponse | |||
import jakarta.annotation.PostConstruct | |||
import org.springframework.context.annotation.Bean | |||
import org.springframework.stereotype.Component | |||
import org.springframework.stereotype.Service | |||
@@ -16,7 +15,7 @@ open class M18TokenService( | |||
private val m18Config: M18Config | |||
) { | |||
// @Bean | |||
@Bean | |||
fun run() { | |||
// val params: MutableMap<String, String> = mutableMapOf( | |||
// "grant_type" to m18Config.GRANT_TYPE, | |||
@@ -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" } | |||
} | |||
} |
@@ -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() | |||
} | |||
} |
@@ -4,6 +4,7 @@ import com.ffii.core.entity.BaseEntity | |||
import com.ffii.fpsms.modules.master.web.models.ItemType | |||
import jakarta.persistence.* | |||
import jakarta.validation.constraints.NotNull | |||
import java.time.LocalDateTime | |||
@Entity | |||
@Table(name = "items") | |||
@@ -37,4 +38,7 @@ open class Items : BaseEntity<Long>() { | |||
@Column(name = "m18Id") | |||
open var m18Id: Long? = null | |||
@Column(name = "m18LastModifyDate") | |||
open var m18LastModifyDate: LocalDateTime? = null | |||
} |
@@ -7,6 +7,10 @@ import org.springframework.stereotype.Repository | |||
@Repository | |||
interface ItemsRepository : AbstractRepository<Items, Long> { | |||
fun findAllByDeletedFalse(): List<Items>; | |||
fun findByIdAndDeletedFalse(id: Long): Items; | |||
fun findByCodeAndTypeAndDeletedFalse(code: String, type: String): Items?; | |||
fun findByM18IdAndDeletedIsFalse(m18Id: Long): Items?; | |||
} |
@@ -1,63 +1,75 @@ | |||
package com.ffii.fpsms.modules.master.entity | |||
import com.ffii.core.entity.BaseEntity | |||
import com.ffii.fpsms.modules.master.enums.ShopType | |||
import com.ffii.fpsms.modules.master.enums.ShopTypeConverter | |||
import jakarta.persistence.Column | |||
import jakarta.persistence.Convert | |||
import jakarta.persistence.Entity | |||
import jakarta.persistence.Table | |||
import jakarta.validation.constraints.NotNull | |||
import jakarta.validation.constraints.Size | |||
import java.time.LocalDateTime | |||
@Entity | |||
@Table(name = "shop") | |||
open class Shop : BaseEntity<Long>() { | |||
@Size(max = 30) | |||
@Size(max = 50) | |||
@NotNull | |||
@Column(name = "code", nullable = false, length = 30) | |||
@Column(name = "code", nullable = false, length = 50) | |||
open var code: String? = null | |||
@Size(max = 30) | |||
@Size(max = 300) | |||
@NotNull | |||
@Column(name = "name", nullable = false, length = 30) | |||
@Column(name = "name", nullable = false, length = 300) | |||
open var name: String? = null | |||
@Size(max = 30) | |||
@Column(name = "brNo", length = 30) | |||
@Size(max = 50) | |||
@Column(name = "brNo", length = 50) | |||
open var brNo: String? = null | |||
@Size(max = 30) | |||
@Column(name = "contactNo", length = 30) | |||
@Size(max = 50) | |||
@Column(name = "contactNo", length = 50) | |||
open var contactNo: String? = null | |||
@Size(max = 30) | |||
@Column(name = "contactEmail", length = 30) | |||
@Size(max = 50) | |||
@Column(name = "contactEmail", length = 50) | |||
open var contactEmail: String? = null | |||
@Size(max = 30) | |||
@Column(name = "contactName", length = 30) | |||
@Size(max = 50) | |||
@Column(name = "contactName", length = 50) | |||
open var contactName: String? = null | |||
@Size(max = 30) | |||
@Column(name = "addr1", length = 30) | |||
@Size(max = 300) | |||
@Column(name = "addr1", length = 300) | |||
open var addr1: String? = null | |||
@Size(max = 30) | |||
@Column(name = "addr2", length = 30) | |||
@Size(max = 300) | |||
@Column(name = "addr2", length = 300) | |||
open var addr2: String? = null | |||
@Size(max = 30) | |||
@Column(name = "addr3", length = 30) | |||
@Size(max = 300) | |||
@Column(name = "addr3", length = 300) | |||
open var addr3: String? = null | |||
@Size(max = 30) | |||
@Column(name = "addr4", length = 30) | |||
@Size(max = 300) | |||
@Column(name = "addr4", length = 300) | |||
open var addr4: String? = null | |||
@Size(max = 30) | |||
@Column(name = "district", length = 30) | |||
@Size(max = 300) | |||
@Column(name = "district", length = 300) | |||
open var district: String? = null | |||
@Size(max = 10) | |||
@Convert(converter = ShopTypeConverter::class) | |||
@Column(name = "type", length = 10) | |||
open var type: String? = null | |||
open var type: ShopType? = null | |||
@NotNull | |||
@Column(name = "m18Id", nullable = false) | |||
open var m18Id: Long? = null | |||
@NotNull | |||
@Column(name = "m18LastModifyDate", nullable = false) | |||
open var m18LastModifyDate: LocalDateTime? = null | |||
} |
@@ -5,4 +5,9 @@ import org.springframework.stereotype.Repository | |||
@Repository | |||
interface ShopRepository : AbstractRepository<Shop, Long> { | |||
fun findAllByDeletedIsFalse(): List<Shop> | |||
fun findByIdAndDeletedIsFalse(id: Long): Shop? | |||
fun findByM18IdAndDeletedIsFalse(m18Id: Long): Shop? | |||
} |
@@ -0,0 +1,6 @@ | |||
package com.ffii.fpsms.modules.master.enums | |||
enum class ShopType(val value: String) { | |||
SUPPLIER("supplier"), | |||
SHOP("shop"); | |||
} |
@@ -0,0 +1,17 @@ | |||
package com.ffii.fpsms.modules.master.enums | |||
import jakarta.persistence.AttributeConverter | |||
import jakarta.persistence.Converter | |||
@Converter(autoApply = true) | |||
class ShopTypeConverter : AttributeConverter<ShopType, String> { | |||
override fun convertToDatabaseColumn(type: ShopType?): String? { | |||
return type?.value | |||
} | |||
override fun convertToEntityAttribute(value: String?): ShopType? { | |||
return value?.let { v -> | |||
ShopType.entries.find { it.value == v } | |||
} | |||
} | |||
} |
@@ -48,6 +48,11 @@ open class ItemsService( | |||
return jdbcDao.queryForList(sql.toString(), args); | |||
} | |||
open fun findByM18Id(m18Id: Long): Items? { | |||
return itemsRepository.findByM18IdAndDeletedIsFalse(m18Id) | |||
} | |||
// QcCheck included item | |||
open fun getItem(id: Long): ItemWithQcResponse { | |||
val list = listOf(1,2) | |||
@@ -83,7 +88,7 @@ open class ItemsService( | |||
@Throws(IOException::class) | |||
@Transactional | |||
open fun saveItem(request: NewItemRequest): MessageResponse { | |||
val duplicatedItem = itemsRepository.findByCodeAndTypeAndDeletedFalse(request.code, request.type.name) | |||
val duplicatedItem = itemsRepository.findByCodeAndTypeAndDeletedFalse(request.code, request.type.type) | |||
if (duplicatedItem != null && duplicatedItem.id != request.id) { | |||
return MessageResponse( | |||
id = request.id, | |||
@@ -94,7 +99,8 @@ open class ItemsService( | |||
errorPosition = "code" | |||
) | |||
} | |||
val item = if (request.id != null && request.id > 0) itemsRepository.findByIdAndDeletedFalse(request.id) | |||
val item = if (request.m18Id != null) findByM18Id(request.m18Id) ?: Items() | |||
else if (request.id != null && request.id > 0) itemsRepository.findByIdAndDeletedFalse(request.id) | |||
else Items() | |||
item.apply { | |||
code = request.code | |||
@@ -104,7 +110,9 @@ open class ItemsService( | |||
shelfLife = request.shelfLife | |||
countryOfOrigin = request.countryOfOrigin | |||
maxQty = request.maxQty | |||
this.type = request.type.name | |||
this.type = request.type.type | |||
m18Id = request.m18Id ?: this.m18Id | |||
m18LastModifyDate = request.m18LastModifyDate ?: this.m18LastModifyDate | |||
} | |||
val savedItem = itemsRepository.saveAndFlush(item) | |||
return MessageResponse( | |||
@@ -4,7 +4,11 @@ import com.ffii.core.support.AbstractBaseEntityService | |||
import com.ffii.core.support.JdbcDao | |||
import com.ffii.fpsms.modules.master.entity.QcItem | |||
import com.ffii.fpsms.modules.master.entity.QcItemRepository | |||
import com.ffii.fpsms.modules.master.web.models.SaveQcItemRequest | |||
import com.ffii.fpsms.modules.master.web.models.SaveQcItemResponse | |||
import jakarta.validation.Valid | |||
import org.springframework.stereotype.Service | |||
import org.springframework.web.bind.annotation.RequestBody | |||
@Service | |||
open class QcItemService( | |||
@@ -31,4 +35,49 @@ open class QcItemService( | |||
return allQcItems() | |||
} | |||
open fun saveQcItem(@Valid @RequestBody request: SaveQcItemRequest): SaveQcItemResponse { | |||
// val qcItemProperties = QcItem::class.members.filterIsInstance<KProperty<QcItem>>() | |||
val errors = mutableMapOf<String, String>() | |||
val id = request.id | |||
val qcItem = if (id != null) qcItemRepository.findById(id).orElseThrow() else QcItem() | |||
// check duplicated code | |||
val duplicateQcItem = findQcItemByCode(request.code) | |||
if (duplicateQcItem != null && duplicateQcItem.id != qcItem.id) { | |||
errors["code"] = "Code is duplicated" | |||
} | |||
if (errors.isNotEmpty()) { | |||
request.let { | |||
SaveQcItemResponse( | |||
id = it.id, | |||
code = it.code, | |||
name = it.name, | |||
description = it.description, | |||
errors = errors | |||
) | |||
} | |||
} | |||
// Save Qc Item | |||
qcItem.apply { | |||
code = request.code | |||
name = request.name | |||
description = request.description | |||
} | |||
val savedQcItem = qcItemRepository.save(qcItem) | |||
return savedQcItem.let { | |||
SaveQcItemResponse( | |||
id = it.id, | |||
code = it.code, | |||
name = it.name, | |||
description = it.description, | |||
errors = null | |||
) | |||
} | |||
} | |||
} |
@@ -0,0 +1,62 @@ | |||
package com.ffii.fpsms.modules.master.service | |||
import com.ffii.fpsms.modules.master.entity.Shop | |||
import com.ffii.fpsms.modules.master.entity.ShopRepository | |||
import com.ffii.fpsms.modules.master.enums.ShopType | |||
import com.ffii.fpsms.modules.master.web.models.SaveShopRequest | |||
import com.ffii.fpsms.modules.master.web.models.SaveShopResponse | |||
import org.springframework.stereotype.Service | |||
import kotlin.jvm.optionals.getOrDefault | |||
@Service | |||
open class ShopService( | |||
val shopRepository: ShopRepository | |||
) { | |||
open fun findAll(): List<Shop> { | |||
return shopRepository.findAllByDeletedIsFalse() | |||
} | |||
open fun findById(id: Long): Shop? { | |||
return shopRepository.findByIdAndDeletedIsFalse(id) | |||
} | |||
open fun findByM18Id(m18Id: Long): Shop? { | |||
return shopRepository.findByM18IdAndDeletedIsFalse(m18Id) | |||
} | |||
open fun saveShop(request: SaveShopRequest): SaveShopResponse { | |||
val shop = if (request.m18Id != null) { | |||
findByM18Id(request.m18Id) ?: Shop() | |||
} else { | |||
request.id?.let { shopRepository.findById(it).getOrDefault(Shop()) } ?: Shop() | |||
} | |||
val type = request.type?.let { type -> ShopType.entries.find { it.value == type } } | |||
shop.apply { | |||
code = request.code | |||
name = request.name | |||
brNo = request.brNo | |||
contactNo = request.contactNo | |||
contactEmail = request.contactEmail | |||
contactName = request.contactName | |||
addr1 = request.addr1 | |||
addr2 = request.addr2 | |||
addr3 = request.addr3 | |||
addr4 = request.addr4 | |||
district = request.district | |||
this.type = type | |||
m18Id = request.m18Id ?: this.m18Id | |||
m18LastModifyDate = request.m18LastModifyDate ?: this.m18LastModifyDate | |||
} | |||
val response = shopRepository.saveAndFlush(shop).let { | |||
SaveShopResponse( | |||
id = it.id, | |||
code = it.code, | |||
name = it.name, | |||
) | |||
} | |||
return response | |||
} | |||
} |
@@ -2,8 +2,9 @@ package com.ffii.fpsms.modules.master.web.models | |||
import jakarta.validation.constraints.NotBlank | |||
import jakarta.validation.constraints.NotNull | |||
import java.time.LocalDateTime | |||
enum class ItemType(type: String) { | |||
enum class ItemType(val type: String) { | |||
MATERIAL("mat"), | |||
BY_PRODUCT("byp"), | |||
PRODUCT("product"), | |||
@@ -24,6 +25,7 @@ data class NewItemRequest( | |||
val countryOfOrigin: String?, | |||
val maxQty: Double?, | |||
val m18Id: Long?, | |||
val m18LastModifyDate: LocalDateTime?, | |||
// val type: List<NewTypeRequest>?, | |||
// val uom: List<NewUomRequest>?, | |||
// val weightUnit: List<NewWeightUnitRequest>?, | |||
@@ -0,0 +1,21 @@ | |||
package com.ffii.fpsms.modules.master.web.models | |||
import java.time.LocalDateTime | |||
data class SaveShopRequest ( | |||
val id: Long?, | |||
val code: String?, | |||
val name: String?, | |||
val brNo: String?, | |||
val contactNo: String?, | |||
val contactEmail: String?, | |||
val contactName: String?, | |||
val addr1: String?, | |||
val addr2: String?, | |||
val addr3: String?, | |||
val addr4: String?, | |||
val district: String?, | |||
val type: String?, | |||
val m18Id: Long?, | |||
val m18LastModifyDate: LocalDateTime?, | |||
) |
@@ -0,0 +1,7 @@ | |||
package com.ffii.fpsms.modules.master.web.models | |||
data class SaveShopResponse ( | |||
val id: Long?, | |||
val code: String?, | |||
val name: String?, | |||
) |
@@ -2,7 +2,9 @@ package com.ffii.fpsms.modules.purchaseOrder.entity | |||
import com.ffii.core.entity.BaseEntity | |||
import com.ffii.fpsms.modules.master.entity.Shop | |||
import com.ffii.fpsms.modules.stock.entity.M18DataLog | |||
import com.ffii.fpsms.m18.entity.M18DataLog | |||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus | |||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatusConverter | |||
import jakarta.persistence.* | |||
import jakarta.validation.constraints.NotNull | |||
import jakarta.validation.constraints.Size | |||
@@ -24,16 +26,16 @@ open class PurchaseOrder : BaseEntity<Long>() { | |||
@Column(name = "orderDate") | |||
open var orderDate: LocalDateTime? = null | |||
@Column(name = "estimatedCompleteDate") | |||
open var estimatedCompleteDate: LocalDate? = null | |||
@Column(name = "estimatedArrivalDate") | |||
open var estimatedArrivalDate: LocalDateTime? = null | |||
@Column(name = "completeDate") | |||
open var completeDate: LocalDateTime? = null | |||
@Size(max = 10) | |||
@NotNull | |||
@Column(name = "status", nullable = false, length = 10) | |||
open var status: String? = null | |||
@Convert(converter = PurchaseOrderStatusConverter::class) | |||
open var status: PurchaseOrderStatus? = null | |||
@NotNull | |||
@ManyToOne(fetch = FetchType.LAZY, optional = false) | |||
@@ -2,7 +2,10 @@ package com.ffii.fpsms.modules.purchaseOrder.entity | |||
import com.ffii.core.entity.BaseEntity | |||
import com.ffii.fpsms.modules.master.entity.Items | |||
import com.ffii.fpsms.modules.stock.entity.M18DataLog | |||
import com.ffii.fpsms.m18.entity.M18DataLog | |||
import com.ffii.fpsms.modules.master.enums.ShopTypeConverter | |||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus | |||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatusConverter | |||
import jakarta.persistence.* | |||
import jakarta.validation.constraints.NotNull | |||
import jakarta.validation.constraints.Size | |||
@@ -10,7 +13,7 @@ import java.math.BigDecimal | |||
@Entity | |||
@Table(name = "purchase_order_line") | |||
class PurchaseOrderLine : BaseEntity<Long>(){ | |||
open class PurchaseOrderLine : BaseEntity<Long>(){ | |||
@NotNull | |||
@ManyToOne(fetch = FetchType.LAZY, optional = false) | |||
@JoinColumn(name = "itemId", nullable = false) | |||
@@ -21,6 +24,11 @@ class PurchaseOrderLine : BaseEntity<Long>(){ | |||
@Column(name = "itemNo", nullable = false, length = 20) | |||
open var itemNo: String? = null | |||
// @NotNull | |||
// @ManyToOne(fetch = FetchType.LAZY, optional = false) | |||
// @JoinColumn(name = "uomId", nullable = false) | |||
// open var uom: UomConversion? = null | |||
@NotNull | |||
@ManyToOne(fetch = FetchType.LAZY, optional = false) | |||
@JoinColumn(name = "purchaseOrderId", nullable = false) | |||
@@ -36,10 +44,10 @@ class PurchaseOrderLine : BaseEntity<Long>(){ | |||
@Column(name = "priceUnit", length = 5) | |||
open var priceUnit: String? = null | |||
@Size(max = 10) | |||
@Convert(converter = PurchaseOrderLineStatusConverter::class) | |||
@NotNull | |||
@Column(name = "status", nullable = false, length = 10) | |||
open var status: String? = null | |||
open var status: PurchaseOrderLineStatus? = null | |||
@NotNull | |||
@ManyToOne(fetch = FetchType.LAZY, optional = false) | |||
@@ -2,7 +2,9 @@ package com.ffii.fpsms.modules.purchaseOrder.entity | |||
import com.ffii.core.support.AbstractRepository | |||
import org.springframework.stereotype.Repository | |||
import java.io.Serializable | |||
@Repository | |||
interface PurchaseOrderLineRepository : AbstractRepository<PurchaseOrderLine, Long> { | |||
fun findByM18DataLogIdAndDeletedIsFalse(m18datalogId: Serializable): PurchaseOrderLine? | |||
} |
@@ -2,7 +2,9 @@ package com.ffii.fpsms.modules.purchaseOrder.entity | |||
import com.ffii.core.support.AbstractRepository | |||
import org.springframework.stereotype.Repository | |||
import java.io.Serializable | |||
@Repository | |||
interface PurchaseOrderRepository : AbstractRepository<PurchaseOrder, Long> { | |||
fun findByM18DataLogIdAndDeletedIsFalse(m18datalogId: Serializable): PurchaseOrder? | |||
} |
@@ -0,0 +1,10 @@ | |||
package com.ffii.fpsms.modules.purchaseOrder.enums | |||
import com.ffii.fpsms.modules.master.enums.ShopType | |||
enum class PurchaseOrderLineStatus(val value: String) { | |||
PENDING("pending"), | |||
PICKING("picking"), | |||
COMPLETED("completed"); | |||
} | |||
@@ -0,0 +1,17 @@ | |||
package com.ffii.fpsms.modules.purchaseOrder.enums | |||
import jakarta.persistence.AttributeConverter | |||
import jakarta.persistence.Converter | |||
@Converter(autoApply = true) | |||
class PurchaseOrderLineStatusConverter : AttributeConverter<PurchaseOrderLineStatus, String> { | |||
override fun convertToDatabaseColumn(status: PurchaseOrderLineStatus?): String? { | |||
return status?.value | |||
} | |||
override fun convertToEntityAttribute(value: String?): PurchaseOrderLineStatus? { | |||
return value?.let { v -> | |||
PurchaseOrderLineStatus.entries.find { it.value == v } | |||
} | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
package com.ffii.fpsms.modules.purchaseOrder.enums | |||
import com.ffii.fpsms.modules.master.enums.ShopType | |||
enum class PurchaseOrderStatus(val value: String) { | |||
PENDING ("pending"), | |||
RECEIVING ("receiving"), | |||
COMPLETED ("completed"); | |||
companion object { | |||
fun fromValue(value: String): ShopType { | |||
return ShopType.entries.find { it.value == value } | |||
?: throw IllegalArgumentException("No enum constant with value: $value") | |||
} | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
package com.ffii.fpsms.modules.purchaseOrder.enums | |||
import jakarta.persistence.AttributeConverter | |||
import jakarta.persistence.Converter | |||
@Converter(autoApply = true) | |||
class PurchaseOrderStatusConverter : AttributeConverter<PurchaseOrderStatus, String>{ | |||
override fun convertToDatabaseColumn(status: PurchaseOrderStatus?): String? { | |||
return status?.value | |||
} | |||
override fun convertToEntityAttribute(value: String?): PurchaseOrderStatus? { | |||
return value?.let { v -> | |||
PurchaseOrderStatus.entries.find { it.value == v } | |||
} | |||
} | |||
} |
@@ -0,0 +1,67 @@ | |||
package com.ffii.fpsms.modules.purchaseOrder.service | |||
import com.ffii.fpsms.m18.entity.M18DataLogRepository | |||
import com.ffii.fpsms.modules.master.entity.ItemsRepository | |||
import com.ffii.fpsms.modules.master.service.ItemsService | |||
import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrder | |||
import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderLine | |||
import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderLineRepository | |||
import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderRepository | |||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus | |||
import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderLineRequest | |||
import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderLineResponse | |||
import org.springframework.stereotype.Service | |||
import java.math.BigDecimal | |||
import kotlin.jvm.optionals.getOrDefault | |||
import kotlin.jvm.optionals.getOrNull | |||
@Service | |||
open class PurchaseOrderLineService( | |||
val purchaseOrderLineRepository: PurchaseOrderLineRepository, | |||
val itemsService: ItemsService, | |||
val itemsRepository: ItemsRepository, | |||
val purchaseOrderRepository: PurchaseOrderRepository, | |||
val m18DataLogRepository: M18DataLogRepository | |||
) { | |||
open fun allPurchaseOrderLine(): List<PurchaseOrderLine> { | |||
return purchaseOrderLineRepository.findAll() | |||
} | |||
open fun findPurchaseOrderLineByM18Id(m18DataLogId: Long): PurchaseOrderLine? { | |||
return purchaseOrderLineRepository.findByM18DataLogIdAndDeletedIsFalse(m18DataLogId) | |||
} | |||
open fun savePurchaseOrderLine(request: SavePurchaseOrderLineRequest): SavePurchaseOrderLineResponse { | |||
val purchaseOrderLine = | |||
request.id?.let { purchaseOrderLineRepository.findById(it).getOrDefault(PurchaseOrderLine()) } | |||
?: PurchaseOrderLine() | |||
val item = request.itemId?.let { itemsRepository.findById(it).getOrNull() } | |||
val purchaseOrder = request.purchaseOrderId?.let { purchaseOrderRepository.findById(it).getOrNull() } | |||
val status = request.status?.let { status -> PurchaseOrderLineStatus.entries.find { it.value == status } } | |||
val m18DataLog = request.m18DataLogId?.let { m18DataLogRepository.findById(it).getOrNull() } | |||
purchaseOrderLine.apply { | |||
this.item = item | |||
itemNo = item?.code | |||
this.purchaseOrder = purchaseOrder | |||
qty = request.qty | |||
price = request.price | |||
priceUnit = request.priceUnit | |||
this.status = status | |||
this.m18DataLog = m18DataLog ?: this.m18DataLog | |||
} | |||
val savedPurchaseOrderLine = purchaseOrderLineRepository.saveAndFlush(purchaseOrderLine).let { | |||
SavePurchaseOrderLineResponse( | |||
id = it.id, | |||
itemNo = it.itemNo, | |||
qty = it.qty, | |||
price = it.price, | |||
priceUnit = it.priceUnit, | |||
status = it.status?.value | |||
) | |||
} | |||
return savedPurchaseOrderLine | |||
} | |||
} |
@@ -1,14 +1,60 @@ | |||
package com.ffii.fpsms.modules.purchaseOrder.service | |||
import com.ffii.fpsms.m18.entity.M18DataLogRepository | |||
import com.ffii.fpsms.modules.master.entity.ShopRepository | |||
import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrder | |||
import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderRepository | |||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus | |||
import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderRequest | |||
import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderResponse | |||
import org.springframework.stereotype.Service | |||
import kotlin.jvm.optionals.getOrDefault | |||
import kotlin.jvm.optionals.getOrNull | |||
@Service | |||
open class PurchaseOrderService( | |||
val purchaseOrderRepository: PurchaseOrderRepository | |||
val purchaseOrderRepository: PurchaseOrderRepository, | |||
val shopRepository: ShopRepository, | |||
val m18DataLogRepository: M18DataLogRepository, | |||
) { | |||
open fun allPurchaseOrder(): List<PurchaseOrder> { | |||
return purchaseOrderRepository.findAll() | |||
} | |||
open fun findPurchaseOrderByM18Id(m18DataLogId: Long): PurchaseOrder? { | |||
return purchaseOrderRepository.findByM18DataLogIdAndDeletedIsFalse(m18DataLogId) | |||
} | |||
open fun savePurchaseOrder(request: SavePurchaseOrderRequest): SavePurchaseOrderResponse { | |||
val purchaseOrder = | |||
request.id?.let { purchaseOrderRepository.findById(it).getOrDefault(PurchaseOrder()) } ?: PurchaseOrder() | |||
val supplier = request.supplierId?.let { shopRepository.findById(it).getOrNull() } | |||
val status = request.status?.let { status -> PurchaseOrderStatus.entries.find { it.value == status } } | |||
val m18DataLog = request.m18DataLogId?.let { m18DataLogRepository.findById(it).getOrNull() } | |||
//Need check duplicate? | |||
purchaseOrder.apply { | |||
code = request.code | |||
this.supplier = supplier | |||
orderDate = request.orderDate | |||
estimatedArrivalDate = request.estimatedArrivalDate | |||
completeDate = request.completeDate | |||
this.status = status | |||
this.m18DataLog = m18DataLog | |||
} | |||
val savedPurchaseOrder = purchaseOrderRepository.saveAndFlush(purchaseOrder).let { | |||
SavePurchaseOrderResponse( | |||
id = it.id, | |||
code = it.code, | |||
supplierCode = it.supplier?.code, | |||
orderDate = it.orderDate, | |||
estimatedArrivalDate = it.estimatedArrivalDate, | |||
completeDate = it.completeDate, | |||
status = it.status?.value | |||
) | |||
} | |||
return savedPurchaseOrder | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
package com.ffii.fpsms.modules.purchaseOrder.web.model | |||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus | |||
import java.math.BigDecimal | |||
data class SavePurchaseOrderLineRequest( | |||
val id: Long?, | |||
val itemId: Long?, | |||
val uomId: Long?, | |||
val purchaseOrderId: Long?, | |||
val qty: BigDecimal?, | |||
val price: BigDecimal?, | |||
val priceUnit: String?, | |||
val status: String?, | |||
val m18DataLogId: Long?, | |||
) |
@@ -0,0 +1,13 @@ | |||
package com.ffii.fpsms.modules.purchaseOrder.web.model | |||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus | |||
import java.math.BigDecimal | |||
data class SavePurchaseOrderLineResponse ( | |||
val id: Long?, | |||
val itemNo: String?, | |||
val qty: BigDecimal?, | |||
val price: BigDecimal?, | |||
val priceUnit: String?, | |||
val status: String?, | |||
) |
@@ -0,0 +1,16 @@ | |||
package com.ffii.fpsms.modules.purchaseOrder.web.model | |||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus | |||
import java.time.LocalDate | |||
import java.time.LocalDateTime | |||
data class SavePurchaseOrderRequest ( | |||
val id: Long?, | |||
val code: String?, | |||
val supplierId: Long?, | |||
val orderDate: LocalDateTime?, | |||
val estimatedArrivalDate: LocalDateTime?, | |||
val completeDate: LocalDateTime?, | |||
val status: String?, | |||
val m18DataLogId: Long? | |||
) |
@@ -0,0 +1,15 @@ | |||
package com.ffii.fpsms.modules.purchaseOrder.web.model | |||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus | |||
import java.time.LocalDate | |||
import java.time.LocalDateTime | |||
data class SavePurchaseOrderResponse ( | |||
val id: Long?, | |||
val code: String?, | |||
val supplierCode: String?, | |||
val orderDate: LocalDateTime?, | |||
val estimatedArrivalDate: LocalDateTime?, | |||
val completeDate: LocalDateTime?, | |||
val status: String?, | |||
) |
@@ -1,6 +1,7 @@ | |||
package com.ffii.fpsms.modules.stock.entity | |||
import com.ffii.core.entity.BaseEntity | |||
import com.ffii.fpsms.m18.entity.M18DataLog | |||
import com.ffii.fpsms.modules.master.entity.Items | |||
import com.ffii.fpsms.modules.stock.entity.enum.StockInLineStatus | |||
import com.ffii.fpsms.modules.user.entity.User | |||
@@ -1,37 +1,54 @@ | |||
server: | |||
servlet: | |||
contextPath: /api | |||
encoding: | |||
charset: UTF-8 | |||
enabled: true | |||
force: true | |||
port: 8090 | |||
error: | |||
include-message: always | |||
servlet: | |||
contextPath: /api | |||
encoding: | |||
charset: UTF-8 | |||
enabled: true | |||
force: true | |||
port: 8090 | |||
error: | |||
include-message: always | |||
spring: | |||
servlet: | |||
multipart: | |||
max-file-size: 500MB | |||
max-request-size: 600MB | |||
jpa: | |||
hibernate: | |||
naming: | |||
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl | |||
database-platform: org.hibernate.dialect.MySQL8Dialect | |||
properties: | |||
hibernate: | |||
dialect: | |||
storage_engine: innodb | |||
servlet: | |||
multipart: | |||
max-file-size: 500MB | |||
max-request-size: 600MB | |||
jpa: | |||
hibernate: | |||
naming: | |||
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl | |||
database-platform: org.hibernate.dialect.MySQL8Dialect | |||
properties: | |||
hibernate: | |||
dialect: | |||
storage_engine: innodb | |||
logging: | |||
config: 'classpath:log4j2.yml' | |||
config: 'classpath:log4j2.yml' | |||
m18: | |||
config: | |||
grant-type: password | |||
client-id: M2Y1OGYxMmQtZDRiOS00OTA4LTgyNTktZDRkNzEzNWVkMzRm | |||
client-secret: M2Y2YjQzYzQtZTc2Mi00OTFhLTkwYmItYmJhMzFjZjEyYmY5 | |||
username: testingMTMS | |||
password: db25f2fc14cd2d2b1e7af307241f548fb03c312a | |||
base-url: http://16.162.251.126/jsf/rfws | |||
config: | |||
grant-type: password | |||
client-id: M2Y1OGYxMmQtZDRiOS00OTA4LTgyNTktZDRkNzEzNWVkMzRm | |||
client-secret: M2Y2YjQzYzQtZTc2Mi00OTFhLTkwYmItYmJhMzFjZjEyYmY5 | |||
username: testingMTMS | |||
password: db25f2fc14cd2d2b1e7af307241f548fb03c312a | |||
base-url: http://16.162.251.126/jsf/rfws | |||
base-password: qwer1234 | |||
beId: | |||
toa: 29 | |||
pp: 27 | |||
pf: 1 | |||
seriesId: | |||
pp: 26 | |||
pf: 33 | |||
fa: 2 | |||
fb: 3 | |||
fc: 4 | |||
fd: 5 | |||
ff: 6 | |||
sc: 27 | |||
se: 28 | |||
sf: 70 | |||
sr: 29 |
@@ -4,23 +4,24 @@ | |||
CREATE TABLE items | |||
( | |||
id INT NOT NULL AUTO_INCREMENT, | |||
version INT NOT NULL DEFAULT '0', | |||
created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||
createdBy VARCHAR(30) NULL, | |||
modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||
modifiedBy VARCHAR(30) NULL, | |||
deleted TINYINT(1) NOT NULL DEFAULT '0', | |||
`code` VARCHAR(50) NOT NULL, | |||
`name` VARCHAR(50) NOT NULL, | |||
description VARCHAR(100) NULL, | |||
remarks varchar(500) NULL, | |||
type VARCHAR(50) NOT NULL, | |||
uomId INT(11) NOT NULL DEFAULT 0, | |||
shelfLife INT(11) NULL, | |||
countryOfOrigin varchar(50) NULL, | |||
maxQty DECIMAL(16, 2) NULL, | |||
m18Id INT(11) NULL, | |||
id INT NOT NULL AUTO_INCREMENT, | |||
version INT NOT NULL DEFAULT '0', | |||
created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||
createdBy VARCHAR(30) NULL, | |||
modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||
modifiedBy VARCHAR(30) NULL, | |||
deleted TINYINT(1) NOT NULL DEFAULT '0', | |||
`code` VARCHAR(50) NOT NULL, | |||
`name` VARCHAR(500) NOT NULL, | |||
description VARCHAR(500) NULL, | |||
remarks varchar(500) NULL, | |||
type VARCHAR(50) NOT NULL, | |||
uomId INT(11) NOT NULL DEFAULT 0, | |||
shelfLife INT(11) NULL, | |||
countryOfOrigin varchar(50) NULL, | |||
maxQty DECIMAL(16, 2) NULL, | |||
m18Id INT(11) NULL, | |||
m18LastModifyDate datetime NOT NULL, | |||
CONSTRAINT pk_material PRIMARY KEY (id) | |||
); | |||
CREATE TABLE uom_conversion | |||
@@ -3,26 +3,27 @@ | |||
--changeset cyril:master data for shop and warehouse | |||
CREATE TABLE `shop` | |||
( | |||
`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, | |||
`name` VARCHAR(30) NOT NULL, | |||
`brNo` VARCHAR(30) NULL, | |||
`contactNo` VARCHAR(30) NULL, | |||
`contactEmail` VARCHAR(30) NULL, | |||
`contactName` VARCHAR(30) NULL, | |||
`addr1` VARCHAR(30) NULL, | |||
`addr2` VARCHAR(30) NULL, | |||
`addr3` VARCHAR(30) NULL, | |||
`addr4` VARCHAR(30) NULL, | |||
`district` VARCHAR(30) NULL, | |||
`type` VARCHAR(10) NULL, | |||
`m18Id` INT NOT NULL, | |||
`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(50) NOT NULL, | |||
`name` VARCHAR(300) NOT NULL, | |||
`brNo` VARCHAR(50) NULL, | |||
`contactNo` VARCHAR(50) NULL, | |||
`contactEmail` VARCHAR(50) NULL, | |||
`contactName` VARCHAR(50) NULL, | |||
`addr1` VARCHAR(300) NULL, | |||
`addr2` VARCHAR(300) NULL, | |||
`addr3` VARCHAR(300) NULL, | |||
`addr4` VARCHAR(300) NULL, | |||
`district` VARCHAR(300) NULL, | |||
`type` VARCHAR(10) NULL, | |||
`m18Id` INT NOT NULL, | |||
`m18LastModifyDate` datetime NOT NULL, | |||
CONSTRAINT pk_shop PRIMARY KEY (id) | |||
); | |||
@@ -3,16 +3,17 @@ | |||
--changeset cyril:m18 data log | |||
CREATE TABLE `m18_data_log` | |||
( | |||
`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', | |||
`refType` VARCHAR(10) NOT NULL, | |||
`m18Id` INT NOT NULL, | |||
`dataLog` JSON NOT NULL, | |||
`status` VARCHAR(5) NOT NULL, | |||
`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', | |||
`refType` VARCHAR(1000) NOT NULL, | |||
`m18Id` INT NOT NULL, | |||
`m18LastModifyDate` datetime NOT NULL, | |||
`dataLog` JSON NOT NULL, | |||
`status` TINYINT(1) NOT NULL, | |||
CONSTRAINT pk_m18_data_log PRIMARY KEY (id) | |||
); |
@@ -13,7 +13,7 @@ CREATE TABLE `purchase_order` | |||
`code` VARCHAR(30) NOT NULL, | |||
`supplierId` INT NULL, | |||
`orderDate` DATETIME NULL, | |||
`estimatedCompleteDate` DATETIME NULL, | |||
`estimatedArrivalDate` DATETIME NULL, | |||
`completeDate` DATETIME NULL, | |||
`status` VARCHAR(10) NOT NULL DEFAULT 'pending', | |||
`m18DataLogId` INT NOT NULL, | |||
@@ -24,23 +24,25 @@ CREATE TABLE `purchase_order` | |||
CREATE TABLE `purchase_order_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', | |||
`itemId` INT NOT NULL, | |||
`itemNo` VARCHAR(20) NOT NULL, | |||
`purchaseOrderId` INT NOT NULL, | |||
`qty` DECIMAL(14, 2) NULL, | |||
`price` DECIMAL(14, 2) NULL, | |||
`priceUnit` VARCHAR(5) NULL, | |||
`status` VARCHAR(10) NOT NULL DEFAULT 'pending', | |||
`m18DataLogId` INT NOT NULL, | |||
`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', | |||
`itemId` INT NOT NULL, | |||
`itemNo` VARCHAR(20) NOT NULL, | |||
`uomId` INT NULL, | |||
`purchaseOrderId` INT NOT NULL, | |||
`qty` DECIMAL(14, 2) NULL, | |||
`price` DECIMAL(14, 2) NULL, | |||
`priceUnit` VARCHAR(5) NULL, | |||
`status` VARCHAR(10) NOT NULL DEFAULT 'pending', | |||
`m18DataLogId` INT NOT NULL, | |||
CONSTRAINT pk_purchase_order_line PRIMARY KEY (id), | |||
CONSTRAINT FK_PURCHASE_ORDER_LINE_ON_ITEMID FOREIGN KEY (itemId) REFERENCES items (id), | |||
-- CONSTRAINT FK_PURCHASE_ORDER_LINE_ON_UOMID FOREIGN KEY (uomId) REFERENCES uom_conversion (id), | |||
CONSTRAINT FK_PURCHASE_ORDER_LINE_ON_PURCHASEORDERID FOREIGN KEY (purchaseOrderId) REFERENCES purchase_order (id), | |||
CONSTRAINT FK_PURCHASE_ORDER_LINE_ON_M18DATALOGID FOREIGN KEY (m18DataLogId) REFERENCES m18_data_log (id) | |||
); |