@@ -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) | |||
); |