| @@ -30,6 +30,8 @@ dependencies { | |||||
| implementation 'org.liquibase:liquibase-core' | implementation 'org.liquibase:liquibase-core' | ||||
| implementation 'com.google.code.gson:gson:2.8.5' | 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.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', version: '5.2.3' | ||||
| implementation group: 'org.apache.poi', name: 'poi-ooxml', 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 | package com.ffii.fpsms.api.service | ||||
| import com.ffii.core.utils.JwtTokenUtil | |||||
| import com.ffii.fpsms.m18.M18Config | import com.ffii.fpsms.m18.M18Config | ||||
| import org.slf4j.Logger | |||||
| import org.slf4j.LoggerFactory | |||||
| import org.springframework.beans.factory.annotation.Value | import org.springframework.beans.factory.annotation.Value | ||||
| import org.springframework.http.HttpHeaders | import org.springframework.http.HttpHeaders | ||||
| import org.springframework.http.MediaType | 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 org.springframework.web.reactive.function.client.bodyToMono | ||||
| import reactor.core.publisher.Mono | import reactor.core.publisher.Mono | ||||
| import kotlin.reflect.full.memberProperties | import kotlin.reflect.full.memberProperties | ||||
| import org.springframework.cloud.context.config.annotation.RefreshScope | |||||
| import org.springframework.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 | @Service | ||||
| open class ApiCallerService( | open class ApiCallerService( | ||||
| @Value("\${m18.config.base-url}") private val baseUrl: String, | @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() | val webClient: WebClient = WebClient.builder() | ||||
| .baseUrl(baseUrl) | .baseUrl(baseUrl) | ||||
| .defaultHeaders { headers -> | .defaultHeaders { headers -> | ||||
| headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) | 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) | 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() | .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( | inline fun <reified T : Any> get( | ||||
| urlPath: String, | urlPath: String, | ||||
| params: MultiValueMap<String, String>, | params: MultiValueMap<String, String>, | ||||
| customHeaders: Map<String, String>? | customHeaders: Map<String, String>? | ||||
| ): Mono<T> { | ): Mono<T> { | ||||
| println("ACCESS TOKEN: ${m18Config.ACCESS_TOKEN}") | |||||
| return webClient.get() | return webClient.get() | ||||
| .uri { uriBuilder -> | .uri { uriBuilder -> | ||||
| uriBuilder | uriBuilder | ||||
| @@ -49,8 +74,30 @@ open class ApiCallerService( | |||||
| } | } | ||||
| .retrieve() | .retrieve() | ||||
| .bodyToMono(T::class.java) | .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( | inline fun <reified T : Any> get( | ||||
| urlPath: String, | urlPath: String, | ||||
| params: Map<String, Any>?, | params: Map<String, Any>?, | ||||
| @@ -72,7 +119,29 @@ open class ApiCallerService( | |||||
| return get<T>(urlPath, queryParams, customHeaders) | 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( | inline fun <reified T : Any, reified U : Any> get( | ||||
| urlPath: String, | urlPath: String, | ||||
| params: U?, | params: U?, | ||||
| @@ -95,4 +164,21 @@ open class ApiCallerService( | |||||
| return get<T>(urlPath, queryParams, customHeaders) | 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 | package com.ffii.fpsms.m18 | ||||
| import org.springframework.beans.factory.annotation.Value | 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.Bean | ||||
| import org.springframework.context.annotation.Configuration | import org.springframework.context.annotation.Configuration | ||||
| @Configuration | @Configuration | ||||
| open class M18Config { | open class M18Config { | ||||
| // Account | |||||
| @Value("\${m18.config.grant-type}") | @Value("\${m18.config.grant-type}") | ||||
| lateinit var GRANT_TYPE: String; | lateinit var GRANT_TYPE: String; | ||||
| @@ -22,5 +25,55 @@ open class M18Config { | |||||
| @Value("\${m18.config.password}") | @Value("\${m18.config.password}") | ||||
| lateinit var PASSWORD: String; | 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; | 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 com.ffii.core.entity.BaseEntity | ||||
| import jakarta.persistence.Column | import jakarta.persistence.Column | ||||
| @@ -8,26 +8,30 @@ import jakarta.validation.constraints.NotNull | |||||
| import jakarta.validation.constraints.Size | import jakarta.validation.constraints.Size | ||||
| import org.hibernate.annotations.JdbcTypeCode | import org.hibernate.annotations.JdbcTypeCode | ||||
| import org.hibernate.type.SqlTypes | import org.hibernate.type.SqlTypes | ||||
| import java.time.LocalDateTime | |||||
| @Entity | @Entity | ||||
| @Table(name = "m18_data_log") | @Table(name = "m18_data_log") | ||||
| open class M18DataLog : BaseEntity<Long>() { | open class M18DataLog : BaseEntity<Long>() { | ||||
| @Size(max = 10) | |||||
| @Size(max = 1000) | |||||
| @NotNull | @NotNull | ||||
| @Column(name = "refType", nullable = false, length = 10) | |||||
| @Column(name = "refType", nullable = false, length = 1000) | |||||
| open var refType: String? = null | open var refType: String? = null | ||||
| @NotNull | @NotNull | ||||
| @Column(name = "m18Id", nullable = false) | @Column(name = "m18Id", nullable = false) | ||||
| open var m18Id: Int? = null | |||||
| open var m18Id: Long? = null | |||||
| @NotNull | @NotNull | ||||
| @JdbcTypeCode(SqlTypes.JSON) | @JdbcTypeCode(SqlTypes.JSON) | ||||
| @Column(name = "dataLog", nullable = false) | @Column(name = "dataLog", nullable = false) | ||||
| open var dataLog: MutableMap<String, Any>? = null | |||||
| open var dataLog: MutableMap<String, Any?>? = null | |||||
| @Size(max = 5) | |||||
| @NotNull | @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 com.ffii.core.support.AbstractRepository | ||||
| import org.springframework.stereotype.Repository | import org.springframework.stereotype.Repository | ||||
| @Repository | @Repository | ||||
| interface M18DataLogRepository : AbstractRepository<M18DataLog, Long> { | 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( | data class M18TokenRequest( | ||||
| val grant_type: String, | val grant_type: String, | ||||
| @@ -1,4 +1,4 @@ | |||||
| package com.ffii.fpsms.m18.modals | |||||
| package com.ffii.fpsms.m18.model | |||||
| data class M18TokenResponse( | data class M18TokenResponse( | ||||
| val access_token: String, | 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.api.service.ApiCallerService | ||||
| import com.ffii.fpsms.m18.M18Config | 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 jakarta.annotation.PostConstruct | ||||
| import org.springframework.context.annotation.Bean | import org.springframework.context.annotation.Bean | ||||
| import org.springframework.stereotype.Component | |||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||
| @@ -16,7 +15,7 @@ open class M18TokenService( | |||||
| private val m18Config: M18Config | private val m18Config: M18Config | ||||
| ) { | ) { | ||||
| // @Bean | |||||
| @Bean | |||||
| fun run() { | fun run() { | ||||
| // val params: MutableMap<String, String> = mutableMapOf( | // val params: MutableMap<String, String> = mutableMapOf( | ||||
| // "grant_type" to m18Config.GRANT_TYPE, | // "grant_type" to m18Config.GRANT_TYPE, | ||||
| @@ -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 com.ffii.fpsms.modules.master.web.models.ItemType | ||||
| import jakarta.persistence.* | import jakarta.persistence.* | ||||
| import jakarta.validation.constraints.NotNull | import jakarta.validation.constraints.NotNull | ||||
| import java.time.LocalDateTime | |||||
| @Entity | @Entity | ||||
| @Table(name = "items") | @Table(name = "items") | ||||
| @@ -37,4 +38,7 @@ open class Items : BaseEntity<Long>() { | |||||
| @Column(name = "m18Id") | @Column(name = "m18Id") | ||||
| open var m18Id: Long? = null | open var m18Id: Long? = null | ||||
| @Column(name = "m18LastModifyDate") | |||||
| open var m18LastModifyDate: LocalDateTime? = null | |||||
| } | } | ||||
| @@ -7,6 +7,10 @@ import org.springframework.stereotype.Repository | |||||
| @Repository | @Repository | ||||
| interface ItemsRepository : AbstractRepository<Items, Long> { | interface ItemsRepository : AbstractRepository<Items, Long> { | ||||
| fun findAllByDeletedFalse(): List<Items>; | fun findAllByDeletedFalse(): List<Items>; | ||||
| fun findByIdAndDeletedFalse(id: Long): Items; | fun findByIdAndDeletedFalse(id: Long): Items; | ||||
| fun findByCodeAndTypeAndDeletedFalse(code: String, type: String): Items?; | fun findByCodeAndTypeAndDeletedFalse(code: String, type: String): Items?; | ||||
| fun findByM18IdAndDeletedIsFalse(m18Id: Long): Items?; | |||||
| } | } | ||||
| @@ -1,63 +1,75 @@ | |||||
| package com.ffii.fpsms.modules.master.entity | package com.ffii.fpsms.modules.master.entity | ||||
| import com.ffii.core.entity.BaseEntity | 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.Column | ||||
| import jakarta.persistence.Convert | |||||
| import jakarta.persistence.Entity | import jakarta.persistence.Entity | ||||
| import jakarta.persistence.Table | import jakarta.persistence.Table | ||||
| import jakarta.validation.constraints.NotNull | import jakarta.validation.constraints.NotNull | ||||
| import jakarta.validation.constraints.Size | import jakarta.validation.constraints.Size | ||||
| import java.time.LocalDateTime | |||||
| @Entity | @Entity | ||||
| @Table(name = "shop") | @Table(name = "shop") | ||||
| open class Shop : BaseEntity<Long>() { | open class Shop : BaseEntity<Long>() { | ||||
| @Size(max = 30) | |||||
| @Size(max = 50) | |||||
| @NotNull | @NotNull | ||||
| @Column(name = "code", nullable = false, length = 30) | |||||
| @Column(name = "code", nullable = false, length = 50) | |||||
| open var code: String? = null | open var code: String? = null | ||||
| @Size(max = 30) | |||||
| @Size(max = 300) | |||||
| @NotNull | @NotNull | ||||
| @Column(name = "name", nullable = false, length = 30) | |||||
| @Column(name = "name", nullable = false, length = 300) | |||||
| open var name: String? = null | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | open var district: String? = null | ||||
| @Size(max = 10) | |||||
| @Convert(converter = ShopTypeConverter::class) | |||||
| @Column(name = "type", length = 10) | @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 | @Repository | ||||
| interface ShopRepository : AbstractRepository<Shop, Long> { | 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); | return jdbcDao.queryForList(sql.toString(), args); | ||||
| } | } | ||||
| open fun findByM18Id(m18Id: Long): Items? { | |||||
| return itemsRepository.findByM18IdAndDeletedIsFalse(m18Id) | |||||
| } | |||||
| // QcCheck included item | // QcCheck included item | ||||
| open fun getItem(id: Long): ItemWithQcResponse { | open fun getItem(id: Long): ItemWithQcResponse { | ||||
| val list = listOf(1,2) | val list = listOf(1,2) | ||||
| @@ -83,7 +88,7 @@ open class ItemsService( | |||||
| @Throws(IOException::class) | @Throws(IOException::class) | ||||
| @Transactional | @Transactional | ||||
| open fun saveItem(request: NewItemRequest): MessageResponse { | 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) { | if (duplicatedItem != null && duplicatedItem.id != request.id) { | ||||
| return MessageResponse( | return MessageResponse( | ||||
| id = request.id, | id = request.id, | ||||
| @@ -94,7 +99,8 @@ open class ItemsService( | |||||
| errorPosition = "code" | 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() | else Items() | ||||
| item.apply { | item.apply { | ||||
| code = request.code | code = request.code | ||||
| @@ -104,7 +110,9 @@ open class ItemsService( | |||||
| shelfLife = request.shelfLife | shelfLife = request.shelfLife | ||||
| countryOfOrigin = request.countryOfOrigin | countryOfOrigin = request.countryOfOrigin | ||||
| maxQty = request.maxQty | 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) | val savedItem = itemsRepository.saveAndFlush(item) | ||||
| return MessageResponse( | return MessageResponse( | ||||
| @@ -4,7 +4,11 @@ import com.ffii.core.support.AbstractBaseEntityService | |||||
| import com.ffii.core.support.JdbcDao | import com.ffii.core.support.JdbcDao | ||||
| import com.ffii.fpsms.modules.master.entity.QcItem | import com.ffii.fpsms.modules.master.entity.QcItem | ||||
| import com.ffii.fpsms.modules.master.entity.QcItemRepository | 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.stereotype.Service | ||||
| import org.springframework.web.bind.annotation.RequestBody | |||||
| @Service | @Service | ||||
| open class QcItemService( | open class QcItemService( | ||||
| @@ -31,4 +35,49 @@ open class QcItemService( | |||||
| return allQcItems() | 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.NotBlank | ||||
| import jakarta.validation.constraints.NotNull | import jakarta.validation.constraints.NotNull | ||||
| import java.time.LocalDateTime | |||||
| enum class ItemType(type: String) { | |||||
| enum class ItemType(val type: String) { | |||||
| MATERIAL("mat"), | MATERIAL("mat"), | ||||
| BY_PRODUCT("byp"), | BY_PRODUCT("byp"), | ||||
| PRODUCT("product"), | PRODUCT("product"), | ||||
| @@ -24,6 +25,7 @@ data class NewItemRequest( | |||||
| val countryOfOrigin: String?, | val countryOfOrigin: String?, | ||||
| val maxQty: Double?, | val maxQty: Double?, | ||||
| val m18Id: Long?, | val m18Id: Long?, | ||||
| val m18LastModifyDate: LocalDateTime?, | |||||
| // val type: List<NewTypeRequest>?, | // val type: List<NewTypeRequest>?, | ||||
| // val uom: List<NewUomRequest>?, | // val uom: List<NewUomRequest>?, | ||||
| // val weightUnit: List<NewWeightUnitRequest>?, | // 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.core.entity.BaseEntity | ||||
| import com.ffii.fpsms.modules.master.entity.Shop | 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.persistence.* | ||||
| import jakarta.validation.constraints.NotNull | import jakarta.validation.constraints.NotNull | ||||
| import jakarta.validation.constraints.Size | import jakarta.validation.constraints.Size | ||||
| @@ -24,16 +26,16 @@ open class PurchaseOrder : BaseEntity<Long>() { | |||||
| @Column(name = "orderDate") | @Column(name = "orderDate") | ||||
| open var orderDate: LocalDateTime? = null | open var orderDate: LocalDateTime? = null | ||||
| @Column(name = "estimatedCompleteDate") | |||||
| open var estimatedCompleteDate: LocalDate? = null | |||||
| @Column(name = "estimatedArrivalDate") | |||||
| open var estimatedArrivalDate: LocalDateTime? = null | |||||
| @Column(name = "completeDate") | @Column(name = "completeDate") | ||||
| open var completeDate: LocalDateTime? = null | open var completeDate: LocalDateTime? = null | ||||
| @Size(max = 10) | |||||
| @NotNull | @NotNull | ||||
| @Column(name = "status", nullable = false, length = 10) | @Column(name = "status", nullable = false, length = 10) | ||||
| open var status: String? = null | |||||
| @Convert(converter = PurchaseOrderStatusConverter::class) | |||||
| open var status: PurchaseOrderStatus? = null | |||||
| @NotNull | @NotNull | ||||
| @ManyToOne(fetch = FetchType.LAZY, optional = false) | @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.core.entity.BaseEntity | ||||
| import com.ffii.fpsms.modules.master.entity.Items | 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.persistence.* | ||||
| import jakarta.validation.constraints.NotNull | import jakarta.validation.constraints.NotNull | ||||
| import jakarta.validation.constraints.Size | import jakarta.validation.constraints.Size | ||||
| @@ -10,7 +13,7 @@ import java.math.BigDecimal | |||||
| @Entity | @Entity | ||||
| @Table(name = "purchase_order_line") | @Table(name = "purchase_order_line") | ||||
| class PurchaseOrderLine : BaseEntity<Long>(){ | |||||
| open class PurchaseOrderLine : BaseEntity<Long>(){ | |||||
| @NotNull | @NotNull | ||||
| @ManyToOne(fetch = FetchType.LAZY, optional = false) | @ManyToOne(fetch = FetchType.LAZY, optional = false) | ||||
| @JoinColumn(name = "itemId", nullable = false) | @JoinColumn(name = "itemId", nullable = false) | ||||
| @@ -21,6 +24,11 @@ class PurchaseOrderLine : BaseEntity<Long>(){ | |||||
| @Column(name = "itemNo", nullable = false, length = 20) | @Column(name = "itemNo", nullable = false, length = 20) | ||||
| open var itemNo: String? = null | open var itemNo: String? = null | ||||
| // @NotNull | |||||
| // @ManyToOne(fetch = FetchType.LAZY, optional = false) | |||||
| // @JoinColumn(name = "uomId", nullable = false) | |||||
| // open var uom: UomConversion? = null | |||||
| @NotNull | @NotNull | ||||
| @ManyToOne(fetch = FetchType.LAZY, optional = false) | @ManyToOne(fetch = FetchType.LAZY, optional = false) | ||||
| @JoinColumn(name = "purchaseOrderId", nullable = false) | @JoinColumn(name = "purchaseOrderId", nullable = false) | ||||
| @@ -36,10 +44,10 @@ class PurchaseOrderLine : BaseEntity<Long>(){ | |||||
| @Column(name = "priceUnit", length = 5) | @Column(name = "priceUnit", length = 5) | ||||
| open var priceUnit: String? = null | open var priceUnit: String? = null | ||||
| @Size(max = 10) | |||||
| @Convert(converter = PurchaseOrderLineStatusConverter::class) | |||||
| @NotNull | @NotNull | ||||
| @Column(name = "status", nullable = false, length = 10) | @Column(name = "status", nullable = false, length = 10) | ||||
| open var status: String? = null | |||||
| open var status: PurchaseOrderLineStatus? = null | |||||
| @NotNull | @NotNull | ||||
| @ManyToOne(fetch = FetchType.LAZY, optional = false) | @ManyToOne(fetch = FetchType.LAZY, optional = false) | ||||
| @@ -2,7 +2,9 @@ package com.ffii.fpsms.modules.purchaseOrder.entity | |||||
| import com.ffii.core.support.AbstractRepository | import com.ffii.core.support.AbstractRepository | ||||
| import org.springframework.stereotype.Repository | import org.springframework.stereotype.Repository | ||||
| import java.io.Serializable | |||||
| @Repository | @Repository | ||||
| interface PurchaseOrderLineRepository : AbstractRepository<PurchaseOrderLine, Long> { | 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 com.ffii.core.support.AbstractRepository | ||||
| import org.springframework.stereotype.Repository | import org.springframework.stereotype.Repository | ||||
| import java.io.Serializable | |||||
| @Repository | @Repository | ||||
| interface PurchaseOrderRepository : AbstractRepository<PurchaseOrder, Long> { | 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 | 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.PurchaseOrder | ||||
| import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderRepository | 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 org.springframework.stereotype.Service | ||||
| import kotlin.jvm.optionals.getOrDefault | |||||
| import kotlin.jvm.optionals.getOrNull | |||||
| @Service | @Service | ||||
| open class PurchaseOrderService( | open class PurchaseOrderService( | ||||
| val purchaseOrderRepository: PurchaseOrderRepository | |||||
| val purchaseOrderRepository: PurchaseOrderRepository, | |||||
| val shopRepository: ShopRepository, | |||||
| val m18DataLogRepository: M18DataLogRepository, | |||||
| ) { | ) { | ||||
| open fun allPurchaseOrder(): List<PurchaseOrder> { | open fun allPurchaseOrder(): List<PurchaseOrder> { | ||||
| return purchaseOrderRepository.findAll() | 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 | package com.ffii.fpsms.modules.stock.entity | ||||
| import com.ffii.core.entity.BaseEntity | 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.master.entity.Items | ||||
| import com.ffii.fpsms.modules.stock.entity.enum.StockInLineStatus | import com.ffii.fpsms.modules.stock.entity.enum.StockInLineStatus | ||||
| import com.ffii.fpsms.modules.user.entity.User | import com.ffii.fpsms.modules.user.entity.User | ||||
| @@ -1,37 +1,54 @@ | |||||
| server: | 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: | 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: | logging: | ||||
| config: 'classpath:log4j2.yml' | |||||
| config: 'classpath:log4j2.yml' | |||||
| m18: | 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 | 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) | CONSTRAINT pk_material PRIMARY KEY (id) | ||||
| ); | ); | ||||
| CREATE TABLE uom_conversion | CREATE TABLE uom_conversion | ||||
| @@ -3,26 +3,27 @@ | |||||
| --changeset cyril:master data for shop and warehouse | --changeset cyril:master data for shop and warehouse | ||||
| CREATE TABLE `shop` | 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) | CONSTRAINT pk_shop PRIMARY KEY (id) | ||||
| ); | ); | ||||
| @@ -3,16 +3,17 @@ | |||||
| --changeset cyril:m18 data log | --changeset cyril:m18 data log | ||||
| CREATE TABLE `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) | CONSTRAINT pk_m18_data_log PRIMARY KEY (id) | ||||
| ); | ); | ||||
| @@ -13,7 +13,7 @@ CREATE TABLE `purchase_order` | |||||
| `code` VARCHAR(30) NOT NULL, | `code` VARCHAR(30) NOT NULL, | ||||
| `supplierId` INT NULL, | `supplierId` INT NULL, | ||||
| `orderDate` DATETIME NULL, | `orderDate` DATETIME NULL, | ||||
| `estimatedCompleteDate` DATETIME NULL, | |||||
| `estimatedArrivalDate` DATETIME NULL, | |||||
| `completeDate` DATETIME NULL, | `completeDate` DATETIME NULL, | ||||
| `status` VARCHAR(10) NOT NULL DEFAULT 'pending', | `status` VARCHAR(10) NOT NULL DEFAULT 'pending', | ||||
| `m18DataLogId` INT NOT NULL, | `m18DataLogId` INT NOT NULL, | ||||
| @@ -24,23 +24,25 @@ CREATE TABLE `purchase_order` | |||||
| CREATE TABLE `purchase_order_line` | 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 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_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_PURCHASEORDERID FOREIGN KEY (purchaseOrderId) REFERENCES purchase_order (id), | ||||
| CONSTRAINT FK_PURCHASE_ORDER_LINE_ON_M18DATALOGID FOREIGN KEY (m18DataLogId) REFERENCES m18_data_log (id) | CONSTRAINT FK_PURCHASE_ORDER_LINE_ON_M18DATALOGID FOREIGN KEY (m18DataLogId) REFERENCES m18_data_log (id) | ||||
| ); | ); | ||||