Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 

632 righe
35 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.entity.DeliveryOrderRepository
  15. import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderLineRequest
  16. import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderRequest
  17. import com.ffii.fpsms.modules.master.entity.ItemUom
  18. import com.ffii.fpsms.modules.master.service.ItemUomService
  19. import com.ffii.fpsms.modules.master.service.ItemsService
  20. import com.ffii.fpsms.modules.master.service.ShopService
  21. import com.ffii.fpsms.modules.master.web.models.ConvertUomByItemRequest
  22. import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderType
  23. import org.slf4j.Logger
  24. import org.slf4j.LoggerFactory
  25. import org.springframework.stereotype.Service
  26. import java.time.LocalDateTime
  27. import java.time.format.DateTimeFormatter
  28. import kotlin.reflect.full.memberProperties
  29. import kotlin.text.substring
  30. @Service
  31. open class M18DeliveryOrderService(
  32. val m18Config: M18Config,
  33. val apiCallerService: ApiCallerService,
  34. val m18DataLogService: M18DataLogService,
  35. val deliveryOrderService: DeliveryOrderService,
  36. val deliveryOrderRepository: DeliveryOrderRepository,
  37. val deliveryOrderLineService: DeliveryOrderLineService,
  38. val itemsService: ItemsService,
  39. val shopService: ShopService,
  40. val itemUomService: ItemUomService,
  41. val m18MasterDataService: M18MasterDataService,
  42. ) {
  43. val commonUtils = CommonUtils()
  44. val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)
  45. val lastModifyDateStart = "2025-05-14 14:00:00"
  46. val lastModifyDateEnd = "2025-05-14 14:30:00"
  47. // val lastModifyDateConds =
  48. // "lastModifyDate=largerOrEqual=${lastModifyDateStart}=and=lastModifyDate=lessOrEqual=${lastModifyDateEnd}"
  49. // val lastModifyDate = LocalDateTime.now().minusMinutes(30)
  50. // val commonConds =
  51. // "(beId=equal=${m18Config.BEID_PF}=or=beId=equal=${m18Config.BEID_PP}=or=beId=equal=${m18Config.BEID_TOA})=and=lastModifyDate=largerOrEqual=${lastModifyDate}"
  52. // M18 API
  53. // Sharing same API with po
  54. val M18_LOAD_PURCHASE_ORDER_API = "/root/api/read/po"
  55. val M18_FETCH_PURCHASE_ORDER_LIST_API = "/search/search"
  56. // Include shop po
  57. open fun getDeliveryOrdersWithType(request: M18CommonRequest): M18PurchaseOrderListResponseWithType? {
  58. val deliveryOrders = M18PurchaseOrderListResponseWithType(mutableListOf())
  59. val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
  60. val lastDateConds = if (request.modifiedDateFrom != null && request.modifiedDateTo != null) {
  61. val dateFrom = LocalDateTime.parse(request.modifiedDateFrom, formatter).toString()
  62. val dateTo = LocalDateTime.parse(request.modifiedDateTo, formatter).toString()
  63. "lastModifyDate=largerOrEqual=$dateFrom=and=lastModifyDate=lessOrEqual=$dateTo"
  64. } else {
  65. ""
  66. }
  67. val dDateConds = if (request.dDateFrom != null && request.dDateTo != null) {
  68. val dateFrom = LocalDateTime.parse(request.dDateFrom, formatter).toLocalDate().toString()
  69. val dateTo = LocalDateTime.parse(request.dDateTo, formatter).toLocalDate().toString()
  70. "dDate=largerOrEqual=$dateFrom=and=dDate=lessOrEqual=$dateTo"
  71. } else {
  72. ""
  73. }
  74. val dDateEqualConds = if (request.dDateEqual != null) {
  75. val dDateEqual = LocalDateTime.parse(request.dDateEqual, formatter).toLocalDate().toString()
  76. "dDate=equal=$dDateEqual"
  77. } else {
  78. ""
  79. }
  80. // Shop PO
  81. val shopPoBuyers = commonUtils.listToString(listOf(m18Config.BEID_TOA), "beId=equal=", "=or=")
  82. val shopPoSupplier = commonUtils.listToString(
  83. shopService.findM18VendorIdsByCodeRegexp(m18Config.SHOP_PO_SUPPLIER),
  84. "venId=equal=",
  85. "=or="
  86. )
  87. var shopPoConds = "(${shopPoBuyers})=and=(${shopPoSupplier})"
  88. if (request.modifiedDateFrom != null && request.modifiedDateTo != null) {
  89. shopPoConds += "=and=(${lastDateConds})"
  90. }
  91. if (request.dDateFrom != null && request.dDateTo != null) {
  92. shopPoConds += "=and=(${dDateConds})"
  93. }
  94. if (request.dDateEqual != null) {
  95. shopPoConds += "=and=(${dDateEqualConds})"
  96. }
  97. logger.info("shopPoConds: ${shopPoConds}")
  98. val shopPoParams = M18PurchaseOrderListRequest(
  99. params = null,
  100. conds = shopPoConds
  101. )
  102. try {
  103. deliveryOrders.valuesWithType += Pair(
  104. PurchaseOrderType.SHOP, apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>(
  105. M18_FETCH_PURCHASE_ORDER_LIST_API,
  106. shopPoParams
  107. ).block()
  108. )
  109. } catch (e: Exception) {
  110. logger.error("(Getting Shop Po list) Error on Function - ${e.stackTrace}")
  111. logger.error(e.message)
  112. }
  113. deliveryOrders.query = shopPoConds
  114. return deliveryOrders
  115. }
  116. open fun getDeliveryOrder(id: Long): M18PurchaseOrderResponse? {
  117. val deliveryOrderParams = M18PurchaseOrderRequest(
  118. id = id
  119. )
  120. var deliveryOrder: M18PurchaseOrderResponse? = null
  121. try {
  122. deliveryOrder = apiCallerService.get<M18PurchaseOrderResponse, M18PurchaseOrderRequest>(
  123. M18_LOAD_PURCHASE_ORDER_API,
  124. deliveryOrderParams
  125. ).block()
  126. } catch (e: Exception) {
  127. logger.error("(Getting Po Detail) Error on Function - ${e.stackTrace}")
  128. logger.error(e.message)
  129. }
  130. return deliveryOrder
  131. }
  132. open fun saveDeliveryOrders(request: M18CommonRequest, skipExistingDo: Boolean = false): SyncResult {
  133. val deliveryOrdersWithType = getDeliveryOrdersWithType(request)
  134. return saveDeliveryOrdersWithPreparedList(
  135. deliveryOrdersWithType,
  136. syncisExtra = false,
  137. skipExistingDo = skipExistingDo,
  138. )
  139. }
  140. /**
  141. * Sync a single M18 shop PO / delivery order by document [code], same search pattern as
  142. * [com.ffii.fpsms.m18.service.M18PurchaseOrderService.savePurchaseOrderByCode].
  143. *
  144. * @param isExtraSync when true, persist local `delivery_order.isExtra=true` (manual DO(加單) sync).
  145. * No M18-side "加單" filtering is used.
  146. * @param newOnly when true, skip if a non-deleted local DO already exists with the same `code`.
  147. */
  148. open fun saveDeliveryOrderByCode(
  149. code: String,
  150. isExtraSync: Boolean = false,
  151. newOnly: Boolean = false,
  152. ): SyncResult {
  153. if (newOnly && deliveryOrderRepository.existsByCodeAndDeletedIsFalse(code)) {
  154. return SyncResult(
  155. totalProcessed = 1,
  156. totalSuccess = 0,
  157. totalFail = 0,
  158. query = "skipped (newOnly=true): delivery_order.code already exists: $code",
  159. )
  160. }
  161. val conds = "(code=equal=$code)"
  162. val searchRequest = M18PurchaseOrderListRequest(
  163. stSearch = "po",
  164. params = null,
  165. conds = conds
  166. )
  167. val doListResponse = try {
  168. apiCallerService.get<M18PurchaseOrderListResponse, M18PurchaseOrderListRequest>(
  169. M18_FETCH_PURCHASE_ORDER_LIST_API,
  170. searchRequest
  171. ).block()
  172. } catch (e: Exception) {
  173. logger.error("(Getting DO list By Code) Error on Function - ${e.stackTrace}")
  174. logger.error(e.message)
  175. null
  176. }
  177. val doValues = doListResponse?.values
  178. if (doValues.isNullOrEmpty()) {
  179. return SyncResult(
  180. totalProcessed = 1,
  181. totalSuccess = 0,
  182. totalFail = 1,
  183. query = conds
  184. )
  185. }
  186. val prepared = M18PurchaseOrderListResponseWithType(
  187. valuesWithType = mutableListOf(Pair(PurchaseOrderType.SHOP, doListResponse)),
  188. query = conds
  189. )
  190. return saveDeliveryOrdersWithPreparedList(prepared, syncisExtra = isExtraSync, skipExistingDo = newOnly)
  191. }
  192. private fun saveDeliveryOrdersWithPreparedList(
  193. deliveryOrdersWithType: M18PurchaseOrderListResponseWithType?,
  194. syncisExtra: Boolean = false,
  195. skipExistingDo: Boolean = false,
  196. ): SyncResult {
  197. logger.info("--------------------------------------------Start - Saving M18 Delivery Order--------------------------------------------")
  198. if (skipExistingDo) {
  199. logger.info("skipExistingDo=true — local delivery orders will not be updated")
  200. }
  201. val successList = mutableListOf<Long>()
  202. val skippedList = mutableListOf<Long>()
  203. val successDetailList = mutableListOf<Long>()
  204. val failList = mutableListOf<Long>()
  205. val failDetailList = mutableListOf<Long>()
  206. val failItemDetailList = mutableListOf<Long>()
  207. val uomByM18IdCache = mutableMapOf<Long, ItemUom?>()
  208. val itemIdCache = mutableMapOf<Long, Long>()
  209. val stockUomIdCache = mutableMapOf<Pair<Long, Long>, Long?>()
  210. val doRefType = "Delivery Order"
  211. val doLineRefType = "Delivery Order Line"
  212. if (deliveryOrdersWithType != null) {
  213. // Loop for Delivery Orders (values)
  214. deliveryOrdersWithType.valuesWithType.forEach { deliveryOrderWithType ->
  215. val type = deliveryOrderWithType.first
  216. // if success
  217. val deliveryOrdersValues = deliveryOrderWithType.second?.values
  218. // if fail
  219. val deliveryOrdersMessages = deliveryOrderWithType.second?.messages
  220. if (deliveryOrdersValues != null) {
  221. deliveryOrdersValues.forEach { deliveryOrder ->
  222. if (skipExistingDo) {
  223. val latestDeliveryOrderLog =
  224. m18DataLogService.findLatestM18DataLogWithSuccess(deliveryOrder.id, doRefType)
  225. val existingByM18 = latestDeliveryOrderLog?.id?.let {
  226. deliveryOrderService.findByM18DataLogId(it)
  227. }
  228. if (existingByM18 != null && existingByM18.deleted != true) {
  229. logger.info(
  230. "${doRefType}: skipExistingDo — skipping M18 id=${deliveryOrder.id} " +
  231. "code=${existingByM18.code} localId=${existingByM18.id} status=${existingByM18.status}"
  232. )
  233. skippedList.add(deliveryOrder.id)
  234. return@forEach
  235. }
  236. }
  237. val deliveryOrderDetail = getDeliveryOrder(deliveryOrder.id)
  238. var deliveryOrderId: Long? = null //FP-MTMS
  239. // Process for Delivery Order (mainpo)
  240. // Assume only one DO in the DO (search by DO ID)
  241. val mainpo = deliveryOrderDetail?.data?.mainpo?.get(0)
  242. // 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}")
  243. val pot = deliveryOrderDetail?.data?.pot
  244. val deliveryOrderLineMessage = deliveryOrderDetail?.messages
  245. // delivery_order + m18_data_log table
  246. if (mainpo != null) {
  247. if (skipExistingDo && deliveryOrderRepository.existsByCodeAndDeletedIsFalse(mainpo.code)) {
  248. logger.info(
  249. "${doRefType}: skipExistingDo — skipping M18 id=${deliveryOrder.id} code=${mainpo.code} (local DO exists by code)"
  250. )
  251. skippedList.add(deliveryOrder.id)
  252. return@forEach
  253. }
  254. // Find the latest m18 data log by m18 id & type
  255. // logger.info("${doRefType}: Finding For Latest M18 Data Log...")
  256. val latestDeliveryOrderLog =
  257. m18DataLogService.findLatestM18DataLogWithSuccess(deliveryOrder.id, doRefType)
  258. //logger.info(latestDeliveryOrderLog.toString())
  259. // Save to m18_data_log table
  260. // logger.info("${doRefType}: Saving for M18 Data Log...")
  261. val mainpoJson =
  262. mainpo::class.memberProperties.associate { prop -> prop.name to prop.getter.call(mainpo) }
  263. .toMutableMap()
  264. val saveM18DeliveryOrderLogRequest = SaveM18DataLogRequest(
  265. id = null,
  266. refType = doRefType,
  267. m18Id = deliveryOrder.id,
  268. m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainpo.lastModifyDate),
  269. // dataLog = mainpoJson,
  270. statusEnum = M18DataLogStatus.NOT_PROCESS
  271. )
  272. val saveM18DeliveryOrderLog =
  273. m18DataLogService.saveM18DataLog(saveM18DeliveryOrderLogRequest)
  274. // logger.info("${doRefType}: Saved M18 Data Log. ID: ${saveM18DeliveryOrderLog.id}")
  275. try {
  276. // Find the delivery_order if exist
  277. // logger.info("${doRefType}: Finding exising delivery order...")
  278. val existingDeliveryOrder =
  279. latestDeliveryOrderLog?.id?.let { deliveryOrderService.findByM18DataLogId(it) }
  280. // logger.info("${doRefType}: Exising delivery order ID: ${existingDeliveryOrder?.id}")
  281. // Save to delivery_order table
  282. // logger.info("${doRefType}: Saving delivery order...")
  283. val saveDeliveryOrderRequest = SaveDeliveryOrderRequest(
  284. id = existingDeliveryOrder?.id,
  285. code = mainpo.code,
  286. m18SupplierId = mainpo.venId,
  287. m18ShopId = mainpo.virDeptId,
  288. m18CurrencyId = mainpo.curId,
  289. orderDate = commonUtils.timestampToLocalDateTime(mainpo.tDate),
  290. estimatedArrivalDate = commonUtils.timestampToLocalDateTime(mainpo.dDate),
  291. completeDate = null,
  292. status = DeliveryOrderStatus.PENDING.value,
  293. type = type.value,
  294. m18DataLogId = saveM18DeliveryOrderLog.id,
  295. handlerId = null,
  296. m18BeId = mainpo.beId,
  297. deleted = mainpo.udfIsVoid == true,
  298. isExtra = syncisExtra,
  299. )
  300. val saveDeliveryOrderResponse =
  301. deliveryOrderService.saveDeliveryOrder(saveDeliveryOrderRequest)
  302. deliveryOrderId = saveDeliveryOrderResponse.id
  303. // Update m18_data_log with success
  304. val successSaveM18DeliveryOrderLogRequest = SaveM18DataLogRequest(
  305. id = saveM18DeliveryOrderLog.id,
  306. dataLog = mainpoJson,
  307. statusEnum = M18DataLogStatus.SUCCESS
  308. )
  309. m18DataLogService.saveM18DataLog(successSaveM18DeliveryOrderLogRequest)
  310. // log success info
  311. successList.add(deliveryOrder.id)
  312. logger.info("${doRefType}: Saved delivery order. ID: ${saveDeliveryOrderResponse.id} | M18 ${doRefType} ID: ${deliveryOrder.id}")
  313. } catch (e: Exception) {
  314. failList.add(deliveryOrder.id)
  315. // logger.error("${doRefType}: Saving Failure!")
  316. logger.error("Error on Function - ${e.stackTrace} | Type: ${doRefType} | M18 ID: ${deliveryOrder.id} | Different? ${mainpo.id}")
  317. logger.error(e.message)
  318. val errorSaveM18DeliveryOrderLogRequest = SaveM18DataLogRequest(
  319. id = saveM18DeliveryOrderLog.id,
  320. dataLog = mutableMapOf(Pair("Exception Message", e.message)),
  321. statusEnum = M18DataLogStatus.FAIL
  322. )
  323. m18DataLogService.saveM18DataLog(errorSaveM18DeliveryOrderLogRequest)
  324. // logger.error("${doRefType}: M18 Data Log Updated! Please see the error. ID: ${saveM18DeliveryOrderLogRequest.id}")
  325. }
  326. // delivery_order_line + m18_data_log
  327. if (pot != null) {
  328. val m18LineIds = pot.map { it.id }.toSet()
  329. // Loop for Delivery Order Lines (pot)
  330. pot.forEach { line ->
  331. // Find the latest m18 data log by m18 id & type
  332. // logger.info("${doLineRefType}: Finding For Latest M18 Data Log...")
  333. val latestDeliveryOrderLineLog =
  334. m18DataLogService.findLatestM18DataLogWithSuccess(line.id, doLineRefType)
  335. // logger.info("${doLineRefType}: Latest M18 Data Log ID: ${latestDeliveryOrderLineLog?.id}")
  336. // Save to m18_data_log table
  337. // logger.info("${doLineRefType}: Saving for M18 Data Log...")
  338. val lineJson =
  339. line::class.memberProperties.associate { prop ->
  340. prop.name to prop.getter.call(
  341. line
  342. )
  343. }
  344. .toMutableMap()
  345. val saveM18DeliveryOrderLineLogRequest = SaveM18DataLogRequest(
  346. id = null,
  347. refType = doLineRefType,
  348. m18Id = line.id,
  349. m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainpo.lastModifyDate),
  350. // dataLog = lineJson,
  351. statusEnum = M18DataLogStatus.NOT_PROCESS
  352. )
  353. val saveM18DeliveryOrderLineLog =
  354. m18DataLogService.saveM18DataLog(saveM18DeliveryOrderLineLogRequest)
  355. // logger.info("${doLineRefType}: Saved M18 Data Log. ID: ${saveM18DeliveryOrderLineLog.id}")
  356. // logger.info("${doLineRefType}: Finding item...")
  357. val itemId: Long? = itemIdCache[line.proId]
  358. ?: m18MasterDataService.resolveLocalItemId(line.proId)?.also {
  359. itemIdCache[line.proId] = it
  360. }
  361. val stockUomId: Long? = if (itemId != null) {
  362. val key = line.proId to line.unitId // safe key
  363. stockUomIdCache.getOrPut(key) {
  364. val uom = itemUomService.findByM18Id(line.unitId)
  365. itemUomService.findStockUnitByItemId(itemId)?.uom?.id
  366. }
  367. } else null
  368. // logger.info("${doLineRefType}: Item ID: ${itemId} | M18 Item ID: ${line.proId}")
  369. if (itemId == null) {
  370. failDetailList.add(line.id)
  371. failItemDetailList.add(line.proId)
  372. logger.error(
  373. "${doLineRefType}: Cannot resolve local item for M18 proId=${line.proId}, skipping line ${line.id}"
  374. )
  375. val errorSaveM18DeliveryOrderLineLogRequest = SaveM18DataLogRequest(
  376. id = saveM18DeliveryOrderLineLog.id,
  377. dataLog = mutableMapOf(
  378. "Exception Message" to "Cannot resolve local item for M18 proId=${line.proId}"
  379. ),
  380. statusEnum = M18DataLogStatus.FAIL
  381. )
  382. m18DataLogService.saveM18DataLog(errorSaveM18DeliveryOrderLineLogRequest)
  383. return@forEach
  384. }
  385. try {
  386. // Find the delivery_order_line if exist
  387. // logger.info("${doLineRefType}: Finding exising delivery order line...")
  388. val existingDeliveryOrderLine = latestDeliveryOrderLineLog?.id?.let {
  389. deliveryOrderLineService.findDeliveryOrderLineByM18Id(it)
  390. }
  391. // logger.info("${doLineRefType}: Exising delivery order line ID: ${existingDeliveryOrderLine?.id}")
  392. // Save to delivery_order_line table
  393. // logger.info("${doLineRefType}: Saving delivery order line...")
  394. val itemUom = uomByM18IdCache.getOrPut(line.unitId) {
  395. itemUomService.findByM18Id(line.unitId)
  396. }
  397. val m18UomId = itemUom?.uom?.id
  398. val sourceQty = line.qty
  399. val stockQty =
  400. if (itemId != null && m18UomId != null && m18UomId == stockUomId) {
  401. // M18 line unit is already the stock unit — skip ratio conversion
  402. // (avoids bad qty when item_uom ratioN/ratioD hold spec numbers like 350g).
  403. sourceQty
  404. } else if (itemId != null && m18UomId != null) {
  405. itemUomService.convertQtyToStockQty(itemId, m18UomId, sourceQty)
  406. } else {
  407. sourceQty
  408. }
  409. val saveDeliveryOrderLineRequest = SaveDeliveryOrderLineRequest(
  410. id = existingDeliveryOrderLine?.id,
  411. itemId = itemId,
  412. uomIdM18 = m18UomId,
  413. uomId= stockUomId,
  414. deliveryOrderId = deliveryOrderId,
  415. qtyM18 = sourceQty,
  416. qty = stockQty,
  417. up = line.up,
  418. price = line.amt,
  419. // m18CurrencyId = mainpo.curId,
  420. status = existingDeliveryOrderLine?.status?.value
  421. ?: DeliveryOrderLineStatus.PENDING.value,
  422. m18DataLogId = saveM18DeliveryOrderLineLog.id,
  423. m18Discount = line.disc,
  424. m18Lot = line.lot
  425. )
  426. val saveDeliveryOrderLineResponse =
  427. deliveryOrderLineService.saveDeliveryOrderLine(saveDeliveryOrderLineRequest)
  428. // Update m18_data_log with success
  429. val successSaveM18DeliveryOrderLineLogRequest = SaveM18DataLogRequest(
  430. id = saveM18DeliveryOrderLineLog.id,
  431. dataLog = lineJson,
  432. statusEnum = M18DataLogStatus.SUCCESS
  433. )
  434. m18DataLogService.saveM18DataLog(successSaveM18DeliveryOrderLineLogRequest)
  435. // log success info
  436. successDetailList.add(line.id)
  437. // logger.info("${doLineRefType}: Delivery order ID: ${deliveryOrderId} | M18 ID: ${deliveryOrder.id}")
  438. //logger.info("${doLineRefType}: Saved delivery order line. ID: ${saveDeliveryOrderLineResponse.id} | M18 Line ID: ${line.id} | Delivery order ID: ${deliveryOrderId} | M18 ID: ${deliveryOrder.id}")
  439. } catch (e: Exception) {
  440. failDetailList.add(line.id)
  441. failItemDetailList.add(line.proId)
  442. // logger.error("${doLineRefType}: Saving Failure!")
  443. logger.error("Error on Function - ${e.stackTrace} | Type: ${doLineRefType} | M18 ID: ${line.id}")
  444. logger.error(e.message)
  445. val errorSaveM18DeliveryOrderLineLogRequest = SaveM18DataLogRequest(
  446. id = saveM18DeliveryOrderLineLog.id,
  447. dataLog = mutableMapOf(Pair("Exception Message", e.message)),
  448. statusEnum = M18DataLogStatus.FAIL
  449. )
  450. m18DataLogService.saveM18DataLog(errorSaveM18DeliveryOrderLineLogRequest)
  451. // logger.error("${doLineRefType}: M18 Data Log Updated! Please see the error. ID: ${saveM18DeliveryOrderLineLog.id}")
  452. }
  453. }
  454. if (deliveryOrderId != null) {
  455. val markedDeleted = deliveryOrderLineService.markDeletedLinesMissingFromM18(
  456. deliveryOrderId = deliveryOrderId,
  457. existingM18LineIds = m18LineIds,
  458. m18RefType = doLineRefType
  459. )
  460. if (markedDeleted > 0) {
  461. logger.info("${doLineRefType}: Marked ${markedDeleted} stale line(s) as deleted for deliveryOrderId=${deliveryOrderId}")
  462. }
  463. val dupesRemoved = deliveryOrderLineService.markDuplicateDeliveryOrderLinesForSameM18LineId(
  464. deliveryOrderId = deliveryOrderId,
  465. existingM18LineIds = m18LineIds,
  466. m18RefType = doLineRefType
  467. )
  468. if (dupesRemoved > 0) {
  469. logger.info("${doLineRefType}: Marked ${dupesRemoved} duplicate line(s) as deleted (same M18 line id) for deliveryOrderId=${deliveryOrderId}")
  470. }
  471. }
  472. } else {
  473. // pot
  474. // logger.error("${doLineRefType}: Saving Failure!")
  475. val saveM18DeliveryOrderLineLogRequest = SaveM18DataLogRequest(
  476. id = null,
  477. refType = "${doLineRefType}",
  478. m18Id = deliveryOrder.id,
  479. m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainpo.lastModifyDate),
  480. // dataLog = mutableMapOf(Pair("Error Message", "${doLineRefType} is null")),
  481. dataLog = mutableMapOf(
  482. Pair(
  483. "${doLineRefType} Error Message",
  484. "pot is null"
  485. ),
  486. Pair(
  487. "${doLineRefType} Error Code",
  488. deliveryOrderLineMessage?.get(0)?.msgCode ?: "No Msg Code from M18"
  489. ),
  490. Pair(
  491. "${doLineRefType} Error Detail",
  492. deliveryOrderLineMessage?.get(0)?.msgDetail ?: "No Msg Detail from M18"
  493. ),
  494. ),
  495. statusEnum = M18DataLogStatus.FAIL
  496. )
  497. val errorLog = m18DataLogService.saveM18DataLog(saveM18DeliveryOrderLineLogRequest)
  498. logger.error("${doLineRefType}: M18 Data Log Updated! Please see the error. ID: ${errorLog.id}")
  499. }
  500. } else {
  501. // mainpo
  502. failList.add(deliveryOrder.id)
  503. // logger.error("${doRefType}: Saving Failure!")
  504. val saveM18DataLogRequest = SaveM18DataLogRequest(
  505. id = null,
  506. refType = "${doRefType}",
  507. m18Id = deliveryOrder.id,
  508. // m18LastModifyDate = if(mainpo?.lastModifyDate != null) commonUtils.instantToLocalDateTime(mainpo.lastModifyDate) else LocalDateTime.now(),
  509. m18LastModifyDate = LocalDateTime.now(),
  510. dataLog = mutableMapOf(
  511. Pair(
  512. "${doRefType} Error",
  513. "mainpo is null"
  514. ),
  515. Pair(
  516. "${doRefType} Error Code",
  517. deliveryOrdersMessages?.get(0)?.msgCode ?: "No Msg Code from M18"
  518. ),
  519. Pair(
  520. "${doRefType} Error Detail",
  521. deliveryOrdersMessages?.get(0)?.msgDetail ?: "No Msg Detail from M18"
  522. ),
  523. ),
  524. statusEnum = M18DataLogStatus.FAIL
  525. )
  526. val errorLog = m18DataLogService.saveM18DataLog(saveM18DataLogRequest)
  527. logger.error("${doLineRefType}: M18 Data Log Updated! Please see the error. ID: ${errorLog.id}")
  528. }
  529. }
  530. } else {
  531. logger.error("${doRefType} List is null. May occur errors.")
  532. }
  533. }
  534. } else {
  535. logger.error("${doRefType} List is null. May occur errors.")
  536. }
  537. // End of save. Check result
  538. logger.info("Total Success (${doRefType}) (${successList.size})")
  539. logger.error("Total Fail (${doRefType}) (${failList.size}): $failList")
  540. if (skippedList.isNotEmpty()) {
  541. logger.info("Total Skipped (${doRefType}) (${skippedList.size}): $skippedList")
  542. }
  543. logger.info("Total Success (${doLineRefType}) (${successDetailList.size})")
  544. logger.error("Total Fail (${doLineRefType}) (${failDetailList.size}): $failDetailList")
  545. // Fee cleanup for DO lines (currently disabled; keep for future use)
  546. // val feeMarked = deliveryOrderLineService.markDeletedLinesWithFeeItems()
  547. // if (feeMarked > 0) {
  548. // logger.info("Marked $feeMarked DO line(s) as deleted (isFee items).")
  549. // }
  550. logger.info("--------------------------------------------End - Saving M18 Delivery Order--------------------------------------------")
  551. val skippedSuffix = if (skippedList.isNotEmpty()) " | skipped=${skippedList.size}" else ""
  552. return SyncResult(
  553. totalProcessed = successList.size + failList.size + skippedList.size,
  554. totalSuccess = successList.size,
  555. totalFail = failList.size,
  556. query = (deliveryOrdersWithType?.query ?: "") + skippedSuffix,
  557. )
  558. }
  559. }