25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

466 lines
26 KiB

  1. package com.ffii.fpsms.m18.service
  2. import com.ffii.core.utils.JwtTokenUtil
  3. import com.ffii.fpsms.api.service.ApiCallerService
  4. import com.ffii.fpsms.m18.M18Config
  5. import com.ffii.fpsms.m18.enums.M18DataLogStatus
  6. import com.ffii.fpsms.m18.model.*
  7. import com.ffii.fpsms.m18.model.SyncResult
  8. import com.ffii.fpsms.m18.utils.CommonUtils
  9. import com.ffii.fpsms.m18.web.models.M18CommonRequest
  10. import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderLineStatus
  11. import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderStatus
  12. import com.ffii.fpsms.modules.deliveryOrder.service.DeliveryOrderLineService
  13. import com.ffii.fpsms.modules.deliveryOrder.service.DeliveryOrderService
  14. import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderLineRequest
  15. import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderRequest
  16. import com.ffii.fpsms.modules.master.service.ItemUomService
  17. import com.ffii.fpsms.modules.master.service.ItemsService
  18. import com.ffii.fpsms.modules.master.service.ShopService
  19. import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderType
  20. import org.slf4j.Logger
  21. import org.slf4j.LoggerFactory
  22. import org.springframework.stereotype.Service
  23. import java.time.LocalDateTime
  24. import java.time.format.DateTimeFormatter
  25. import kotlin.reflect.full.memberProperties
  26. import kotlin.text.substring
  27. @Service
  28. open class M18DeliveryOrderService(
  29. val m18Config: M18Config,
  30. val apiCallerService: ApiCallerService,
  31. val m18DataLogService: M18DataLogService,
  32. val deliveryOrderService: DeliveryOrderService,
  33. val deliveryOrderLineService: DeliveryOrderLineService,
  34. val itemsService: ItemsService,
  35. val shopService: ShopService,
  36. val itemUomService: ItemUomService,
  37. val m18MasterDataService: M18MasterDataService,
  38. ) {
  39. val commonUtils = CommonUtils()
  40. val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)
  41. val lastModifyDateStart = "2025-05-14 14:00:00"
  42. val lastModifyDateEnd = "2025-05-14 14:30:00"
  43. // val lastModifyDateConds =
  44. // "lastModifyDate=largerOrEqual=${lastModifyDateStart}=and=lastModifyDate=lessOrEqual=${lastModifyDateEnd}"
  45. // val lastModifyDate = LocalDateTime.now().minusMinutes(30)
  46. // val commonConds =
  47. // "(beId=equal=${m18Config.BEID_PF}=or=beId=equal=${m18Config.BEID_PP}=or=beId=equal=${m18Config.BEID_TOA})=and=lastModifyDate=largerOrEqual=${lastModifyDate}"
  48. // M18 API
  49. // Sharing same API with po
  50. val M18_LOAD_PURCHASE_ORDER_API = "/root/api/read/po"
  51. val M18_FETCH_PURCHASE_ORDER_LIST_API = "/search/search"
  52. // Include shop po
  53. open fun getDeliveryOrdersWithType(request: M18CommonRequest): M18PurchaseOrderListResponseWithType? {
  54. val deliveryOrders = M18PurchaseOrderListResponseWithType(mutableListOf())
  55. val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
  56. val lastDateConds = if (request.modifiedDateFrom != null && request.modifiedDateTo != null) {
  57. val dateFrom = LocalDateTime.parse(request.modifiedDateFrom, formatter).toString()
  58. val dateTo = LocalDateTime.parse(request.modifiedDateTo, formatter).toString()
  59. "lastModifyDate=largerOrEqual=$dateFrom=and=lastModifyDate=lessOrEqual=$dateTo"
  60. } else {
  61. ""
  62. }
  63. val dDateConds = if (request.dDateFrom != null && request.dDateTo != null) {
  64. val dateFrom = LocalDateTime.parse(request.dDateFrom, formatter).toLocalDate().toString()
  65. val dateTo = LocalDateTime.parse(request.dDateTo, formatter).toLocalDate().toString()
  66. "dDate=largerOrEqual=$dateFrom=and=dDate=lessOrEqual=$dateTo"
  67. } else {
  68. ""
  69. }
  70. val dDateEqualConds = if (request.dDateEqual != null) {
  71. val dDateEqual = LocalDateTime.parse(request.dDateEqual, formatter).toLocalDate().toString()
  72. "dDate=equal=$dDateEqual"
  73. } else {
  74. ""
  75. }
  76. // Shop PO
  77. val shopPoBuyers = commonUtils.listToString(listOf(m18Config.BEID_TOA), "beId=equal=", "=or=")
  78. val shopPoSupplier = commonUtils.listToString(
  79. shopService.findM18VendorIdsByCodeRegexp(m18Config.SHOP_PO_SUPPLIER),
  80. "venId=equal=",
  81. "=or="
  82. )
  83. var shopPoConds = "(${shopPoBuyers})=and=(${shopPoSupplier})"
  84. if (request.modifiedDateFrom != null && request.modifiedDateTo != null) {
  85. shopPoConds += "=and=(${lastDateConds})"
  86. }
  87. if (request.dDateFrom != null && request.dDateTo != null) {
  88. shopPoConds += "=and=(${dDateConds})"
  89. }
  90. if (request.dDateEqual != null) {
  91. shopPoConds += "=and=(${dDateEqualConds})"
  92. }
  93. println("shopPoConds: ${shopPoConds}")
  94. val shopPoParams = M18PurchaseOrderListRequest(
  95. params = null,
  96. conds = shopPoConds
  97. )
  98. try {
  99. deliveryOrders.valuesWithType += Pair(
  100. PurchaseOrderType.SHOP, apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>(
  101. M18_FETCH_PURCHASE_ORDER_LIST_API,
  102. shopPoParams
  103. ).block()
  104. )
  105. } catch (e: Exception) {
  106. logger.error("(Getting Shop Po list) Error on Function - ${e.stackTrace}")
  107. logger.error(e.message)
  108. }
  109. deliveryOrders.query = shopPoConds
  110. return deliveryOrders
  111. }
  112. open fun getDeliveryOrder(id: Long): M18PurchaseOrderResponse? {
  113. val deliveryOrderParams = M18PurchaseOrderRequest(
  114. id = id
  115. )
  116. var deliveryOrder: M18PurchaseOrderResponse? = null
  117. try {
  118. deliveryOrder = apiCallerService.get<M18PurchaseOrderResponse, M18PurchaseOrderRequest>(
  119. M18_LOAD_PURCHASE_ORDER_API,
  120. deliveryOrderParams
  121. ).block()
  122. } catch (e: Exception) {
  123. logger.error("(Getting Po Detail) Error on Function - ${e.stackTrace}")
  124. logger.error(e.message)
  125. }
  126. return deliveryOrder
  127. }
  128. open fun saveDeliveryOrders(request: M18CommonRequest) : SyncResult{
  129. logger.info("--------------------------------------------Start - Saving M18 Delivery Order--------------------------------------------")
  130. val deliveryOrdersWithType = getDeliveryOrdersWithType(request)
  131. val successList = mutableListOf<Long>()
  132. val successDetailList = mutableListOf<Long>()
  133. val failList = mutableListOf<Long>()
  134. val failDetailList = mutableListOf<Long>()
  135. val failItemDetailList = mutableListOf<Long>()
  136. val doRefType = "Delivery Order"
  137. val doLineRefType = "Delivery Order Line"
  138. if (deliveryOrdersWithType != null) {
  139. // Loop for Delivery Orders (values)
  140. deliveryOrdersWithType.valuesWithType.forEach { deliveryOrderWithType ->
  141. val type = deliveryOrderWithType.first
  142. // if success
  143. val deliveryOrdersValues = deliveryOrderWithType.second?.values
  144. // if fail
  145. val deliveryOrdersMessages = deliveryOrderWithType.second?.messages
  146. if (deliveryOrdersValues != null) {
  147. deliveryOrdersValues.forEach { deliveryOrder ->
  148. val deliveryOrderDetail = getDeliveryOrder(deliveryOrder.id)
  149. var deliveryOrderId: Long? = null //FP-MTMS
  150. // Process for Delivery Order (mainpo)
  151. // Assume only one DO in the DO (search by DO ID)
  152. val mainpo = deliveryOrderDetail?.data?.mainpo?.get(0)
  153. // logger.info("deliveryOrderDetail: data is null? ${deliveryOrderDetail?.data == null} | mainpo is null? ${deliveryOrderDetail?.data?.mainpo == null} | get(0) is null? ${deliveryOrderDetail?.data?.mainpo?.get(0) == null}")
  154. val pot = deliveryOrderDetail?.data?.pot
  155. val deliveryOrderLineMessage = deliveryOrderDetail?.messages
  156. // delivery_order + m18_data_log table
  157. if (mainpo != null) {
  158. // Find the latest m18 data log by m18 id & type
  159. // logger.info("${doRefType}: Finding For Latest M18 Data Log...")
  160. val latestDeliveryOrderLog =
  161. m18DataLogService.findLatestM18DataLogWithSuccess(deliveryOrder.id, doRefType)
  162. logger.info(latestDeliveryOrderLog.toString())
  163. // Save to m18_data_log table
  164. // logger.info("${doRefType}: Saving for M18 Data Log...")
  165. val mainpoJson =
  166. mainpo::class.memberProperties.associate { prop -> prop.name to prop.getter.call(mainpo) }
  167. .toMutableMap()
  168. val saveM18DeliveryOrderLogRequest = SaveM18DataLogRequest(
  169. id = null,
  170. refType = doRefType,
  171. m18Id = deliveryOrder.id,
  172. m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainpo.lastModifyDate),
  173. // dataLog = mainpoJson,
  174. statusEnum = M18DataLogStatus.NOT_PROCESS
  175. )
  176. val saveM18DeliveryOrderLog =
  177. m18DataLogService.saveM18DataLog(saveM18DeliveryOrderLogRequest)
  178. // logger.info("${doRefType}: Saved M18 Data Log. ID: ${saveM18DeliveryOrderLog.id}")
  179. try {
  180. // Find the delivery_order if exist
  181. // logger.info("${doRefType}: Finding exising delivery order...")
  182. val existingDeliveryOrder =
  183. latestDeliveryOrderLog?.id?.let { deliveryOrderService.findByM18DataLogId(it) }
  184. // logger.info("${doRefType}: Exising delivery order ID: ${existingDeliveryOrder?.id}")
  185. // Save to delivery_order table
  186. // logger.info("${doRefType}: Saving delivery order...")
  187. val saveDeliveryOrderRequest = SaveDeliveryOrderRequest(
  188. id = existingDeliveryOrder?.id,
  189. code = mainpo.code,
  190. m18SupplierId = mainpo.venId,
  191. m18ShopId = mainpo.virDeptId,
  192. m18CurrencyId = mainpo.curId,
  193. orderDate = commonUtils.timestampToLocalDateTime(mainpo.tDate),
  194. estimatedArrivalDate = commonUtils.timestampToLocalDateTime(mainpo.dDate),
  195. completeDate = null,
  196. status = DeliveryOrderStatus.PENDING.value,
  197. type = type.value,
  198. m18DataLogId = saveM18DeliveryOrderLog.id,
  199. handlerId = null,
  200. m18BeId = mainpo.beId,
  201. deleted = mainpo.udfIsVoid == "false"
  202. )
  203. val saveDeliveryOrderResponse =
  204. deliveryOrderService.saveDeliveryOrder(saveDeliveryOrderRequest)
  205. deliveryOrderId = saveDeliveryOrderResponse.id
  206. // Update m18_data_log with success
  207. val successSaveM18DeliveryOrderLogRequest = SaveM18DataLogRequest(
  208. id = saveM18DeliveryOrderLog.id,
  209. dataLog = mainpoJson,
  210. statusEnum = M18DataLogStatus.SUCCESS
  211. )
  212. m18DataLogService.saveM18DataLog(successSaveM18DeliveryOrderLogRequest)
  213. // log success info
  214. successList.add(deliveryOrder.id)
  215. logger.info("${doRefType}: Saved delivery order. ID: ${saveDeliveryOrderResponse.id} | M18 ${doRefType} ID: ${deliveryOrder.id}")
  216. } catch (e: Exception) {
  217. failList.add(deliveryOrder.id)
  218. // logger.error("${doRefType}: Saving Failure!")
  219. logger.error("Error on Function - ${e.stackTrace} | Type: ${doRefType} | M18 ID: ${deliveryOrder.id} | Different? ${mainpo.id}")
  220. logger.error(e.message)
  221. val errorSaveM18DeliveryOrderLogRequest = SaveM18DataLogRequest(
  222. id = saveM18DeliveryOrderLog.id,
  223. dataLog = mutableMapOf(Pair("Exception Message", e.message)),
  224. statusEnum = M18DataLogStatus.FAIL
  225. )
  226. m18DataLogService.saveM18DataLog(errorSaveM18DeliveryOrderLogRequest)
  227. // logger.error("${doRefType}: M18 Data Log Updated! Please see the error. ID: ${saveM18DeliveryOrderLogRequest.id}")
  228. }
  229. // delivery_order_line + m18_data_log
  230. // TODO: check deleted po line?
  231. if (pot != null) {
  232. // Loop for Delivery Order Lines (pot)
  233. pot.forEach { line ->
  234. // Find the latest m18 data log by m18 id & type
  235. // logger.info("${doLineRefType}: Finding For Latest M18 Data Log...")
  236. val latestDeliveryOrderLineLog =
  237. m18DataLogService.findLatestM18DataLogWithSuccess(line.id, doLineRefType)
  238. // logger.info("${doLineRefType}: Latest M18 Data Log ID: ${latestDeliveryOrderLineLog?.id}")
  239. // Save to m18_data_log table
  240. // logger.info("${doLineRefType}: Saving for M18 Data Log...")
  241. val lineJson =
  242. line::class.memberProperties.associate { prop ->
  243. prop.name to prop.getter.call(
  244. line
  245. )
  246. }
  247. .toMutableMap()
  248. val saveM18DeliveryOrderLineLogRequest = SaveM18DataLogRequest(
  249. id = null,
  250. refType = doLineRefType,
  251. m18Id = line.id,
  252. m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainpo.lastModifyDate),
  253. // dataLog = lineJson,
  254. statusEnum = M18DataLogStatus.NOT_PROCESS
  255. )
  256. val saveM18DeliveryOrderLineLog =
  257. m18DataLogService.saveM18DataLog(saveM18DeliveryOrderLineLogRequest)
  258. // logger.info("${doLineRefType}: Saved M18 Data Log. ID: ${saveM18DeliveryOrderLineLog.id}")
  259. // logger.info("${doLineRefType}: Finding item...")
  260. val item = itemsService.findByM18Id(line.proId)
  261. var itemId: Long? = null
  262. if (item == null) {
  263. itemId = m18MasterDataService.saveProduct(line.proId)?.id
  264. } else {
  265. itemId = item.id
  266. }
  267. // logger.info("${doLineRefType}: Item ID: ${itemId} | M18 Item ID: ${line.proId}")
  268. try {
  269. // Find the delivery_order_line if exist
  270. // logger.info("${doLineRefType}: Finding exising delivery order line...")
  271. val existingDeliveryOrderLine = latestDeliveryOrderLineLog?.id?.let {
  272. deliveryOrderLineService.findDeliveryOrderLineByM18Id(it)
  273. }
  274. // logger.info("${doLineRefType}: Exising delivery order line ID: ${existingDeliveryOrderLine?.id}")
  275. // Save to delivery_order_line table
  276. // logger.info("${doLineRefType}: Saving delivery order line...")
  277. val itemUom = itemId?.let { itemUomService.findStockUnitByItemId(it) }
  278. val saveDeliveryOrderLineRequest = SaveDeliveryOrderLineRequest(
  279. id = existingDeliveryOrderLine?.id,
  280. itemId = itemId,
  281. uomId = itemUom?.uom?.id,
  282. deliveryOrderId = deliveryOrderId,
  283. qty = line.qty,
  284. up = line.up,
  285. price = line.amt,
  286. // m18CurrencyId = mainpo.curId,
  287. status = existingDeliveryOrderLine?.status?.value
  288. ?: DeliveryOrderLineStatus.PENDING.value,
  289. m18DataLogId = saveM18DeliveryOrderLineLog.id,
  290. m18Discount = line.disc,
  291. m18Lot = line.lot
  292. )
  293. val saveDeliveryOrderLineResponse =
  294. deliveryOrderLineService.saveDeliveryOrderLine(saveDeliveryOrderLineRequest)
  295. // Update m18_data_log with success
  296. val successSaveM18DeliveryOrderLineLogRequest = SaveM18DataLogRequest(
  297. id = saveM18DeliveryOrderLineLog.id,
  298. dataLog = lineJson,
  299. statusEnum = M18DataLogStatus.SUCCESS
  300. )
  301. m18DataLogService.saveM18DataLog(successSaveM18DeliveryOrderLineLogRequest)
  302. // log success info
  303. successDetailList.add(line.id)
  304. // logger.info("${doLineRefType}: Delivery order ID: ${deliveryOrderId} | M18 ID: ${deliveryOrder.id}")
  305. logger.info("${doLineRefType}: Saved delivery order line. ID: ${saveDeliveryOrderLineResponse.id} | M18 Line ID: ${line.id} | Delivery order ID: ${deliveryOrderId} | M18 ID: ${deliveryOrder.id}")
  306. } catch (e: Exception) {
  307. failDetailList.add(line.id)
  308. failItemDetailList.add(line.proId)
  309. // logger.error("${doLineRefType}: Saving Failure!")
  310. logger.error("Error on Function - ${e.stackTrace} | Type: ${doLineRefType} | M18 ID: ${line.id}")
  311. logger.error(e.message)
  312. val errorSaveM18DeliveryOrderLineLogRequest = SaveM18DataLogRequest(
  313. id = saveM18DeliveryOrderLineLog.id,
  314. dataLog = mutableMapOf(Pair("Exception Message", e.message)),
  315. statusEnum = M18DataLogStatus.FAIL
  316. )
  317. m18DataLogService.saveM18DataLog(errorSaveM18DeliveryOrderLineLogRequest)
  318. // logger.error("${doLineRefType}: M18 Data Log Updated! Please see the error. ID: ${saveM18DeliveryOrderLineLog.id}")
  319. }
  320. }
  321. } else {
  322. // pot
  323. // logger.error("${doLineRefType}: Saving Failure!")
  324. val saveM18DeliveryOrderLineLogRequest = SaveM18DataLogRequest(
  325. id = null,
  326. refType = "${doLineRefType}",
  327. m18Id = deliveryOrder.id,
  328. m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainpo.lastModifyDate),
  329. // dataLog = mutableMapOf(Pair("Error Message", "${doLineRefType} is null")),
  330. dataLog = mutableMapOf(
  331. Pair(
  332. "${doLineRefType} Error Message",
  333. "pot is null"
  334. ),
  335. Pair(
  336. "${doLineRefType} Error Code",
  337. deliveryOrderLineMessage?.get(0)?.msgCode ?: "No Msg Code from M18"
  338. ),
  339. Pair(
  340. "${doLineRefType} Error Detail",
  341. deliveryOrderLineMessage?.get(0)?.msgDetail ?: "No Msg Detail from M18"
  342. ),
  343. ),
  344. statusEnum = M18DataLogStatus.FAIL
  345. )
  346. val errorLog = m18DataLogService.saveM18DataLog(saveM18DeliveryOrderLineLogRequest)
  347. logger.error("${doLineRefType}: M18 Data Log Updated! Please see the error. ID: ${errorLog.id}")
  348. }
  349. } else {
  350. // mainpo
  351. failList.add(deliveryOrder.id)
  352. // logger.error("${doRefType}: Saving Failure!")
  353. val saveM18DataLogRequest = SaveM18DataLogRequest(
  354. id = null,
  355. refType = "${doRefType}",
  356. m18Id = deliveryOrder.id,
  357. // m18LastModifyDate = if(mainpo?.lastModifyDate != null) commonUtils.instantToLocalDateTime(mainpo.lastModifyDate) else LocalDateTime.now(),
  358. m18LastModifyDate = LocalDateTime.now(),
  359. dataLog = mutableMapOf(
  360. Pair(
  361. "${doRefType} Error",
  362. "mainpo is null"
  363. ),
  364. Pair(
  365. "${doRefType} Error Code",
  366. deliveryOrdersMessages?.get(0)?.msgCode ?: "No Msg Code from M18"
  367. ),
  368. Pair(
  369. "${doRefType} Error Detail",
  370. deliveryOrdersMessages?.get(0)?.msgDetail ?: "No Msg Detail from M18"
  371. ),
  372. ),
  373. statusEnum = M18DataLogStatus.FAIL
  374. )
  375. val errorLog = m18DataLogService.saveM18DataLog(saveM18DataLogRequest)
  376. logger.error("${doLineRefType}: M18 Data Log Updated! Please see the error. ID: ${errorLog.id}")
  377. }
  378. }
  379. } else {
  380. logger.error("${doRefType} List is null. May occur errors.")
  381. }
  382. }
  383. } else {
  384. logger.error("${doRefType} List is null. May occur errors.")
  385. }
  386. // End of save. Check result
  387. // logger.info("Total Success (${doRefType}) (${successList.size}): $successList")
  388. logger.info("Total Success (${doRefType}) (${successList.size})")
  389. // if (failList.size > 0) {
  390. logger.error("Total Fail (${doRefType}) (${failList.size}): $failList")
  391. // }
  392. // logger.info("Total Success (${doLineRefType}) (${successDetailList.size}): $successDetailList")
  393. logger.info("Total Success (${doLineRefType}) (${successDetailList.size})")
  394. // if (failDetailList.size > 0) {
  395. logger.error("Total Fail (${doLineRefType}) (${failDetailList.size}): $failDetailList")
  396. // logger.error("Total Fail M18 Items (${doLineRefType}) (${failItemDetailList.distinct().size}): ${failItemDetailList.distinct()}")
  397. // }
  398. logger.info("--------------------------------------------End - Saving M18 Delivery Order--------------------------------------------")
  399. return SyncResult(
  400. totalProcessed = successList.size + failList.size,
  401. totalSuccess = successList.size,
  402. totalFail = failList.size,
  403. query = deliveryOrdersWithType?.query ?: ""
  404. )
  405. }
  406. }