| @@ -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<Long>() { | |||
| @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<String, Any?>? = null | |||
| @NotNull | |||
| @Column(name = "status") | |||
| open var status: Boolean? = null | |||
| } | |||
| @@ -0,0 +1,6 @@ | |||
| package com.ffii.fpsms.m18.entity | |||
| import com.ffii.core.support.AbstractRepository | |||
| interface GrnSendLogRepository: AbstractRepository<GrnSendLog, Long> { | |||
| } | |||
| @@ -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() | |||
| } | |||
| } | |||
| } | |||
| @@ -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; | |||
| @@ -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, | |||
| ) | |||
| } | |||
| @@ -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<PurchaseOrder, Long, PurchaseOrderRepository>(jdbcDao, purchaseOrderRepository) { | |||
| // open fun getPurchaseOrderInfo(args: Map<String, Any>): List<Map<String, Any>> { | |||
| // 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, | |||
| @@ -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<Ant> | |||
| ) | |||
| @@ -16,4 +16,5 @@ interface StockInLineRepository : AbstractRepository<StockInLine, Long> { | |||
| fun findStockInLineInfoByPurchaseOrderLineIdAndDeletedFalse(purchaseOrderLineId: Long): List<StockInLineInfo> | |||
| fun findStockInLineInfoByIdAndStatusAndDeletedFalse(id: Long, status: String): Optional<StockInLineInfo> | |||
| fun findAllStockInLineInfoByPurchaseOrderIdAndStatusStartsWithAndDeletedFalse(purchaseOrderId: Long, status: String): List<Optional<StockInLineInfo>> | |||
| fun findAllByPurchaseOrderIdAndDeletedFalse(purchaseOrderId: Long): Optional<List<StockInLine>> | |||
| } | |||
| @@ -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<StockOutLine, Long, StockOutLIneRepository>(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 | |||
| @@ -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) | |||
| ); | |||