diff --git a/src/main/java/com/ffii/fpsms/m18/entity/GrnSendLog.kt b/src/main/java/com/ffii/fpsms/m18/entity/GrnSendLog.kt new file mode 100644 index 0000000..bfbbbc3 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/m18/entity/GrnSendLog.kt @@ -0,0 +1,27 @@ +package com.ffii.fpsms.m18.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 org.hibernate.annotations.JdbcTypeCode +import org.hibernate.type.SqlTypes + +@Entity +@Table(name = "grn_send_log") +open class GrnSendLog: BaseEntity() { + @Size(max = 1000) + @NotNull + @Column(name = "refType", nullable = false, length = 1000) + open var refType: String? = null + + @JdbcTypeCode(SqlTypes.JSON) + @Column(name = "data") + open var data: MutableMap? = null + + @NotNull + @Column(name = "status") + open var status: Boolean? = null +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/entity/GrnSendLogRepository.kt b/src/main/java/com/ffii/fpsms/m18/entity/GrnSendLogRepository.kt new file mode 100644 index 0000000..29b1963 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/m18/entity/GrnSendLogRepository.kt @@ -0,0 +1,6 @@ +package com.ffii.fpsms.m18.entity + +import com.ffii.core.support.AbstractRepository + +interface GrnSendLogRepository: AbstractRepository { +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt b/src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt index b59a2f5..0e99b5d 100644 --- a/src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt +++ b/src/main/java/com/ffii/fpsms/m18/utils/CommonUtils.kt @@ -4,6 +4,7 @@ import com.ffii.fpsms.m18.M18Config import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Lazy import org.springframework.stereotype.Component +import java.math.BigDecimal import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId @@ -32,4 +33,10 @@ open class CommonUtils( } return strings.joinToString(delimiter) { "$prefix$it" } } + + companion object { + fun getAmt(up: BigDecimal, discount: BigDecimal, qty: BigDecimal): Double { + return qty.times(BigDecimal(1) - discount).times(up).toDouble() + } + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt index e0a1d78..2822d1f 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/ProductionScheduleService.kt @@ -338,12 +338,14 @@ open class ProductionScheduleService( // Job Order Bom Material val jobmRequests = bom.bomMaterials.map { bm -> val demandQty = bm.qty?.times(proportion) ?: BigDecimal.ZERO + val saleUnit = bm.item?.id?.let { itemUomService.findSalesUnitByItemId(it) } + println("itemId: ${bm.item?.id} | itemNo: ${bm.item?.code} | itemName: ${bm.item?.name} | saleUnit: ${saleUnit?.uom?.udfudesc}") val jobm = CreateJobOrderBomMaterialRequest( joId = jo.id, itemId = bm.item?.id, reqQty = bm.qty?.times(proportion) ?: BigDecimal.ZERO, - uomId = bm.salesUnit?.id + uomId = saleUnit?.uom?.id ) jobm @@ -354,7 +356,7 @@ open class ProductionScheduleService( } // Inventory - val inventories = bom.bomMaterials.map { bm -> + /* val inventories = bom.bomMaterials.map { bm -> val demandQty = bm.qty?.times(proportion) ?: BigDecimal.ZERO var inventory = bm.item?.id?.let { inventoryRepository.findByItemId(it).getOrNull() } @@ -388,7 +390,7 @@ open class ProductionScheduleService( } } - inventoryRepository.saveAllAndFlush(inventories) + inventoryRepository.saveAllAndFlush(inventories) */ } // Create Job Order Process @@ -874,12 +876,14 @@ open class ProductionScheduleService( for (i in 5 until 12) { try { val prodSchedule = productionScheduleRepository.findById(parentId).get() - val item = roughScheduleObj.fgDetail?.id?.let { itemService.findById(it) } ?: Items() + val item = roughScheduleObj.fgDetail?.id?.let { itemService.findById(it) } var savedItem = ProductionScheduleLine() savedItem.id = -1; // savedItem.prodScheduleId = parentId; savedItem.productionSchedule = prodSchedule; - savedItem.item = item; + if (item != null) { + savedItem.item = item + }; savedItem.lastMonthAvgSales = roughScheduleObj.fgDetail?.lastMonthAvgSalesCount ?: 0.0; savedItem.refScheduleId = null; savedItem.approverId = null; diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/ShopService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/ShopService.kt index bf6134e..b7c5481 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/ShopService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/ShopService.kt @@ -41,24 +41,28 @@ open class ShopService( open fun saveShop(request: SaveShopRequest): SaveShopResponse { val shop = if (request.m18Id != null) { - findVendorByM18Id(request.m18Id) ?: Shop() + when (request.type){ + "supplier" -> findVendorByM18Id(request.m18Id) ?: Shop() + "shop" -> findShopByM18Id(request.m18Id) ?: Shop() + else -> Shop(); + } } else { request.id?.let { shopRepository.findById(it).getOrDefault(Shop()) } ?: Shop() } - if (shop.m18LastModifyDate == request.m18LastModifyDate) { + if (shop?.m18LastModifyDate == request.m18LastModifyDate) { return shop.let { SaveShopResponse( - id = it.id, - code = it.code, - name = it.name, + id = it?.id, + code = it?.code, + name = it?.name, ) } } val type = request.type?.let { type -> ShopType.entries.find { it.value == type } } - shop.apply { + shop?.apply { code = request.code name = request.name brNo = request.brNo @@ -77,9 +81,9 @@ open class ShopService( val response = shopRepository.saveAndFlush(shop).let { SaveShopResponse( - id = it.id, - code = it.code, - name = it.name, + id = it?.id, + code = it?.code, + name = it?.name, ) } diff --git a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderService.kt b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderService.kt index eda66bc..d64983f 100644 --- a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderService.kt @@ -3,7 +3,10 @@ package com.ffii.fpsms.modules.purchaseOrder.service import com.ffii.core.response.RecordsRes import com.ffii.core.support.AbstractBaseEntityService import com.ffii.core.support.JdbcDao +import com.ffii.fpsms.m18.entity.GrnSendLog +import com.ffii.fpsms.m18.entity.GrnSendLogRepository import com.ffii.fpsms.m18.entity.M18DataLogRepository +import com.ffii.fpsms.m18.utils.CommonUtils import com.ffii.fpsms.modules.master.entity.ShopRepository import com.ffii.fpsms.modules.master.service.CurrencyService import com.ffii.fpsms.modules.master.service.ShopService @@ -17,19 +20,19 @@ import com.ffii.fpsms.modules.purchaseOrder.entity.projections.PurchaseOrderInfo 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.web.model.PagingRequest -import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderRequest -import com.ffii.fpsms.modules.purchaseOrder.web.model.SavePurchaseOrderResponse +import com.ffii.fpsms.modules.purchaseOrder.web.model.* import com.ffii.fpsms.modules.stock.entity.StockInLine import com.ffii.fpsms.modules.stock.entity.StockInLineRepository import com.ffii.fpsms.modules.stock.entity.StockInRepository import com.ffii.fpsms.modules.stock.web.model.StockInLineStatus +import com.google.gson.Gson import org.springframework.data.domain.Page import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.io.IOException +import java.math.BigDecimal import java.time.LocalDateTime import java.util.HashMap import java.util.Objects @@ -47,6 +50,7 @@ open class PurchaseOrderService( private val stockInLineRepository: StockInLineRepository, private val currencyService: CurrencyService, private val shopService: ShopService, + private val grnSendLogRepository: GrnSendLogRepository, ) : AbstractBaseEntityService(jdbcDao, purchaseOrderRepository) { // open fun getPurchaseOrderInfo(args: Map): List> { // val sql = StringBuilder( @@ -91,6 +95,7 @@ open class PurchaseOrderService( sql.append(" and sil.purchaseOrderId IS NULL "); } } + sql.append(" order by po.orderDate desc") val list = jdbcDao.queryForList(sql.toString(), args); println(list) @@ -226,6 +231,10 @@ open class PurchaseOrderService( @Transactional open fun checkPolAndCompletePo(id: Long): MessageResponse { val unfinishedLines = polRepository.findAllByPurchaseOrderIdAndStatusNotAndDeletedIsFalse(purchaseOrderId = id, status = PurchaseOrderLineStatus.COMPLETED) +// val purchaseOrderLine = polRepository.findAllByPurchaseOrderIdAndDeletedIsFalse(purchaseOrderId = id) +// val unfinishedLines = purchaseOrderLine.filter { +// it.status != PurchaseOrderLineStatus.COMPLETED +// } // val unfinishedLines = polRepository.findAllByPurchaseOrderIdAndDeletedIsFalse(purchaseOrderId = id) // .filter { // it.status != PurchaseOrderLineStatus.COMPLETED | @@ -233,12 +242,47 @@ open class PurchaseOrderService( // } println("unfinishedLines") println(unfinishedLines) + val po = purchaseOrderRepository.findById(id).orElseThrow() if (unfinishedLines.isEmpty()) { + val stockInLines = stockInLineRepository.findAllByPurchaseOrderIdAndDeletedFalse(po.id).orElseThrow() po.apply { status = PurchaseOrderStatus.COMPLETED } val savedPo = purchaseOrderRepository.saveAndFlush(po) + // map request + val antRequest = stockInLines.map { + Ant( + proCode = it.itemNo!!, + unitCode = it.purchaseOrderLine!!.uom!!.code!!, + locCode = it.inventoryLotLine!!.warehouse!!.code!!, + qty = it.acceptedQty!!.toDouble(), + up = (it.purchaseOrderLine!!.up ?: 0.0).toDouble(), + amt = CommonUtils.getAmt( + up = (it.purchaseOrderLine!!.up ?: BigDecimal(0)), + discount = it.purchaseOrderLine!!.m18Discount ?: BigDecimal(0), + qty = it.acceptedQty!! + ) + ) + } + val postGrnRequest = PostGrnRequest( + beId = po!!.m18BeId!!, + venCode = po.supplier!!.code!!, + ant = antRequest + ) + // post grn api + // log in grn send log + val grnSendLog = GrnSendLog().apply { + this.refType = "purchase order" + this.data = mutableMapOf( + "beId" to postGrnRequest.beId, + "venCode" to postGrnRequest.venCode, + "ant" to postGrnRequest.ant, + ) + this.status = true + } + grnSendLogRepository.save(grnSendLog) + return MessageResponse( id = savedPo.id, name = savedPo.code, diff --git a/src/main/java/com/ffii/fpsms/modules/purchaseOrder/web/model/PostGrnRequest.kt b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/web/model/PostGrnRequest.kt new file mode 100644 index 0000000..f1a663b --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/purchaseOrder/web/model/PostGrnRequest.kt @@ -0,0 +1,16 @@ +package com.ffii.fpsms.modules.purchaseOrder.web.model + +data class Ant( // stock in line + val proCode: String, + val unitCode: String, + val locCode: String, + val qty: Double, + val up: Double, + val amt: Double, +) +data class PostGrnRequest( + val beId: Long, + val venCode: String, + val ant: List + +) diff --git a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt index 104e430..a88beef 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/entity/StockInLineRepository.kt @@ -16,4 +16,5 @@ interface StockInLineRepository : AbstractRepository { fun findStockInLineInfoByPurchaseOrderLineIdAndDeletedFalse(purchaseOrderLineId: Long): List fun findStockInLineInfoByIdAndStatusAndDeletedFalse(id: Long, status: String): Optional fun findAllStockInLineInfoByPurchaseOrderIdAndStatusStartsWithAndDeletedFalse(purchaseOrderId: Long, status: String): List> + fun findAllByPurchaseOrderIdAndDeletedFalse(purchaseOrderId: Long): Optional> } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt b/src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt index ae6660c..2a5eaaa 100644 --- a/src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt +++ b/src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt @@ -2,6 +2,7 @@ package com.ffii.fpsms.modules.stock.service import com.ffii.core.support.AbstractBaseEntityService import com.ffii.core.support.JdbcDao +import com.ffii.fpsms.modules.master.entity.ItemUomRespository import com.ffii.fpsms.modules.master.entity.ItemsRepository import com.ffii.fpsms.modules.master.web.models.MessageResponse import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository @@ -25,6 +26,7 @@ open class StockOutLineService( private val stockOutLineRepository: StockOutLIneRepository, private val itemRepository: ItemsRepository, private val inventoryRepository: InventoryRepository, + private val itemUomRespository: ItemUomRespository, private val inventoryLotLineRepository: InventoryLotLineRepository ): AbstractBaseEntityService(jdbcDao, stockOutLineRepository) { @Throws(IOException::class) @@ -117,19 +119,24 @@ open class StockOutLineService( this.status = StockOutLineStatus.COMPLETE.status // complete } // update inventory lot line + val zero = BigDecimal.ZERO + val one = BigDecimal.ONE val targetLotLine = inventoryLotLineRepository.findById(request.inventoryLotLineId!!).orElseThrow() + val salesUnit = inventoryLotLine?.inventoryLot?.item?.id?.let {_itemId -> itemUomRespository.findByItemIdAndSalesUnitIsTrueAndDeletedIsFalse(_itemId) } + val ratio = (salesUnit?.ratioN ?: zero).divide(salesUnit?.ratioD ?: one).toDouble() val targetLotLineEntry = targetLotLine.apply { - this.outQty = (this.outQty?: BigDecimal.ZERO) + request.qty.toBigDecimal() - this.holdQty = this.holdQty!!.minus(request.qty.toBigDecimal()) + + this.outQty = (this.outQty?: BigDecimal.ZERO) + (request.qty.div(ratio)).toBigDecimal() + this.holdQty = this.holdQty!!.minus((request.qty.div(ratio)).toBigDecimal()) } inventoryLotLineRepository.save(targetLotLineEntry) // update inventory val inventory = inventoryRepository.findByItemId(request.itemId).orElseThrow() val inventoryEntry = inventory.apply { - this.onHandQty = this.onHandQty!!.minus(request.qty.toBigDecimal()) - this.onHoldQty = this.onHoldQty!!.minus(request.qty.toBigDecimal()) + this.onHandQty = this.onHandQty!!.minus((request.qty.div(ratio)).toBigDecimal()) + this.onHoldQty = this.onHoldQty!!.minus((request.qty.div(ratio)).toBigDecimal()) } - + inventoryRepository.save(inventoryEntry) return listOf(stockOutLine, newStockOutLine) } @Transactional diff --git a/src/main/resources/db/changelog/changes/20250724_derek/01_create_GRN_post_log.sql b/src/main/resources/db/changelog/changes/20250724_derek/01_create_GRN_post_log.sql new file mode 100644 index 0000000..5e1a6a9 --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250724_derek/01_create_GRN_post_log.sql @@ -0,0 +1,17 @@ +--liquibase formatted sql + +--changeset derek:grn psot log +CREATE TABLE `grn_send_log` +( + `id` INT NOT NULL AUTO_INCREMENT, + `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `createdBy` VARCHAR(30) NULL DEFAULT NULL, + `version` INT NOT NULL DEFAULT '0', + `modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `modifiedBy` VARCHAR(30) NULL DEFAULT NULL, + `deleted` TINYINT(1) NOT NULL DEFAULT '0', + `refType` VARCHAR(1000) NOT NULL, + `data` JSON NOT NULL, + `status` TINYINT(1) NOT NULL, + CONSTRAINT pk_grn_post_log PRIMARY KEY (id) +); \ No newline at end of file