| @@ -22,13 +22,12 @@ import org.springframework.web.reactive.function.client.awaitBody | |||
| @Service | |||
| open class ApiCallerService( | |||
| @Value("\${m18.config.base-url}") private val baseUrl: String, | |||
| open val m18Config: M18Config | |||
| val m18Config: M18Config | |||
| ) { | |||
| val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) | |||
| val webClient: WebClient = WebClient.builder() | |||
| .baseUrl(baseUrl) | |||
| .baseUrl(m18Config.BASE_URL) | |||
| .defaultHeaders { headers -> | |||
| headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) | |||
| // headers.set(HttpHeaders.AUTHORIZATION, "Bearer ${m18Config.ACCESS_TOKEN}") | |||
| @@ -10,48 +10,61 @@ import org.springframework.context.annotation.Configuration | |||
| open class M18Config { | |||
| // Account | |||
| @Value("\${m18.config.grant-type}") | |||
| lateinit var GRANT_TYPE: String; | |||
| // @Value("\${m18.config.grant-type}") | |||
| var GRANT_TYPE: String = "password"; | |||
| @Value("\${m18.config.client-id}") | |||
| lateinit var CLIENT_ID: String; | |||
| // @Value("\${m18.config.client-id}") | |||
| var CLIENT_ID: String = "M2Y1OGYxMmQtZDRiOS00OTA4LTgyNTktZDRkNzEzNWVkMzRm"; | |||
| @Value("\${m18.config.client-secret}") | |||
| lateinit var CLIENT_SECRET: String; | |||
| // @Value("\${m18.config.client-secret}") | |||
| var CLIENT_SECRET: String = "M2Y2YjQzYzQtZTc2Mi00OTFhLTkwYmItYmJhMzFjZjEyYmY5"; | |||
| @Value("\${m18.config.username}") | |||
| lateinit var USERNAME: String; | |||
| // @Value("\${m18.config.username}") | |||
| var USERNAME: String = "testingMTMS"; | |||
| @Value("\${m18.config.password}") | |||
| lateinit var PASSWORD: String; | |||
| // @Value("\${m18.config.password}") | |||
| var PASSWORD: String = "db25f2fc14cd2d2b1e7af307241f548fb03c312a"; | |||
| var BASE_URL: String = "http://16.162.251.126/jsf/rfws" | |||
| // Supplier | |||
| // @Value("\${m18.config.supplier-not.material-po}") | |||
| var MATERIAL_PO_SUPPLIER_NOT: List<String> = listOf("P06", "P07"); | |||
| // @Value("\${m18.config.supplier.shop-po}") | |||
| var SHOP_PO_SUPPLIER: List<String> = listOf("P06", "P07"); | |||
| // @Value("\${m18.config.supplier.oem-po}") | |||
| var OEM_PO_SUPPLIER: List<String> = listOf("T62"); | |||
| // Series | |||
| @Value("\${m18.config.seriesId.pp}") | |||
| var SERIESID_PP: Long? = null; | |||
| // @Value("\${m18.config.seriesId.pp}") | |||
| var SERIESID_PP: Long = 26; | |||
| // @Value("\${m18.config.seriesId.pf}") | |||
| var SERIESID_PF: Long = 33; | |||
| @Value("\${m18.config.seriesId.pf}") | |||
| var SERIESID_PF: Long? = null; | |||
| // @Value("\${m18.config.seriesId.sc}") | |||
| var SERIESID_SC: Long = 27; | |||
| @Value("\${m18.config.seriesId.sc}") | |||
| var SERIESID_SC: Long? = null; | |||
| // @Value("\${m18.config.seriesId.se}") | |||
| var SERIESID_SE: Long = 28; | |||
| @Value("\${m18.config.seriesId.se}") | |||
| var SERIESID_SE: Long? = null; | |||
| // @Value("\${m18.config.seriesId.sf}") | |||
| var SERIESID_SF: Long = 70; | |||
| @Value("\${m18.config.seriesId.sf}") | |||
| var SERIESID_SF: Long? = null; | |||
| // @Value("\${m18.config.seriesId.sr}") | |||
| var SERIESID_SR: Long = 29; | |||
| @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.pp}") | |||
| var BEID_PP: Long = 27; | |||
| @Value("\${m18.config.beId.pf}") | |||
| var BEID_PF: Long? = null; | |||
| // @Value("\${m18.config.beId.pf}") | |||
| var BEID_PF: Long = 1; | |||
| @Value("\${m18.config.beId.toa}") | |||
| var BEID_TOA: Long? = null; | |||
| // @Value("\${m18.config.beId.toa}") | |||
| var BEID_TOA: Long = 29; | |||
| // Fetch | |||
| var ACCESS_TOKEN: String? = null; | |||
| @@ -1,40 +1,22 @@ | |||
| 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, | |||
| ) | |||
| /** StSearch Type */ | |||
| enum class StSearchType(val value: String) { | |||
| PRODUCT("pro"), | |||
| VENDOR("ven"), | |||
| CUSTOMER("cus"), | |||
| UNIT("unit"), | |||
| CURRENCY("cur"), | |||
| } | |||
| /** Vendor List Request */ | |||
| data class M18VendorListRequest ( | |||
| val stSearch: String = "ven", | |||
| /** M18 Common Master Data Request */ | |||
| data class M18CommonListRequest ( | |||
| val stSearch: String? = null, | |||
| val params: String? = null, | |||
| val conds: String? = null, | |||
| ) | |||
| /** Customer Request */ | |||
| data class M18CustomerRequest ( | |||
| data class M18CommonLineRequest ( | |||
| 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, | |||
| ) | |||
| ) | |||
| @@ -10,16 +10,17 @@ data class M18ErrorMessages ( | |||
| ) | |||
| /** Product / Material Response */ | |||
| data class M18ItemResponse ( | |||
| val data: M18ItemData?, | |||
| data class M18ProductResponse ( | |||
| val data: M18ProductData?, | |||
| val messages: List<M18ErrorMessages>? | |||
| ) | |||
| data class M18ItemData ( | |||
| val pro: List<M18ItemPro>? | |||
| data class M18ProductData ( | |||
| val pro: List<M18ProductPro>?, | |||
| val price: List<M18ProductPrice>? | |||
| ) | |||
| data class M18ItemPro ( | |||
| data class M18ProductPro ( | |||
| val id: Long, | |||
| val code: String, | |||
| val desc: String, | |||
| @@ -28,12 +29,23 @@ data class M18ItemPro ( | |||
| val lastModifyDate: Long, | |||
| ) | |||
| data class M18ProductPrice ( | |||
| val id: Long, | |||
| val hId: Long, | |||
| val unitId: Long, | |||
| val basicUnit: Boolean, | |||
| val saleUnit: Boolean, | |||
| val stkUnit: Boolean, | |||
| val purUnit: Boolean, | |||
| val pickUnit: Boolean, | |||
| ) | |||
| /** Product / Material List Response */ | |||
| data class M18ItemListResponse ( | |||
| val values: List<M18ItemListValue>?, | |||
| data class M18ProductListResponse ( | |||
| val values: List<M18ProductListValue>?, | |||
| ) | |||
| data class M18ItemListValue ( | |||
| data class M18ProductListValue ( | |||
| val id: Long, | |||
| val lastModifyDate: String?, | |||
| ) | |||
| @@ -72,4 +84,67 @@ data class M18VendorListResponse ( | |||
| data class M18VendorListValue ( | |||
| val id: Long, | |||
| val lastModifyDate: String?, | |||
| ) | |||
| /** Unit List Response */ | |||
| data class M18UnitListResponse ( | |||
| val values: List<M18UnitListValue>?, | |||
| ) | |||
| data class M18UnitListValue ( | |||
| val id: Long, | |||
| val lastModifyDate: String?, | |||
| val code: String, | |||
| val udfudesc: String, | |||
| ) | |||
| /** Unit Response */ | |||
| data class M18UnitResponse ( | |||
| val data: List<M18UnitData> | |||
| ) | |||
| data class M18UnitData ( | |||
| val unit: List<M18UnitUnit> | |||
| ) | |||
| data class M18UnitUnit ( | |||
| val id: Long, | |||
| val expiredDate: Long, | |||
| val lastModifyDate: Long, | |||
| val code: String, | |||
| val udfShortDesc: String, | |||
| val udfudesc: String, | |||
| val status: String, | |||
| ) | |||
| /** Currency List Response */ | |||
| data class M18CurrencyListResponse ( | |||
| val values: List<M18CurrencyListValue>?, | |||
| ) | |||
| data class M18CurrencyListValue ( | |||
| val id: Long, | |||
| val lastModifyDate: String?, | |||
| val code: String, | |||
| val sym: String, | |||
| val curDesc: String, | |||
| ) | |||
| /** Currency Response */ | |||
| data class M18CurrencyResponse ( | |||
| val data: List<M18CurrencyData> | |||
| ) | |||
| data class M18CurrencyData ( | |||
| val cur: List<M18CurrencyCur> | |||
| ) | |||
| data class M18CurrencyCur ( | |||
| val id: Long, | |||
| val expiredDate: Long, | |||
| val lastModifyDate: Long, | |||
| val code: String, | |||
| val sym: String, | |||
| val desc: String, | |||
| val status: String, | |||
| ) | |||
| @@ -1,5 +1,6 @@ | |||
| package com.ffii.fpsms.m18.model | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderType | |||
| import java.math.BigDecimal | |||
| import java.time.Instant | |||
| import java.time.LocalDateTime | |||
| @@ -10,7 +11,7 @@ data class M18PurchaseOrderResponse ( | |||
| ) | |||
| data class M18PurchaseOrderData ( | |||
| val mainPo: List<M18PurchaseOrderMainPo>, | |||
| val mainpo: List<M18PurchaseOrderMainPo>, | |||
| val pot: List<M18PurchaseOrderPot> | |||
| ) | |||
| @@ -27,23 +28,35 @@ data class M18PurchaseOrderMainPo ( | |||
| ) | |||
| data class M18PurchaseOrderPot ( | |||
| // Purchase Order Line ID | |||
| val id: Long, | |||
| // Purchase Order ID | |||
| val hId: Long, | |||
| // product ID | |||
| val proId: Long, | |||
| val code: String, | |||
| val desc: String, | |||
| val bDesc: String, | |||
| val unitId: Long, | |||
| val seriesId: Long, | |||
| // val seriesId: Long?, | |||
| val qty: BigDecimal, | |||
| val amt: BigDecimal, | |||
| val curId: Long, | |||
| ) | |||
| /** Purchase Order List Response */ | |||
| data class M18PurchaseOrderListResponseWithType ( | |||
| var valuesWithType: MutableList<Pair<PurchaseOrderType, List<M18PurchaseOrderListValue>?>> | |||
| ) | |||
| data class M18PurchaseOrderListResponse ( | |||
| val values: List<M18PurchaseOrderListValue> | |||
| var values: List<M18PurchaseOrderListValue> | |||
| ) | |||
| data class M18PurchaseOrderListValue ( | |||
| val id: Long, | |||
| val code: String, | |||
| val lastModifyDate: String, | |||
| // Defined by FP-MTMS | |||
| val type: PurchaseOrderType?, | |||
| ) | |||
| @@ -5,16 +5,15 @@ 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.entity.UomConversion | |||
| 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 com.ffii.fpsms.modules.master.service.* | |||
| import com.ffii.fpsms.modules.master.web.models.* | |||
| import org.slf4j.Logger | |||
| import org.slf4j.LoggerFactory | |||
| import org.springframework.stereotype.Service | |||
| import java.time.LocalDate | |||
| import java.time.LocalDateTime | |||
| import java.time.format.DateTimeFormatter | |||
| @Service | |||
| @@ -23,87 +22,129 @@ open class M18MasterDataService( | |||
| val apiCallerService: ApiCallerService, | |||
| val itemsService: ItemsService, | |||
| val shopService: ShopService, | |||
| val uomConversionService: UomConversionService, | |||
| val currencyService: CurrencyService, | |||
| val itemUomService: ItemUomService, | |||
| ) { | |||
| val commonUtils = CommonUtils() | |||
| val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) | |||
| val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") | |||
| // Everyday update the master data | |||
| // M18 Conditions | |||
| 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 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 M18_COMMON_FETCH_LIST_API = "/search/search" | |||
| val M18_COMMON_LOAD_LINE_API = "/root/api/read" | |||
| val M18_LOAD_PRODUCT_API = "${M18_COMMON_LOAD_LINE_API}/${StSearchType.PRODUCT.value}" | |||
| val M18_LOAD_VENDOR_API = "${M18_COMMON_LOAD_LINE_API}/${StSearchType.VENDOR.value}" | |||
| val M18_LOAD_UNIT_API = "${M18_COMMON_LOAD_LINE_API}/${StSearchType.UNIT.value}" | |||
| val M18_LOAD_CURRENCY_API = "${M18_COMMON_LOAD_LINE_API}/${StSearchType.CURRENCY.value}" | |||
| // --------------------------------------------- Common Function --------------------------------------------- /// | |||
| private inline fun <reified T : Any> getList( | |||
| stSearch: String?, | |||
| params: String? = null, | |||
| conds: String? = null, | |||
| ): T? { | |||
| val request = M18CommonListRequest( | |||
| stSearch = stSearch, | |||
| params = params, | |||
| conds = conds | |||
| ) | |||
| val items = apiCallerService.get<M18ItemListResponse, M18ItemListRequest>( | |||
| M18_FETCH_ITEM_LIST_API, | |||
| itemsParams | |||
| val response = apiCallerService.get<T, M18CommonListRequest>( | |||
| M18_COMMON_FETCH_LIST_API, | |||
| request | |||
| ).block() | |||
| return items | |||
| return response | |||
| } | |||
| open fun getItem(id: Long): M18ItemResponse? { | |||
| logger.info("M18 Item ID: $id") | |||
| val itemParams = M18ItemRequest( | |||
| private inline fun <reified T : Any> getLine( | |||
| id: Long, | |||
| params: String?, | |||
| api: String, | |||
| ): T? { | |||
| val request = M18CommonLineRequest( | |||
| id = id, | |||
| params = null, | |||
| params = params, | |||
| ) | |||
| val item = apiCallerService.get<M18ItemResponse, M18ItemRequest>( | |||
| M18_LOAD_ITEM_API, | |||
| itemParams | |||
| val response = apiCallerService.get<T, M18CommonLineRequest>( | |||
| api, | |||
| request | |||
| ).block() | |||
| return item | |||
| return response | |||
| } | |||
| // --------------------------------------------- Product --------------------------------------------- /// | |||
| open fun getProducts(): M18ProductListResponse? { | |||
| // seems no beId | |||
| return getList<M18ProductListResponse>( | |||
| stSearch = StSearchType.PRODUCT.value, | |||
| params = null, | |||
| conds = seriesIdConds | |||
| ) | |||
| // val itemsParams = M18CommonListRequest( | |||
| // stSearch = StSearchType.PRODUCT.value, | |||
| // params = null, | |||
| // conds = seriesIdConds | |||
| // ) | |||
| // | |||
| // val items = apiCallerService.get<M18ProductListResponse, M18CommonListRequest>( | |||
| // M18_COMMON_FETCH_LIST_API, | |||
| // itemsParams | |||
| // ).block() | |||
| // | |||
| // return items | |||
| } | |||
| open fun saveItems() { | |||
| open fun getProduct(id: Long): M18ProductResponse? { | |||
| logger.info("M18 Product ID: $id") | |||
| return getLine<M18ProductResponse>( | |||
| id = id, | |||
| params = null, | |||
| api = M18_LOAD_PRODUCT_API | |||
| ) | |||
| } | |||
| val items = getItems() | |||
| val exampleItems = listOf<Long>(10946L, 3825L) | |||
| open fun saveProducts() { | |||
| logger.info("--------------------------------------------Start - Saving M18 Products / Materials--------------------------------------------") | |||
| val items = getProducts() | |||
| val exampleProducts = 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) { | |||
| val values = items?.values?.sortedBy { it.id } | |||
| if (values != null) { | |||
| values.forEach { item -> | |||
| // if (item.id in exampleProducts) { | |||
| try { | |||
| val itemDetail = getItem(item.id) | |||
| if (itemDetail != null && itemDetail.data?.pro != null) { | |||
| val pro = itemDetail.data.pro[0] | |||
| val itemDetail = getProduct(item.id) | |||
| val pro = itemDetail?.data?.pro?.get(0) | |||
| val price = itemDetail?.data?.price | |||
| if (itemDetail != null && pro != null) { | |||
| val existingItem = itemsService.findByM18Id(item.id) | |||
| val saveItemRequest = NewItemRequest( | |||
| code = pro.code, | |||
| name = pro.desc, | |||
| // type = if (pro.seriesId == m18Config.SERIESID_PF) ItemType.MATERIAL | |||
| // type = if (pro.seriesId == m18Config.SERIESID_PF) ProductType.MATERIAL | |||
| // else ItemType.PRODUCT, | |||
| type = ItemType.MATERIAL, | |||
| id = null, | |||
| id = existingItem?.id, | |||
| description = pro.desc, | |||
| remarks = null, | |||
| shelfLife = null, | |||
| @@ -113,108 +154,95 @@ open class M18MasterDataService( | |||
| m18LastModifyDate = commonUtils.InstantToLocalDateTime(pro.lastModifyDate) | |||
| ) | |||
| itemsService.saveItem(saveItemRequest) | |||
| val savedItem = itemsService.saveItem(saveItemRequest) | |||
| logger.info("Processing item uom...") | |||
| // Find the item uom that ready to delete (not in m18) | |||
| val existingItemUoms = savedItem.id?.let { itemUomService.findAllByItemsId(it) } | |||
| val m18ItemUomIds = price?.map { it.id } ?: listOf() | |||
| // Delete the item uom | |||
| logger.info("Deleting item uom...") | |||
| existingItemUoms?.filter { deleteItemUom -> | |||
| m18ItemUomIds.any { it != deleteItemUom.m18Id } | |||
| }?.mapNotNull { it.id }?.let { itemUomService.deleteItemUoms(it) } | |||
| // Update the item uom | |||
| logger.info("Updating item uom...") | |||
| price?.forEach { | |||
| val itemUomRequest = ItemUomRequest( | |||
| m18UomId = it.unitId, | |||
| itemId = savedItem.id, | |||
| baseUnit = it.basicUnit, | |||
| stockUnit = it.stkUnit, | |||
| pickingUnit = it.pickUnit, | |||
| salesUnit = it.saleUnit, | |||
| purchaseUnit = it.purUnit, | |||
| price = null, | |||
| currencyId = null, | |||
| m18Id = it.id, | |||
| m18LastModifyDate = commonUtils.InstantToLocalDateTime(pro.lastModifyDate) | |||
| ) | |||
| logger.info("saved item id: ${savedItem.id}") | |||
| itemUomService.saveItemUom(itemUomRequest) | |||
| } | |||
| 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") | |||
| 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") | |||
| logger.error("Exception") | |||
| logger.error("Fail Message: ${e.message}") | |||
| logger.error("Fail Count ${failList.size}: Item ID - ${item.id}") | |||
| } | |||
| // 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") | |||
| logger.info("Total Success (${successList.size})") | |||
| if (failList.size > 0) { | |||
| logger.error("Total Fail (${failList.size}): $failList") | |||
| } | |||
| logger.info("--------------------------------------------End - Saving M18 Products / Materials--------------------------------------------") | |||
| } | |||
| // --------------------------------------------- Vendor --------------------------------------------- /// | |||
| open fun getVendors(): M18VendorListResponse? { | |||
| val vendorsParams = M18VendorListRequest( | |||
| return getList<M18VendorListResponse>( | |||
| stSearch = StSearchType.VENDOR.value, | |||
| 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( | |||
| return getLine<M18VendorResponse>( | |||
| id = id, | |||
| params = null, | |||
| api = M18_LOAD_VENDOR_API | |||
| ) | |||
| val vendor = apiCallerService.get<M18VendorResponse, M18VendorRequest>( | |||
| M18_LOAD_VENDOR_API, | |||
| vendorParams | |||
| ).block() | |||
| return vendor | |||
| } | |||
| open fun saveVendors() { | |||
| logger.info("--------------------------------------------Start - Saving M18 Vendors--------------------------------------------") | |||
| val vendors = getVendors() | |||
| val exampleVendors = listOf<Long>(191L) | |||
| val successList = mutableListOf<Long>() | |||
| val failList = mutableListOf<Long>() | |||
| val values = vendors?.values?.sortedBy { it.id } | |||
| if (vendors?.values != null) { | |||
| vendors.values.forEach { vendor -> | |||
| if (values != null) { | |||
| values.forEach { vendor -> | |||
| // if (vendor.id in exampleVendors) { | |||
| try { | |||
| val vendorDetail = getVendor(vendor.id) | |||
| @@ -246,23 +274,170 @@ open class M18MasterDataService( | |||
| } 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") | |||
| 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") | |||
| logger.error("Exception") | |||
| logger.error("Fail Message: ${e.message}") | |||
| logger.error("Fail Count ${failList.size}: Vendor ID - ${vendor.id}") | |||
| } | |||
| // } | |||
| } | |||
| } else { | |||
| logger.error("Items List is null. May occur errors.") | |||
| logger.error("Vendor List is null. May occur errors.") | |||
| } | |||
| logger.info("Total Success (${successList.size}): $successList") | |||
| logger.info("Total Success (${successList.size})") | |||
| if (failList.size > 0) { | |||
| logger.error("Total Fail (${failList.size}): $failList") | |||
| } | |||
| logger.info("--------------------------------------------End - Saving M18 Vendors--------------------------------------------") | |||
| } | |||
| // --------------------------------------------- Unit --------------------------------------------- /// | |||
| open fun getUnits(): M18UnitListResponse? { | |||
| // seems no beId | |||
| return getList<M18UnitListResponse>( | |||
| stSearch = StSearchType.UNIT.value, | |||
| params = null, | |||
| conds = null | |||
| ) | |||
| } | |||
| open fun getUnit(id: Long): M18UnitResponse? { | |||
| logger.info("M18 Unit ID: $id") | |||
| return getLine<M18UnitResponse>( | |||
| id = id, | |||
| params = null, | |||
| api = M18_LOAD_UNIT_API | |||
| ) | |||
| } | |||
| open fun saveUnits() { | |||
| logger.info("--------------------------------------------Start - Saving M18 Units--------------------------------------------") | |||
| val units = getUnits() | |||
| val successTransformList = mutableListOf<Long>() | |||
| val successSaveList = mutableListOf<Long>() | |||
| val failTransformList = mutableListOf<Long>() | |||
| val failSaveList = mutableListOf<Long>() | |||
| val values = units?.values?.sortedBy { it.id } | |||
| if (values != null) { | |||
| val finalUnitList = arrayListOf<UomConversion>() | |||
| // transform unit | |||
| values.forEach { unit -> | |||
| try { | |||
| val tempObject = UomConversionService.BomObject().apply { | |||
| code = unit.code | |||
| udfudesc = unit.udfudesc | |||
| lastModifyDate = unit.lastModifyDate | |||
| id = unit.id | |||
| } | |||
| finalUnitList += uomConversionService.transformItem(tempObject) | |||
| successTransformList += unit.id | |||
| logger.info("Transform Success (M18): ${unit.id}") | |||
| } catch (e: Exception) { | |||
| failTransformList.add(unit.id) | |||
| logger.error("Transform Exception") | |||
| logger.error("Transform Fail Message: ${e.message}") | |||
| logger.error("Transform Fail Count ${failTransformList.size}: Unit ID - ${unit.id}") | |||
| } | |||
| } | |||
| uomConversionService.calculateSizeInGram(finalUnitList) | |||
| finalUnitList.forEach { | |||
| try { | |||
| uomConversionService.saveUomConversion(it) | |||
| successSaveList += it.m18Id | |||
| logger.info("Save Success (M18): ${it.m18Id}") | |||
| } catch (e: Exception) { | |||
| failSaveList.add(it.m18Id) | |||
| logger.error("Save Exception") | |||
| logger.error("Save Fail Message: ${e.message}") | |||
| logger.error("Save Fail Count ${failTransformList.size}: Unit ID - ${it.m18Id}") | |||
| } | |||
| } | |||
| } else { | |||
| logger.error("Unit List is null. May occur errors.") | |||
| } | |||
| logger.info("Total Transform Success (${successTransformList.size})") | |||
| logger.info("Total Save Success (${successSaveList.size})") | |||
| if (failTransformList.size > 0) { | |||
| logger.error("Total Transform Fail (${failTransformList.size}): $failTransformList") | |||
| } | |||
| if (failSaveList.size > 0) { | |||
| logger.error("Total Save Fail (${failSaveList.size}): $failSaveList") | |||
| } | |||
| logger.info("--------------------------------------------End - Saving M18 Units--------------------------------------------") | |||
| } | |||
| // --------------------------------------------- Currency --------------------------------------------- /// | |||
| open fun getCurrencies(): M18CurrencyListResponse? { | |||
| return getList<M18CurrencyListResponse>( | |||
| stSearch = StSearchType.CURRENCY.value, | |||
| params = null, | |||
| conds = null | |||
| ) | |||
| } | |||
| open fun getCurrency(id: Long): M18CurrencyResponse? { | |||
| logger.info("M18 Currency ID: $id") | |||
| return getLine<M18CurrencyResponse>( | |||
| id = id, | |||
| params = null, | |||
| api = M18_LOAD_CURRENCY_API | |||
| ) | |||
| } | |||
| open fun saveCurrencies() { | |||
| logger.info("--------------------------------------------Start - Saving M18 Currencies--------------------------------------------") | |||
| val currencies = getCurrencies() | |||
| val successList = mutableListOf<Long>() | |||
| val failList = mutableListOf<Long>() | |||
| val values = currencies?.values?.sortedBy { it.id } | |||
| if (values != null) { | |||
| // save currency | |||
| values.forEach { currency -> | |||
| try { | |||
| val currencyRequest = CurrencyRequest( | |||
| id = null, | |||
| code = currency.code, | |||
| name = currency.sym, | |||
| description = currency.curDesc, | |||
| m18Id = currency.id, | |||
| m18LastModifyDate = LocalDateTime.parse(currency.lastModifyDate, formatter) | |||
| ) | |||
| currencyService.saveCurrency(currencyRequest) | |||
| successList += currency.id | |||
| logger.info("Save Success (M18): ${currency.id}") | |||
| } catch (e: Exception) { | |||
| failList += currency.id | |||
| logger.error("Exception") | |||
| logger.error("Fail Message: ${e.message}") | |||
| logger.error("Fail Count ${failList.size}: Unit ID - ${currency.id}") | |||
| } | |||
| } | |||
| } else { | |||
| logger.error("Currency List is null. May occur errors.") | |||
| } | |||
| logger.info("Total Save Success (${successList.size})") | |||
| if (failList.size > 0) { | |||
| logger.error("Total Fail (${failList.size}): $failList") | |||
| } | |||
| logger.info("--------------------------------------------End - Saving Currencies--------------------------------------------") | |||
| } | |||
| } | |||
| @@ -9,6 +9,7 @@ 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.enums.PurchaseOrderType | |||
| 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 | |||
| @@ -16,7 +17,6 @@ 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 | |||
| @@ -30,28 +30,81 @@ open class M18PurchaseOrderService( | |||
| val itemsService: ItemsService, | |||
| val shopService: ShopService, | |||
| ) { | |||
| val dateTimeConverter = CommonUtils() | |||
| val commonUtils = 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}" | |||
| val lastModifyDate = LocalDateTime.now().minusMinutes(30) | |||
| // val commonConds = | |||
| // "(beId=equal=${m18Config.BEID_PF}=or=beId=equal=${m18Config.BEID_PP}=or=beId=equal=${m18Config.BEID_TOA})=and=lastModifyDate=largerOrEqual=${lastModifyDate}" | |||
| // 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( | |||
| // Include material po, shop po, oem po | |||
| open fun getPurchaseOrdersWithType(): M18PurchaseOrderListResponseWithType? { | |||
| val purchaseOrders = M18PurchaseOrderListResponseWithType(mutableListOf()) | |||
| // Material PO | |||
| val materialPoBuyers = | |||
| commonUtils.ListToString(listOf(m18Config.BEID_PP, m18Config.BEID_PF), "beId=equal=", "=or=") | |||
| val materialPoSupplierNot = "venId=unequal=${m18Config.MATERIAL_PO_SUPPLIER_NOT}" | |||
| val materialPoConds = "${materialPoBuyers}=and=${materialPoSupplierNot}" | |||
| val materialPoParams = M18PurchaseOrderListRequest( | |||
| params = null, | |||
| conds = commonConds | |||
| conds = materialPoConds | |||
| ) | |||
| var purchaseOrders: M18PurchaseOrderListResponse? = null | |||
| try { | |||
| purchaseOrders = apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>( | |||
| M18_FETCH_PURCHASE_ORDER_LIST_API, | |||
| purchaseOrdersParams | |||
| ).block() | |||
| purchaseOrders.valuesWithType += Pair( | |||
| PurchaseOrderType.MATERIAL, | |||
| apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>( | |||
| M18_FETCH_PURCHASE_ORDER_LIST_API, | |||
| materialPoParams | |||
| ).block()?.values ?: mutableListOf() | |||
| ) | |||
| } catch (e: Exception) { | |||
| logger.error("Error on Function - ${e.stackTrace}") | |||
| logger.error(e.message) | |||
| } | |||
| // Shop PO | |||
| val shopPoBuyers = commonUtils.ListToString(listOf(m18Config.BEID_TOA), "beId=equal=", "=or=") | |||
| val shopPoSupplier = "venId=equal=${m18Config.SHOP_PO_SUPPLIER}" | |||
| val shopPoConds = "${shopPoBuyers}=and=${shopPoSupplier}" | |||
| val shopPoParams = M18PurchaseOrderListRequest( | |||
| params = null, | |||
| conds = shopPoConds | |||
| ) | |||
| try { | |||
| purchaseOrders.valuesWithType += Pair( | |||
| PurchaseOrderType.SHOP, apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>( | |||
| M18_FETCH_PURCHASE_ORDER_LIST_API, | |||
| shopPoParams | |||
| ).block()?.values ?: mutableListOf() | |||
| ) | |||
| } catch (e: Exception) { | |||
| logger.error("Error on Function - ${e.stackTrace}") | |||
| logger.error(e.message) | |||
| } | |||
| // OEM PO | |||
| val oemPoBuyers = commonUtils.ListToString(listOf(m18Config.BEID_PF, m18Config.BEID_PP), "beId=equal=", "=or=") | |||
| val oemPoSupplier = "venId=equal=${m18Config.OEM_PO_SUPPLIER}" | |||
| val oemPoConds = "${oemPoBuyers}=and=${oemPoSupplier}" | |||
| val oemPoParams = M18PurchaseOrderListRequest( | |||
| params = null, | |||
| conds = oemPoConds | |||
| ) | |||
| try { | |||
| purchaseOrders.valuesWithType += Pair( | |||
| PurchaseOrderType.OEM, apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>( | |||
| M18_FETCH_PURCHASE_ORDER_LIST_API, | |||
| oemPoParams | |||
| ).block()?.values | |||
| ) | |||
| } catch (e: Exception) { | |||
| logger.error("Error on Function - ${e.stackTrace}") | |||
| logger.error(e.message) | |||
| @@ -81,7 +134,8 @@ open class M18PurchaseOrderService( | |||
| } | |||
| open fun savePurchaseOrders() { | |||
| val purchaseOrders = getPurchaseOrders() | |||
| logger.info("--------------------------------------------Start - Saving M18 Purchase Order--------------------------------------------") | |||
| val purchaseOrdersWithType = getPurchaseOrdersWithType() | |||
| val examplePurchaseOrders = listOf<Long>(4764034L) | |||
| val successList = mutableListOf<Long>() | |||
| @@ -89,180 +143,235 @@ open class M18PurchaseOrderService( | |||
| val failList = mutableListOf<Long>() | |||
| val failDetailList = mutableListOf<Long>() | |||
| if (purchaseOrders != null) { | |||
| val poRefType = "Purchase Order" | |||
| val poLineRefType = "Purchase Order Line" | |||
| if (purchaseOrdersWithType != 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) | |||
| } | |||
| purchaseOrdersWithType.valuesWithType.forEach { purchaseOrderWithType -> | |||
| val type = purchaseOrderWithType.first | |||
| val purchaseOrders = purchaseOrderWithType.second | |||
| if (purchaseOrders != null) { | |||
| purchaseOrders.forEach { purchaseOrder -> | |||
| val purchaseOrderDetail = getPurchaseOrder(purchaseOrder.id) | |||
| // purchase_order_line + m18_data_log | |||
| if (pot != null) { | |||
| // Loop for Purchase Order Lines (pot) | |||
| pot.forEach { line -> | |||
| val poLineRefType = "Purchase Order Line" | |||
| 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) { | |||
| // Find the latest m18 data log by m18 id & type | |||
| val latestM18DataLog = m18DataLogService.findLatestM18DataLog(line.id, poLineRefType) | |||
| logger.info("${poRefType}: Finding For Latest M18 Data Log...") | |||
| val latestPurchaseOrderLog = | |||
| m18DataLogService.findLatestM18DataLog(purchaseOrder.id, poRefType) | |||
| // logger.info("${poRefType}: Latest M18 Data Log ID: ${latestPurchaseOrderLog?.id}") | |||
| // Save to m18_data_log table | |||
| val lineJson = | |||
| line::class.memberProperties.associate { prop -> prop.name to prop.getter.call(line) } | |||
| logger.info("${poRefType}: Saving for M18 Data Log...") | |||
| val mainpoJson = | |||
| mainpo::class.memberProperties.associate { prop -> prop.name to prop.getter.call(mainpo) } | |||
| .toMutableMap() | |||
| val saveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( | |||
| val saveM18PurchaseOrderLogRequest = SaveM18DataLogRequest( | |||
| id = null, | |||
| refType = poLineRefType, | |||
| m18Id = line.id, | |||
| m18LastModifyDate = dateTimeConverter.InstantToLocalDateTime(mainPo.lastModifyDate), | |||
| dataLog = lineJson, | |||
| refType = poRefType, | |||
| m18Id = purchaseOrder.id, | |||
| m18LastModifyDate = commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate), | |||
| dataLog = mainpoJson, | |||
| status = true | |||
| ) | |||
| val saveM18PurchaseOrderLineLog = m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLineLogRequest) | |||
| val item = itemsService.findByM18Id(line.id) | |||
| logger.info("Item ID: ${item?.id}") | |||
| val saveM18PurchaseOrderLog = | |||
| m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLogRequest) | |||
| // logger.info("${poRefType}: Saved M18 Data Log. ID: ${saveM18PurchaseOrderLog.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, | |||
| // Find the purchase_order if exist | |||
| logger.info("${poRefType}: Finding exising purchase order...") | |||
| val existingPurchaseOrder = | |||
| latestPurchaseOrderLog?.id?.let { purchaseOrderService.findPurchaseOrderByM18Id(it) } | |||
| logger.info("${poRefType}: Exising purchase order ID: ${existingPurchaseOrder?.id}") | |||
| // Save to purchase_order table | |||
| logger.info("${poRefType}: Saving purchase order...") | |||
| val supplierId = shopService.findByM18Id(mainpo.venId)?.id | |||
| val savePurchaseOrderRequest = SavePurchaseOrderRequest( | |||
| id = existingPurchaseOrder?.id, | |||
| code = mainpo.code, | |||
| supplierId = supplierId, | |||
| orderDate = commonUtils.InstantToLocalDateTime(mainpo.tDate), | |||
| estimatedArrivalDate = commonUtils.InstantToLocalDateTime(mainpo.dDate), | |||
| completeDate = null, | |||
| status = PurchaseOrderStatus.PENDING.value, | |||
| type = type.value, | |||
| m18DataLogId = saveM18PurchaseOrderLog.id, | |||
| ) | |||
| purchaseOrderLineService.savePurchaseOrderLine(savePurchaseOrderLineRequest) | |||
| val savePurchaseOrderResponse = | |||
| purchaseOrderService.savePurchaseOrder(savePurchaseOrderRequest) | |||
| purchaseOrderId = savePurchaseOrderResponse.id | |||
| successList.add(purchaseOrder.id) | |||
| logger.info("${poRefType}: Saved purchase order. ID: ${savePurchaseOrderResponse.id} | M18 ${poRefType} ID: ${purchaseOrder.id}") | |||
| } catch (e: Exception) { | |||
| failDetailList.add(line.id) | |||
| logger.error("Error on Function - ${e.stackTrace} | Type: Purchase Order Line | M18 ID: ${line.id}") | |||
| failList.add(purchaseOrder.id) | |||
| logger.error("${poRefType}: Saving Failure!") | |||
| logger.error("Error on Function - ${e.stackTrace} | Type: ${poRefType} | M18 ID: ${purchaseOrder.id} | Different? ${mainpo.id}") | |||
| logger.error(e.message) | |||
| val errorSaveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( | |||
| id = saveM18PurchaseOrderLineLog.id, | |||
| refType = "Purchase Order", | |||
| m18Id = line.id, | |||
| m18LastModifyDate = dateTimeConverter.InstantToLocalDateTime(mainPo.lastModifyDate), | |||
| dataLog = lineJson, | |||
| val errorSaveM18PurchaseOrderLogRequest = SaveM18DataLogRequest( | |||
| id = saveM18PurchaseOrderLogRequest.id, | |||
| refType = poRefType, | |||
| m18Id = purchaseOrder.id, | |||
| m18LastModifyDate = commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate), | |||
| dataLog = mainpoJson, | |||
| status = false | |||
| ) | |||
| m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLineLogRequest) | |||
| m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLogRequest) | |||
| logger.error("${poRefType}: M18 Data Log Updated! Please see the error. ID: ${saveM18PurchaseOrderLogRequest.id}") | |||
| } | |||
| // purchase_order_line + m18_data_log | |||
| if (pot != null) { | |||
| // Loop for Purchase Order Lines (pot) | |||
| pot.forEach { line -> | |||
| // // Find the latest m18 data log by m18 id & type | |||
| logger.info("${poLineRefType}: Finding For Latest M18 Data Log...") | |||
| val latestPurchaseOrderLineLog = | |||
| m18DataLogService.findLatestM18DataLog(line.id, poLineRefType) | |||
| // logger.info("${poLineRefType}: Latest M18 Data Log ID: ${latestPurchaseOrderLineLog?.id}") | |||
| // Save to m18_data_log table | |||
| logger.info("${poLineRefType}: Saving for M18 Data Log...") | |||
| 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 = commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate), | |||
| dataLog = lineJson, | |||
| status = true | |||
| ) | |||
| val saveM18PurchaseOrderLineLog = | |||
| m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLineLogRequest) | |||
| // logger.info("${poLineRefType}: Saved M18 Data Log. ID: ${saveM18PurchaseOrderLineLog.id}") | |||
| logger.info("${poLineRefType}: Finding item...") | |||
| val item = itemsService.findByM18Id(line.proId) | |||
| logger.info("${poLineRefType}: Item ID: ${item?.id} | M18 Item ID: ${line.proId}") | |||
| try { | |||
| // Find the purchase_order_line if exist | |||
| logger.info("${poLineRefType}: Finding exising purchase order line...") | |||
| val existingPurchaseOrderLine = latestPurchaseOrderLineLog?.id?.let { | |||
| purchaseOrderLineService.findPurchaseOrderLineByM18Id(it) | |||
| } | |||
| logger.info("${poLineRefType}: Exising purchase order line ID: ${existingPurchaseOrderLine?.id}") | |||
| // Save to purchase_order_line table | |||
| logger.info("${poLineRefType}: Saving purchase order line...") | |||
| val lineUom = | |||
| val savePurchaseOrderLineRequest = SavePurchaseOrderLineRequest( | |||
| id = existingPurchaseOrderLine?.id, | |||
| itemId = item?.id, | |||
| uomId = null, | |||
| purchaseOrderId = purchaseOrderId, | |||
| qty = line.qty, | |||
| price = line.amt, | |||
| m18CurrencyId = line.curId, | |||
| status = existingPurchaseOrderLine?.status?.value | |||
| ?: PurchaseOrderLineStatus.PENDING.value, | |||
| m18DataLogId = saveM18PurchaseOrderLineLog.id, | |||
| ) | |||
| val savePurchaseOrderLineResponse = | |||
| purchaseOrderLineService.savePurchaseOrderLine(savePurchaseOrderLineRequest) | |||
| logger.info("${poLineRefType}: Purchase order ID: ${purchaseOrderId} | M18 ID: ${purchaseOrder.id}") | |||
| logger.info("${poLineRefType}: Saved purchase order line. ID: ${savePurchaseOrderLineResponse.id} | M18 Line ID: ${line.id}") | |||
| } catch (e: Exception) { | |||
| failDetailList.add(line.id) | |||
| logger.error("${poLineRefType}: Saving Failure!") | |||
| logger.error("Error on Function - ${e.stackTrace} | Type: ${poLineRefType} | M18 ID: ${line.id}") | |||
| logger.error(e.message) | |||
| val errorSaveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( | |||
| id = saveM18PurchaseOrderLineLog.id, | |||
| refType = "${poRefType}", | |||
| m18Id = line.id, | |||
| m18LastModifyDate = commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate), | |||
| dataLog = lineJson, | |||
| status = false | |||
| ) | |||
| m18DataLogService.saveM18DataLog(errorSaveM18PurchaseOrderLineLogRequest) | |||
| logger.error("${poLineRefType}: M18 Data Log Updated! Please see the error. ID: ${saveM18PurchaseOrderLineLog.id}") | |||
| } | |||
| } | |||
| } else { | |||
| // pot | |||
| logger.error("${poLineRefType}: Saving Failure!") | |||
| val saveM18PurchaseOrderLineLogRequest = SaveM18DataLogRequest( | |||
| id = null, | |||
| refType = "${poLineRefType}", | |||
| m18Id = purchaseOrder.id, | |||
| m18LastModifyDate = commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate), | |||
| dataLog = mutableMapOf(Pair("Error Message", "${poLineRefType} is null")), | |||
| status = false | |||
| ) | |||
| val errorLog = m18DataLogService.saveM18DataLog(saveM18PurchaseOrderLineLogRequest) | |||
| logger.error("${poLineRefType}: M18 Data Log Updated! Please see the error. ID: ${errorLog.id}") | |||
| } | |||
| } else { | |||
| // mainpo | |||
| logger.error("${poRefType}: Saving Failure!") | |||
| val saveM18DataLogRequest = SaveM18DataLogRequest( | |||
| id = null, | |||
| refType = "${poRefType}", | |||
| m18Id = purchaseOrder.id, | |||
| // m18LastModifyDate = if(mainpo?.lastModifyDate != null) commonUtils.InstantToLocalDateTime(mainpo.lastModifyDate) else LocalDateTime.now(), | |||
| m18LastModifyDate = LocalDateTime.now(), | |||
| dataLog = mutableMapOf(Pair("Error Message", "${poRefType} is null")), | |||
| status = false | |||
| ) | |||
| val errorLog = m18DataLogService.saveM18DataLog(saveM18DataLogRequest) | |||
| logger.error("${poLineRefType}: M18 Data Log Updated! Please see the error. ID: ${errorLog.id}") | |||
| } | |||
| } 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) | |||
| logger.error("${poRefType} List is null. May occur errors.") | |||
| } | |||
| } | |||
| } else { | |||
| logger.error("Purchase Order List is null. May occur errors.") | |||
| logger.error("${poRefType} List is null. May occur errors.") | |||
| } | |||
| // End of save. Check result | |||
| logger.info("Total Success (Purchase Order) (${successList.size}): $successList") | |||
| logger.info("Total Success (${poRefType}) (${successList.size}): $successList") | |||
| if (failList.size > 0) { | |||
| logger.error("Total Fail (Purchase Order) (${failList.size}): $failList") | |||
| logger.error("Total Fail (${poRefType}) (${failList.size}): $failList") | |||
| } | |||
| logger.info("Total Success (Purchase Order Line) (${successDetailList.size}): $successDetailList") | |||
| logger.info("Total Success (${poLineRefType}) (${successDetailList.size}): $successDetailList") | |||
| if (failDetailList.size > 0) { | |||
| logger.error("Total Fail (Purchase Order Line) (${failDetailList.size}): $failDetailList") | |||
| logger.error("Total Fail (${poLineRefType}) (${failDetailList.size}): $failDetailList") | |||
| } | |||
| logger.info("--------------------------------------------End - Saving M18 Purchase Order--------------------------------------------") | |||
| } | |||
| } | |||
| @@ -15,7 +15,7 @@ open class M18TokenService( | |||
| private val m18Config: M18Config | |||
| ) { | |||
| @Bean | |||
| // @Bean | |||
| fun run() { | |||
| // val params: MutableMap<String, String> = mutableMapOf( | |||
| // "grant_type" to m18Config.GRANT_TYPE, | |||
| @@ -7,8 +7,8 @@ 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("ZoneId: ${ZoneId.systemDefault()}") | |||
| // println("ZoneId: ${ZoneId.of("Asia/Hong_Kong")}") | |||
| println("Timestamp: $timestamp") | |||
| println("Local Date Time: $localDateTime") | |||
| return localDateTime | |||
| @@ -4,27 +4,45 @@ import com.ffii.core.utils.JwtTokenUtil | |||
| import com.ffii.fpsms.m18.M18Config | |||
| import com.ffii.fpsms.m18.service.M18MasterDataService | |||
| import com.ffii.fpsms.m18.service.M18PurchaseOrderService | |||
| import com.ffii.fpsms.modules.master.entity.Shop | |||
| import com.ffii.fpsms.modules.master.entity.ShopRepository | |||
| import com.ffii.fpsms.modules.master.entity.projections.SearchId | |||
| import com.ffii.fpsms.modules.master.enums.ShopType | |||
| import com.ffii.fpsms.modules.master.service.ShopService | |||
| 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.RequestParam | |||
| import org.springframework.web.bind.annotation.RestController | |||
| @RestController | |||
| @RequestMapping("/m18") | |||
| class M18TestController ( | |||
| private val shopRepository: ShopRepository, | |||
| private val shopService: ShopService, | |||
| private val m18MasterDataService: M18MasterDataService, | |||
| private val m18PurchaseOrderService: M18PurchaseOrderService, | |||
| private val m18Config: M18Config, | |||
| ) { | |||
| var logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java) | |||
| @GetMapping("/test1") | |||
| fun test1(): List<Long>? { | |||
| return shopService.findVendorIdsByCodeRegexp(listOf("P06", "P07")) | |||
| } | |||
| @GetMapping("/test2") | |||
| fun test2(): List<Long>? { | |||
| return shopRepository.findIdsByCodeRegexpAndTypeAndDeletedIsFalse("P06|P07", ShopType.SUPPLIER.value) | |||
| } | |||
| // --------------------------------------------- Master Data --------------------------------------------- /// | |||
| @GetMapping("/item") | |||
| fun m18Items() { | |||
| @GetMapping("/product") | |||
| fun m18Products() { | |||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||
| m18MasterDataService.saveItems() | |||
| m18MasterDataService.saveProducts() | |||
| } | |||
| @GetMapping("/vendor") | |||
| @@ -33,6 +51,18 @@ class M18TestController ( | |||
| m18MasterDataService.saveVendors() | |||
| } | |||
| @GetMapping("/unit") | |||
| fun m18Unit() { | |||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||
| m18MasterDataService.saveUnits() | |||
| } | |||
| @GetMapping("/currency") | |||
| fun m18Currency() { | |||
| logger.info("Access token: ${m18Config.ACCESS_TOKEN}") | |||
| m18MasterDataService.saveCurrencies() | |||
| } | |||
| // --------------------------------------------- Purchase Order --------------------------------------------- /// | |||
| @GetMapping("/po") | |||
| fun m18PO() { | |||
| @@ -0,0 +1,34 @@ | |||
| package com.ffii.fpsms.modules.master.entity | |||
| import com.ffii.core.entity.BaseEntity | |||
| import jakarta.persistence.Column | |||
| 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 = "currency") | |||
| open class Currency : BaseEntity<Long>() { | |||
| @Size(max = 30) | |||
| @NotNull | |||
| @Column(name = "code", nullable = false, length = 30) | |||
| open var code: String? = null | |||
| @Size(max = 30) | |||
| @NotNull | |||
| @Column(name = "name", nullable = false, length = 30) | |||
| open var name: String? = null | |||
| @Size(max = 100) | |||
| @NotNull | |||
| @Column(name = "description", nullable = false, length = 100) | |||
| open var description: String? = null | |||
| @Column(name = "m18Id") | |||
| open var m18Id: Long? = null | |||
| @Column(name = "m18LastModifyDate") | |||
| open var m18LastModifyDate: LocalDateTime? = null | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| package com.ffii.fpsms.modules.master.entity | |||
| import com.ffii.core.support.AbstractRepository | |||
| import org.springframework.stereotype.Repository | |||
| @Repository | |||
| interface CurrencyRepository: AbstractRepository<Currency, Long> { | |||
| fun findByIdAndDeletedIsFalse (id: Long): Currency? | |||
| fun findByM18IdAndDeletedIsFalse (m18Id: Long): Currency? | |||
| } | |||
| @@ -0,0 +1,55 @@ | |||
| package com.ffii.fpsms.modules.master.entity | |||
| import com.ffii.core.entity.BaseEntity | |||
| import jakarta.persistence.* | |||
| import jakarta.validation.constraints.NotNull | |||
| import java.math.BigDecimal | |||
| import java.time.LocalDateTime | |||
| @Entity | |||
| @Table(name = "item_uom") | |||
| open class ItemUom : BaseEntity<Long>() { | |||
| @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 = "itemId", nullable = false) | |||
| open var item: Items? = null | |||
| @NotNull | |||
| @Column(name = "baseUnit", nullable = false) | |||
| open var baseUnit: Boolean? = null | |||
| @NotNull | |||
| @Column(name = "stockUnit", nullable = false) | |||
| open var stockUnit: Boolean? = null | |||
| @NotNull | |||
| @Column(name = "pickingUnit", nullable = false) | |||
| open var pickingUnit: Boolean? = null | |||
| @NotNull | |||
| @Column(name = "salesUnit", nullable = false) | |||
| open var salesUnit: Boolean? = null | |||
| @NotNull | |||
| @Column(name = "purchaseUnit", nullable = false) | |||
| open var purchaseUnit: Boolean? = null | |||
| @Column(name = "price", precision = 14, scale = 2) | |||
| open var price: BigDecimal? = null | |||
| @ManyToOne(fetch = FetchType.LAZY) | |||
| @JoinColumn(name = "currencyId") | |||
| open var currency: Currency? = null | |||
| @NotNull | |||
| @Column(name = "m18Id", nullable = false) | |||
| open var m18Id: Long? = null | |||
| @Column(name = "m18LastModifyDate") | |||
| open var m18LastModifyDate: LocalDateTime? = null | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| package com.ffii.fpsms.modules.master.entity | |||
| import com.ffii.core.support.AbstractRepository | |||
| import org.springframework.stereotype.Repository | |||
| import java.io.Serializable | |||
| @Repository | |||
| interface ItemUomRespository : AbstractRepository<ItemUom, Long> { | |||
| fun findAllByItemIdAndDeletedIsFalse(itemId: Serializable): List<ItemUom> | |||
| fun findByIdAndDeletedIsFalse(id: Serializable): ItemUom? | |||
| fun findByM18IdAndDeletedIsFalse(m18Id: Serializable): ItemUom? | |||
| fun deleteAllByIdIn(id: List<Serializable>) | |||
| fun findByItemIdAndPurchaseUnitIsTrueAndDeletedIsFalse(itemId: Serializable): ItemUom? | |||
| } | |||
| @@ -1,7 +1,6 @@ | |||
| package com.ffii.fpsms.modules.master.entity | |||
| 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 | |||
| @@ -41,4 +40,7 @@ open class Items : BaseEntity<Long>() { | |||
| @Column(name = "m18LastModifyDate") | |||
| open var m18LastModifyDate: LocalDateTime? = null | |||
| @OneToMany(mappedBy = "item", cascade = [CascadeType.ALL], orphanRemoval = true) | |||
| open var itemUoms: MutableSet<ItemUom> = mutableSetOf() | |||
| } | |||
| @@ -1,6 +1,9 @@ | |||
| package com.ffii.fpsms.modules.master.entity | |||
| import com.ffii.core.support.AbstractRepository | |||
| import com.ffii.fpsms.modules.master.entity.projections.SearchId | |||
| import com.ffii.fpsms.modules.master.enums.ShopType | |||
| import org.springframework.data.jpa.repository.Query | |||
| import org.springframework.stereotype.Repository | |||
| @Repository | |||
| @@ -10,4 +13,14 @@ interface ShopRepository : AbstractRepository<Shop, Long> { | |||
| fun findByIdAndDeletedIsFalse(id: Long): Shop? | |||
| fun findByM18IdAndDeletedIsFalse(m18Id: Long): Shop? | |||
| @Query( | |||
| nativeQuery = true, | |||
| value = "select s.id from Shop s where s.code regexp ?1 and s.type = ?2 and s.deleted = false") | |||
| fun findIdsByCodeRegexpAndTypeAndDeletedIsFalse(codeRegexp: String, type: String): List<Long>? | |||
| @Query( | |||
| nativeQuery = true, | |||
| value = "select s.id from Shop s where s.code not regexp ?1 and s.type = ?2 and s.deleted = false") | |||
| fun findIdsByCodeNotRegexpAndTypeAndDeletedIsFalse(codeNotRegexp: String, type: String): List<Long>? | |||
| } | |||
| @@ -8,5 +8,8 @@ import java.time.LocalDateTime | |||
| interface UomConversionRepository : AbstractRepository<UomConversion, Long> { | |||
| //fun importFromM18(): ArrayList<UomConversion>; | |||
| fun findByIdAndDeletedFalse(id: Long): UomConversion; | |||
| fun findByM18IdAndDeletedFalse(m18Id: Long): UomConversion?; | |||
| fun findByLastModifyDateAndM18IdAndDeletedFalse(lastModifyDate: LocalDateTime, m18Id: Long): UomConversion?; | |||
| } | |||
| @@ -0,0 +1,5 @@ | |||
| package com.ffii.fpsms.modules.master.entity.projections | |||
| interface SearchId { | |||
| val id: Long | |||
| } | |||
| @@ -0,0 +1,33 @@ | |||
| package com.ffii.fpsms.modules.master.service | |||
| import com.ffii.fpsms.modules.master.entity.Currency | |||
| import com.ffii.fpsms.modules.master.entity.CurrencyRepository | |||
| import com.ffii.fpsms.modules.master.web.models.CurrencyRequest | |||
| import org.springframework.stereotype.Service | |||
| @Service | |||
| open class CurrencyService( | |||
| val currencyRepository: CurrencyRepository, | |||
| ) { | |||
| open fun findById(id: Long): Currency? { | |||
| return currencyRepository.findByIdAndDeletedIsFalse(id); | |||
| } | |||
| open fun findByM18Id(m18Id: Long): Currency? { | |||
| return currencyRepository.findByM18IdAndDeletedIsFalse(m18Id); | |||
| } | |||
| open fun saveCurrency(request: CurrencyRequest): Currency { | |||
| val currency = request.m18Id?.let { findByM18Id(it) } ?: request.id?.let { findById(it) } ?: Currency() | |||
| currency.apply { | |||
| code = request.code | |||
| name = request.name | |||
| description = request.description | |||
| m18Id = request.m18Id | |||
| m18LastModifyDate = request.m18LastModifyDate | |||
| } | |||
| return currencyRepository.saveAndFlush(currency) | |||
| } | |||
| } | |||
| @@ -0,0 +1,57 @@ | |||
| package com.ffii.fpsms.modules.master.service | |||
| import com.ffii.fpsms.modules.master.entity.ItemUom | |||
| import com.ffii.fpsms.modules.master.entity.ItemUomRespository | |||
| import com.ffii.fpsms.modules.master.web.models.ItemUomRequest | |||
| import org.springframework.stereotype.Service | |||
| import kotlin.jvm.optionals.getOrNull | |||
| @Service | |||
| open class ItemUomService( | |||
| val itemsService: ItemsService, | |||
| val uomConversionService: UomConversionService, | |||
| val itemUomRespository: ItemUomRespository, | |||
| val currencyService: CurrencyService | |||
| ) { | |||
| open fun findAllByItemsId(itemId: Long): List<ItemUom> { | |||
| return itemUomRespository.findAllByItemIdAndDeletedIsFalse(itemId); | |||
| } | |||
| open fun findById(id: Long): ItemUom? { | |||
| return itemUomRespository.findByIdAndDeletedIsFalse(id); | |||
| } | |||
| open fun findByM18Id(m18Id: Long): ItemUom? { | |||
| return itemUomRespository.findByM18IdAndDeletedIsFalse(m18Id); | |||
| } | |||
| // See if need to update the response | |||
| open fun saveItemUom(request: ItemUomRequest): ItemUom { | |||
| val itemUom = request.m18Id?.let { findByM18Id(it) } ?: request.id?.let { findById(it) } ?: ItemUom() | |||
| val item = request.itemId?.let { itemsService.find(it).getOrNull() } | |||
| val uom = request.m18UomId?.let { uomConversionService.findByM18Id(it) } ?: request.uomId?.let { uomConversionService.find(it).getOrNull() } | |||
| val currency = request.currencyId?.let { currencyService.findById(it) } | |||
| itemUom.apply { | |||
| this.uom = uom | |||
| this.item = item | |||
| this.currency = currency | |||
| baseUnit = request.baseUnit | |||
| stockUnit = request.stockUnit | |||
| pickingUnit = request.pickingUnit | |||
| salesUnit = request.salesUnit | |||
| purchaseUnit = request.purchaseUnit | |||
| price = request.price | |||
| m18Id = request.m18Id | |||
| m18LastModifyDate = request.m18LastModifyDate | |||
| } | |||
| val savedItemUom = itemUomRespository.saveAndFlush(itemUom) | |||
| return savedItemUom | |||
| } | |||
| open fun deleteItemUoms(deleteIds: List<Long>) { | |||
| itemUomRespository.deleteAllByIdIn(deleteIds) | |||
| } | |||
| } | |||
| @@ -2,6 +2,7 @@ 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.entity.projections.SearchId | |||
| 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 | |||
| @@ -24,6 +25,16 @@ open class ShopService( | |||
| return shopRepository.findByM18IdAndDeletedIsFalse(m18Id) | |||
| } | |||
| open fun findVendorIdsByCodeRegexp(code: List<String>): List<Long>? { | |||
| val codeRegexp = code.joinToString("|") | |||
| return shopRepository.findIdsByCodeRegexpAndTypeAndDeletedIsFalse(codeRegexp, type = ShopType.SUPPLIER.value) | |||
| } | |||
| open fun findVendorIdsByCodeNotRegexp(code: List<String>): List<Long>? { | |||
| val codeRegexp = code.joinToString("|") | |||
| return shopRepository.findIdsByCodeNotRegexpAndTypeAndDeletedIsFalse(codeRegexp, type = ShopType.SUPPLIER.value) | |||
| } | |||
| open fun saveShop(request: SaveShopRequest): SaveShopResponse { | |||
| val shop = if (request.m18Id != null) { | |||
| findByM18Id(request.m18Id) ?: Shop() | |||
| @@ -196,6 +196,9 @@ open class UomConversionService( | |||
| } | |||
| } | |||
| open fun findByM18Id(m18Id: Long) : UomConversion? { | |||
| return uomConversionRepository.findByM18IdAndDeletedFalse(m18Id) | |||
| } | |||
| @Throws(IOException::class) | |||
| @Transactional | |||
| open fun saveUomConversion(newUomConversion: UomConversion): MessageResponse { | |||
| @@ -211,7 +214,8 @@ open class UomConversionService( | |||
| ) | |||
| } | |||
| val uomConversion = if (newUomConversion.id != null && newUomConversion.id > 0) | |||
| val uomConversion = findByM18Id(newUomConversion.m18Id) ?: | |||
| if (newUomConversion.id != null && newUomConversion.id > 0) | |||
| uomConversionRepository.findByIdAndDeletedFalse(newUomConversion.id) | |||
| else UomConversion() | |||
| @@ -39,47 +39,6 @@ class QcItemController( | |||
| @PostMapping("/save") | |||
| 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 = qcItemService.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 | |||
| ) | |||
| } | |||
| return qcItemService.saveQcItem(request) | |||
| } | |||
| } | |||
| @@ -0,0 +1,12 @@ | |||
| package com.ffii.fpsms.modules.master.web.models | |||
| import java.time.LocalDateTime | |||
| data class CurrencyRequest ( | |||
| val id: Long?, | |||
| val code: String?, | |||
| val name: String?, | |||
| val description: String?, | |||
| val m18Id: Long?, | |||
| val m18LastModifyDate: LocalDateTime?, | |||
| ) | |||
| @@ -0,0 +1,27 @@ | |||
| package com.ffii.fpsms.modules.master.web.models | |||
| import java.math.BigDecimal | |||
| import java.time.LocalDateTime | |||
| data class DeleteItemUomRequest( | |||
| val id: Long? = null, | |||
| val m18Id: Long? = null | |||
| ) | |||
| data class ItemUomRequest( | |||
| val id: Long? = null, | |||
| val uomId: Long? = null, | |||
| val m18UomId: Long? = null, | |||
| val itemId: Long? = null, | |||
| val m18ItemId: Long? = null, | |||
| val baseUnit: Boolean?, | |||
| val stockUnit: Boolean?, | |||
| val pickingUnit: Boolean?, | |||
| val salesUnit: Boolean?, | |||
| val purchaseUnit: Boolean?, | |||
| val price: BigDecimal?, | |||
| val currencyId: Long? = null, | |||
| val m18CurrencyId: Long? = null, | |||
| val m18Id: Long?, | |||
| val m18LastModifyDate: LocalDateTime?, | |||
| ) | |||
| @@ -5,10 +5,11 @@ import com.ffii.fpsms.modules.master.entity.Shop | |||
| import com.ffii.fpsms.m18.entity.M18DataLog | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatusConverter | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderType | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderTypeConverter | |||
| import jakarta.persistence.* | |||
| import jakarta.validation.constraints.NotNull | |||
| import jakarta.validation.constraints.Size | |||
| import java.time.LocalDate | |||
| import java.time.LocalDateTime | |||
| @Entity | |||
| @@ -37,6 +38,11 @@ open class PurchaseOrder : BaseEntity<Long>() { | |||
| @Convert(converter = PurchaseOrderStatusConverter::class) | |||
| open var status: PurchaseOrderStatus? = null | |||
| @NotNull | |||
| @Column(name = "type", nullable = true, length = 20) | |||
| @Convert(converter = PurchaseOrderTypeConverter::class) | |||
| open var type: PurchaseOrderType? = null | |||
| @NotNull | |||
| @ManyToOne | |||
| @JoinColumn(name = "m18DataLogId", nullable = false) | |||
| @@ -3,7 +3,7 @@ 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.m18.entity.M18DataLog | |||
| import com.ffii.fpsms.modules.master.enums.ShopTypeConverter | |||
| import com.ffii.fpsms.modules.master.entity.Currency | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatusConverter | |||
| import jakarta.persistence.* | |||
| @@ -40,10 +40,6 @@ open class PurchaseOrderLine : BaseEntity<Long>(){ | |||
| @Column(name = "price", precision = 14, scale = 2) | |||
| open var price: BigDecimal? = null | |||
| @Size(max = 5) | |||
| @Column(name = "priceUnit", length = 5) | |||
| open var priceUnit: String? = null | |||
| @Convert(converter = PurchaseOrderLineStatusConverter::class) | |||
| @NotNull | |||
| @Column(name = "status", nullable = false, length = 10) | |||
| @@ -53,4 +49,11 @@ open class PurchaseOrderLine : BaseEntity<Long>(){ | |||
| @ManyToOne | |||
| @JoinColumn(name = "m18DataLogId", nullable = false) | |||
| open var m18DataLog: M18DataLog? = null | |||
| @Column(name = "uomId") | |||
| open var uomId: Long? = null | |||
| @ManyToOne(fetch = FetchType.LAZY) | |||
| @JoinColumn(name = "currencyId") | |||
| open var currency: Currency? = null | |||
| } | |||
| @@ -13,4 +13,10 @@ enum class PurchaseOrderStatus(val value: String) { | |||
| ?: throw IllegalArgumentException("No enum constant with value: $value") | |||
| } | |||
| } | |||
| } | |||
| enum class PurchaseOrderType(val value: String) { | |||
| MATERIAL ("material"), | |||
| SHOP ("shop"), | |||
| OEM ("oem") | |||
| } | |||
| @@ -3,6 +3,7 @@ package com.ffii.fpsms.modules.purchaseOrder.enums | |||
| import jakarta.persistence.AttributeConverter | |||
| import jakarta.persistence.Converter | |||
| // Purchase Order Status | |||
| @Converter(autoApply = true) | |||
| class PurchaseOrderStatusConverter : AttributeConverter<PurchaseOrderStatus, String>{ | |||
| override fun convertToDatabaseColumn(status: PurchaseOrderStatus?): String? { | |||
| @@ -14,4 +15,18 @@ class PurchaseOrderStatusConverter : AttributeConverter<PurchaseOrderStatus, Str | |||
| PurchaseOrderStatus.entries.find { it.value == v } | |||
| } | |||
| } | |||
| } | |||
| // Purchase Order Type | |||
| @Converter(autoApply = true) | |||
| class PurchaseOrderTypeConverter : AttributeConverter<PurchaseOrderType, String>{ | |||
| override fun convertToDatabaseColumn(status: PurchaseOrderType?): String? { | |||
| return status?.value | |||
| } | |||
| override fun convertToEntityAttribute(value: String?): PurchaseOrderType? { | |||
| return value?.let { v -> | |||
| PurchaseOrderType.entries.find { it.value == v } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,7 +1,5 @@ | |||
| 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"), | |||
| @@ -2,8 +2,8 @@ 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.CurrencyService | |||
| 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 | |||
| @@ -12,7 +12,6 @@ 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 | |||
| @@ -22,7 +21,8 @@ open class PurchaseOrderLineService( | |||
| private val itemsService: ItemsService, | |||
| private val itemsRepository: ItemsRepository, | |||
| private val purchaseOrderRepository: PurchaseOrderRepository, | |||
| private val m18DataLogRepository: M18DataLogRepository | |||
| private val m18DataLogRepository: M18DataLogRepository, | |||
| private val currencyService: CurrencyService, | |||
| ) { | |||
| open fun allPurchaseOrderLine(): List<PurchaseOrderLine> { | |||
| return purchaseOrderLineRepository.findAll() | |||
| @@ -31,6 +31,7 @@ open class PurchaseOrderLineService( | |||
| open fun findPurchaseOrderLineByM18Id(m18DataLogId: Long): PurchaseOrderLine? { | |||
| return purchaseOrderLineRepository.findByM18DataLogIdAndDeletedIsFalse(m18DataLogId) | |||
| } | |||
| open fun findAllPoLineInfoByPoId(poId: Long): List<PurchaseOrderLineInfo> { | |||
| return purchaseOrderLineRepository.findAllPurchaseOrderLineInfoByPurchaseOrderIdAndDeletedIsFalse(poId) | |||
| } | |||
| @@ -43,6 +44,8 @@ open class PurchaseOrderLineService( | |||
| 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() } | |||
| val currency = request.m18CurrencyId?.let { currencyService.findByM18Id(it) } | |||
| ?: request.currencyId?.let { currencyService.findById(it) } | |||
| purchaseOrderLine.apply { | |||
| this.item = item | |||
| @@ -50,7 +53,7 @@ open class PurchaseOrderLineService( | |||
| this.purchaseOrder = purchaseOrder | |||
| qty = request.qty | |||
| price = request.price | |||
| priceUnit = request.priceUnit | |||
| this.currency = currency | |||
| this.status = status | |||
| this.m18DataLog = m18DataLog ?: this.m18DataLog | |||
| } | |||
| @@ -61,7 +64,7 @@ open class PurchaseOrderLineService( | |||
| itemNo = it.itemNo, | |||
| qty = it.qty, | |||
| price = it.price, | |||
| priceUnit = it.priceUnit, | |||
| currency = currency?.name, | |||
| status = it.status?.value | |||
| ) | |||
| } | |||
| @@ -10,6 +10,7 @@ import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderRepository | |||
| import com.ffii.fpsms.modules.purchaseOrder.entity.projections.PoLineWithStockInLine | |||
| import com.ffii.fpsms.modules.purchaseOrder.entity.projections.PurchaseOrderInfo | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderType | |||
| import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderRequest | |||
| import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderResponse | |||
| import com.ffii.fpsms.modules.stock.entity.StockInLine | |||
| @@ -77,6 +78,7 @@ open class PurchaseOrderService( | |||
| 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 type = request.type?.let { type -> PurchaseOrderType.entries.find { it.value == type } } | |||
| val m18DataLog = request.m18DataLogId?.let { m18DataLogRepository.findById(it).getOrNull() } | |||
| //Need check duplicate? | |||
| @@ -88,6 +90,7 @@ open class PurchaseOrderService( | |||
| estimatedArrivalDate = request.estimatedArrivalDate | |||
| completeDate = request.completeDate | |||
| this.status = status | |||
| this.type = type | |||
| this.m18DataLog = m18DataLog | |||
| } | |||
| @@ -1,6 +1,5 @@ | |||
| package com.ffii.fpsms.modules.purchaseOrder.web.model | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus | |||
| import java.math.BigDecimal | |||
| data class SavePurchaseOrderLineRequest( | |||
| @@ -10,7 +9,8 @@ data class SavePurchaseOrderLineRequest( | |||
| val purchaseOrderId: Long?, | |||
| val qty: BigDecimal?, | |||
| val price: BigDecimal?, | |||
| val priceUnit: String?, | |||
| val currencyId: Long? = null, | |||
| val m18CurrencyId: Long? = null, | |||
| val status: String?, | |||
| val m18DataLogId: Long?, | |||
| ) | |||
| @@ -1,6 +1,5 @@ | |||
| package com.ffii.fpsms.modules.purchaseOrder.web.model | |||
| import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderLineStatus | |||
| import java.math.BigDecimal | |||
| data class SavePurchaseOrderLineResponse ( | |||
| @@ -8,6 +7,6 @@ data class SavePurchaseOrderLineResponse ( | |||
| val itemNo: String?, | |||
| val qty: BigDecimal?, | |||
| val price: BigDecimal?, | |||
| val priceUnit: String?, | |||
| val currency: String?, | |||
| val status: String?, | |||
| ) | |||
| @@ -12,5 +12,6 @@ data class SavePurchaseOrderRequest ( | |||
| val estimatedArrivalDate: LocalDateTime?, | |||
| val completeDate: LocalDateTime?, | |||
| val status: String?, | |||
| val type: String?, | |||
| val m18DataLogId: Long? | |||
| ) | |||
| @@ -36,6 +36,11 @@ m18: | |||
| password: db25f2fc14cd2d2b1e7af307241f548fb03c312a | |||
| base-url: http://16.162.251.126/jsf/rfws | |||
| base-password: qwer1234 | |||
| supplier: | |||
| shop-po: P06, P07 | |||
| oem-po: T62 | |||
| supplier-not: | |||
| material-po: P06, P07 | |||
| beId: | |||
| toa: 29 | |||
| pp: 27 | |||
| @@ -0,0 +1,19 @@ | |||
| --liquibase formatted sql | |||
| --changeset cyril:create currency table | |||
| CREATE TABLE `currency` | |||
| ( | |||
| `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, | |||
| `description` VARCHAR(100) NOT NULL DEFAULT '0', | |||
| `m18Id` INT NULL, | |||
| `m18LastModifyDate` DATETIME NULL, | |||
| CONSTRAINT pk_currency PRIMARY KEY (id) | |||
| ); | |||
| @@ -0,0 +1,28 @@ | |||
| --liquibase formatted sql | |||
| --changeset cyril:create item_uom table | |||
| CREATE TABLE `item_uom` | |||
| ( | |||
| `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', | |||
| `uomId` INT NOT NULL, | |||
| `itemId` INT NOT NULL, | |||
| `baseUnit` TINYINT NOT NULL DEFAULT '0', | |||
| `stockUnit` TINYINT NOT NULL DEFAULT '0', | |||
| `pickingUnit` TINYINT NOT NULL DEFAULT '0', | |||
| `salesUnit` TINYINT NOT NULL DEFAULT '0', | |||
| `purchaseUnit` TINYINT NOT NULL DEFAULT '0', | |||
| `price` DECIMAL(14, 2) NULL, | |||
| `currencyId` INT NULL, | |||
| `m18Id` INT NOT NULL, | |||
| `m18LastModifyDate` DATETIME NULL, | |||
| CONSTRAINT pk_item_uom PRIMARY KEY (id), | |||
| CONSTRAINT FK_ITEM_UOM_ON_UOMID FOREIGN KEY (uomId) REFERENCES uom_conversion (id), | |||
| CONSTRAINT FK_ITEM_UOM_ON_ITEMID FOREIGN KEY (itemId) REFERENCES items (id), | |||
| CONSTRAINT FK_ITEM_UOM_ON_CURRENCYID FOREIGN KEY (currencyId) REFERENCES currency (id) | |||
| ); | |||
| @@ -0,0 +1,8 @@ | |||
| --liquibase formatted sql | |||
| --changeset cyril:update purchase order line | |||
| ALTER TABLE `purchase_order_line` | |||
| CHANGE COLUMN `priceUnit` `currencyId` INT NULL DEFAULT NULL, | |||
| ADD CONSTRAINT `FK_PURCHASE_ORDER_LINE_ON_UOMID` FOREIGN KEY (`uomId`) REFERENCES `uom_conversion` (`id`), | |||
| ADD CONSTRAINT `FK_PURCHASE_ORDER_LINE_ON_CURRENCYID` FOREIGN KEY (`currencyId`) REFERENCES `currency` (`id`); | |||
| @@ -0,0 +1,6 @@ | |||
| --liquibase formatted sql | |||
| --changeset cyril:update purchase order | |||
| ALTER TABLE `purchase_order` | |||
| ADD COLUMN `type` VARCHAR(20) NULL AFTER `status`; | |||