@@ -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.beans.factory.annotation.Autowired | ||||
import org.springframework.context.annotation.Lazy | import org.springframework.context.annotation.Lazy | ||||
import org.springframework.stereotype.Component | import org.springframework.stereotype.Component | ||||
import java.math.BigDecimal | |||||
import java.time.Instant | import java.time.Instant | ||||
import java.time.LocalDateTime | import java.time.LocalDateTime | ||||
import java.time.ZoneId | import java.time.ZoneId | ||||
@@ -32,4 +33,10 @@ open class CommonUtils( | |||||
} | } | ||||
return strings.joinToString(delimiter) { "$prefix$it" } | 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 | // Job Order Bom Material | ||||
val jobmRequests = bom.bomMaterials.map { bm -> | val jobmRequests = bom.bomMaterials.map { bm -> | ||||
val demandQty = bm.qty?.times(proportion) ?: BigDecimal.ZERO | 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( | val jobm = CreateJobOrderBomMaterialRequest( | ||||
joId = jo.id, | joId = jo.id, | ||||
itemId = bm.item?.id, | itemId = bm.item?.id, | ||||
reqQty = bm.qty?.times(proportion) ?: BigDecimal.ZERO, | reqQty = bm.qty?.times(proportion) ?: BigDecimal.ZERO, | ||||
uomId = bm.salesUnit?.id | |||||
uomId = saleUnit?.uom?.id | |||||
) | ) | ||||
jobm | jobm | ||||
@@ -354,7 +356,7 @@ open class ProductionScheduleService( | |||||
} | } | ||||
// Inventory | // Inventory | ||||
val inventories = bom.bomMaterials.map { bm -> | |||||
/* val inventories = bom.bomMaterials.map { bm -> | |||||
val demandQty = bm.qty?.times(proportion) ?: BigDecimal.ZERO | val demandQty = bm.qty?.times(proportion) ?: BigDecimal.ZERO | ||||
var inventory = bm.item?.id?.let { inventoryRepository.findByItemId(it).getOrNull() } | 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 | // Create Job Order Process | ||||
@@ -874,12 +876,14 @@ open class ProductionScheduleService( | |||||
for (i in 5 until 12) { | for (i in 5 until 12) { | ||||
try { | try { | ||||
val prodSchedule = productionScheduleRepository.findById(parentId).get() | 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() | var savedItem = ProductionScheduleLine() | ||||
savedItem.id = -1; | savedItem.id = -1; | ||||
// savedItem.prodScheduleId = parentId; | // savedItem.prodScheduleId = parentId; | ||||
savedItem.productionSchedule = prodSchedule; | savedItem.productionSchedule = prodSchedule; | ||||
savedItem.item = item; | |||||
if (item != null) { | |||||
savedItem.item = item | |||||
}; | |||||
savedItem.lastMonthAvgSales = roughScheduleObj.fgDetail?.lastMonthAvgSalesCount ?: 0.0; | savedItem.lastMonthAvgSales = roughScheduleObj.fgDetail?.lastMonthAvgSalesCount ?: 0.0; | ||||
savedItem.refScheduleId = null; | savedItem.refScheduleId = null; | ||||
savedItem.approverId = null; | savedItem.approverId = null; | ||||
@@ -41,24 +41,28 @@ open class ShopService( | |||||
open fun saveShop(request: SaveShopRequest): SaveShopResponse { | open fun saveShop(request: SaveShopRequest): SaveShopResponse { | ||||
val shop = if (request.m18Id != null) { | 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 { | } else { | ||||
request.id?.let { shopRepository.findById(it).getOrDefault(Shop()) } ?: Shop() | request.id?.let { shopRepository.findById(it).getOrDefault(Shop()) } ?: Shop() | ||||
} | } | ||||
if (shop.m18LastModifyDate == request.m18LastModifyDate) { | |||||
if (shop?.m18LastModifyDate == request.m18LastModifyDate) { | |||||
return shop.let { | return shop.let { | ||||
SaveShopResponse( | 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 } } | val type = request.type?.let { type -> ShopType.entries.find { it.value == type } } | ||||
shop.apply { | |||||
shop?.apply { | |||||
code = request.code | code = request.code | ||||
name = request.name | name = request.name | ||||
brNo = request.brNo | brNo = request.brNo | ||||
@@ -77,9 +81,9 @@ open class ShopService( | |||||
val response = shopRepository.saveAndFlush(shop).let { | val response = shopRepository.saveAndFlush(shop).let { | ||||
SaveShopResponse( | 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.response.RecordsRes | ||||
import com.ffii.core.support.AbstractBaseEntityService | import com.ffii.core.support.AbstractBaseEntityService | ||||
import com.ffii.core.support.JdbcDao | 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.entity.M18DataLogRepository | ||||
import com.ffii.fpsms.m18.utils.CommonUtils | |||||
import com.ffii.fpsms.modules.master.entity.ShopRepository | import com.ffii.fpsms.modules.master.entity.ShopRepository | ||||
import com.ffii.fpsms.modules.master.service.CurrencyService | import com.ffii.fpsms.modules.master.service.CurrencyService | ||||
import com.ffii.fpsms.modules.master.service.ShopService | 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.PurchaseOrderLineStatus | ||||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus | import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus | ||||
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderType | 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.StockInLine | ||||
import com.ffii.fpsms.modules.stock.entity.StockInLineRepository | import com.ffii.fpsms.modules.stock.entity.StockInLineRepository | ||||
import com.ffii.fpsms.modules.stock.entity.StockInRepository | import com.ffii.fpsms.modules.stock.entity.StockInRepository | ||||
import com.ffii.fpsms.modules.stock.web.model.StockInLineStatus | 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.Page | ||||
import org.springframework.data.domain.PageRequest | import org.springframework.data.domain.PageRequest | ||||
import org.springframework.data.domain.Pageable | import org.springframework.data.domain.Pageable | ||||
import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||
import org.springframework.transaction.annotation.Transactional | import org.springframework.transaction.annotation.Transactional | ||||
import java.io.IOException | import java.io.IOException | ||||
import java.math.BigDecimal | |||||
import java.time.LocalDateTime | import java.time.LocalDateTime | ||||
import java.util.HashMap | import java.util.HashMap | ||||
import java.util.Objects | import java.util.Objects | ||||
@@ -47,6 +50,7 @@ open class PurchaseOrderService( | |||||
private val stockInLineRepository: StockInLineRepository, | private val stockInLineRepository: StockInLineRepository, | ||||
private val currencyService: CurrencyService, | private val currencyService: CurrencyService, | ||||
private val shopService: ShopService, | private val shopService: ShopService, | ||||
private val grnSendLogRepository: GrnSendLogRepository, | |||||
) : AbstractBaseEntityService<PurchaseOrder, Long, PurchaseOrderRepository>(jdbcDao, purchaseOrderRepository) { | ) : AbstractBaseEntityService<PurchaseOrder, Long, PurchaseOrderRepository>(jdbcDao, purchaseOrderRepository) { | ||||
// open fun getPurchaseOrderInfo(args: Map<String, Any>): List<Map<String, Any>> { | // open fun getPurchaseOrderInfo(args: Map<String, Any>): List<Map<String, Any>> { | ||||
// val sql = StringBuilder( | // val sql = StringBuilder( | ||||
@@ -91,6 +95,7 @@ open class PurchaseOrderService( | |||||
sql.append(" and sil.purchaseOrderId IS NULL "); | sql.append(" and sil.purchaseOrderId IS NULL "); | ||||
} | } | ||||
} | } | ||||
sql.append(" order by po.orderDate desc") | |||||
val list = jdbcDao.queryForList(sql.toString(), args); | val list = jdbcDao.queryForList(sql.toString(), args); | ||||
println(list) | println(list) | ||||
@@ -226,6 +231,10 @@ open class PurchaseOrderService( | |||||
@Transactional | @Transactional | ||||
open fun checkPolAndCompletePo(id: Long): MessageResponse { | open fun checkPolAndCompletePo(id: Long): MessageResponse { | ||||
val unfinishedLines = polRepository.findAllByPurchaseOrderIdAndStatusNotAndDeletedIsFalse(purchaseOrderId = id, status = PurchaseOrderLineStatus.COMPLETED) | 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) | // val unfinishedLines = polRepository.findAllByPurchaseOrderIdAndDeletedIsFalse(purchaseOrderId = id) | ||||
// .filter { | // .filter { | ||||
// it.status != PurchaseOrderLineStatus.COMPLETED | | // it.status != PurchaseOrderLineStatus.COMPLETED | | ||||
@@ -233,12 +242,47 @@ open class PurchaseOrderService( | |||||
// } | // } | ||||
println("unfinishedLines") | println("unfinishedLines") | ||||
println(unfinishedLines) | println(unfinishedLines) | ||||
val po = purchaseOrderRepository.findById(id).orElseThrow() | val po = purchaseOrderRepository.findById(id).orElseThrow() | ||||
if (unfinishedLines.isEmpty()) { | if (unfinishedLines.isEmpty()) { | ||||
val stockInLines = stockInLineRepository.findAllByPurchaseOrderIdAndDeletedFalse(po.id).orElseThrow() | |||||
po.apply { | po.apply { | ||||
status = PurchaseOrderStatus.COMPLETED | status = PurchaseOrderStatus.COMPLETED | ||||
} | } | ||||
val savedPo = purchaseOrderRepository.saveAndFlush(po) | 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( | return MessageResponse( | ||||
id = savedPo.id, | id = savedPo.id, | ||||
name = savedPo.code, | 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 findStockInLineInfoByPurchaseOrderLineIdAndDeletedFalse(purchaseOrderLineId: Long): List<StockInLineInfo> | ||||
fun findStockInLineInfoByIdAndStatusAndDeletedFalse(id: Long, status: String): Optional<StockInLineInfo> | fun findStockInLineInfoByIdAndStatusAndDeletedFalse(id: Long, status: String): Optional<StockInLineInfo> | ||||
fun findAllStockInLineInfoByPurchaseOrderIdAndStatusStartsWithAndDeletedFalse(purchaseOrderId: Long, status: String): List<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.AbstractBaseEntityService | ||||
import com.ffii.core.support.JdbcDao | 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.entity.ItemsRepository | ||||
import com.ffii.fpsms.modules.master.web.models.MessageResponse | import com.ffii.fpsms.modules.master.web.models.MessageResponse | ||||
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository | import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository | ||||
@@ -25,6 +26,7 @@ open class StockOutLineService( | |||||
private val stockOutLineRepository: StockOutLIneRepository, | private val stockOutLineRepository: StockOutLIneRepository, | ||||
private val itemRepository: ItemsRepository, | private val itemRepository: ItemsRepository, | ||||
private val inventoryRepository: InventoryRepository, | private val inventoryRepository: InventoryRepository, | ||||
private val itemUomRespository: ItemUomRespository, | |||||
private val inventoryLotLineRepository: InventoryLotLineRepository | private val inventoryLotLineRepository: InventoryLotLineRepository | ||||
): AbstractBaseEntityService<StockOutLine, Long, StockOutLIneRepository>(jdbcDao, stockOutLineRepository) { | ): AbstractBaseEntityService<StockOutLine, Long, StockOutLIneRepository>(jdbcDao, stockOutLineRepository) { | ||||
@Throws(IOException::class) | @Throws(IOException::class) | ||||
@@ -117,19 +119,24 @@ open class StockOutLineService( | |||||
this.status = StockOutLineStatus.COMPLETE.status // complete | this.status = StockOutLineStatus.COMPLETE.status // complete | ||||
} | } | ||||
// update inventory lot line | // update inventory lot line | ||||
val zero = BigDecimal.ZERO | |||||
val one = BigDecimal.ONE | |||||
val targetLotLine = inventoryLotLineRepository.findById(request.inventoryLotLineId!!).orElseThrow() | 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 { | 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) | inventoryLotLineRepository.save(targetLotLineEntry) | ||||
// update inventory | // update inventory | ||||
val inventory = inventoryRepository.findByItemId(request.itemId).orElseThrow() | val inventory = inventoryRepository.findByItemId(request.itemId).orElseThrow() | ||||
val inventoryEntry = inventory.apply { | 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) | return listOf(stockOutLine, newStockOutLine) | ||||
} | } | ||||
@Transactional | @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) | |||||
); |