| @@ -0,0 +1,24 @@ | |||||
| package com.ffii.fpsms.modules.bag.entity | |||||
| import com.fasterxml.jackson.annotation.JsonManagedReference | |||||
| import com.ffii.core.entity.BaseEntity | |||||
| import com.ffii.fpsms.m18.entity.M18DataLog | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | |||||
| import jakarta.validation.constraints.Size | |||||
| import java.time.LocalDateTime | |||||
| @Entity | |||||
| @Table(name = "bag") | |||||
| open class Bag: BaseEntity<Long>() { | |||||
| @Column(name = "itemId", nullable = false) | |||||
| open var itemId: Long? = null | |||||
| @Column(name = "itemCode", nullable = false) | |||||
| open var itemCode: String? = null | |||||
| @Column(name = "itemName", nullable = false) | |||||
| open var itemName: String? = null | |||||
| @Column(name = "takenBagBalance", nullable = false) | |||||
| open var takenBagBalance: Int? = null | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| package com.ffii.fpsms.modules.bag.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| import org.springframework.data.jpa.repository.JpaRepository | |||||
| import org.springframework.data.jpa.repository.Query | |||||
| import org.springframework.data.repository.query.Param | |||||
| import org.springframework.data.domain.Page | |||||
| import org.springframework.data.domain.Pageable | |||||
| import org.springframework.stereotype.Repository | |||||
| import java.io.Serializable | |||||
| import java.time.LocalDateTime | |||||
| @Repository | |||||
| interface BagLotLineRepository : AbstractRepository<BagLotLine, Long> { | |||||
| fun findAllByBagId(bagId: Long): List<BagLotLine> | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| package com.ffii.fpsms.modules.bag.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| import org.springframework.data.jpa.repository.JpaRepository | |||||
| import org.springframework.data.jpa.repository.Query | |||||
| import org.springframework.data.repository.query.Param | |||||
| import org.springframework.data.domain.Page | |||||
| import org.springframework.data.domain.Pageable | |||||
| import org.springframework.stereotype.Repository | |||||
| import java.io.Serializable | |||||
| import java.time.LocalDateTime | |||||
| @Repository | |||||
| interface BagRepository : AbstractRepository<Bag, Long> { | |||||
| fun findAllByDeletedIsFalse(): List<Bag> | |||||
| fun findByItemIdAndDeletedIsFalse(itemId: Long): Bag? | |||||
| } | |||||
| @@ -0,0 +1,45 @@ | |||||
| package com.ffii.fpsms.modules.bag.entity | |||||
| import com.fasterxml.jackson.annotation.JsonManagedReference | |||||
| import com.ffii.core.entity.BaseEntity | |||||
| import com.ffii.fpsms.m18.entity.M18DataLog | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | |||||
| import jakarta.validation.constraints.Size | |||||
| import java.time.LocalDate | |||||
| import java.time.LocalDateTime | |||||
| @Entity | |||||
| @Table(name = "jo_bag_consumption") | |||||
| open class JoBagConsumption: BaseEntity<Long>() { | |||||
| @Column(name = "bagId", nullable = false) | |||||
| open var bagId: Long? = null | |||||
| @Column(name = "bagLotLineId", nullable = false) | |||||
| open var bagLotLineId: Long? = null | |||||
| @Column(name = "jobId", nullable = false) | |||||
| open var jobId: Long? = null | |||||
| @Column(name = "jobOrderCode", nullable = false) | |||||
| open var jobOrderCode: String? = null | |||||
| @Column(name = "stockOutLineId", nullable = false) | |||||
| open var stockOutLineId: Long? = null | |||||
| @Column(name = "startQty", nullable = false) | |||||
| open var startQty: Int? = null | |||||
| @Column(name = "consumedQty", nullable = false) | |||||
| open var consumedQty: Int? = null | |||||
| @Column(name = "scrapQty", nullable = false) | |||||
| open var scrapQty: Int? = null | |||||
| @Column(name = "endQty", nullable = false) | |||||
| open var endQty: Int? = null | |||||
| @Column(name = "date", nullable = false) | |||||
| open var date: LocalDate? = null | |||||
| @Column(name = "time", nullable = false) | |||||
| open var time: LocalDateTime? = null | |||||
| } | |||||
| @@ -0,0 +1,42 @@ | |||||
| package com.ffii.fpsms.modules.bag.entity | |||||
| import com.fasterxml.jackson.annotation.JsonManagedReference | |||||
| import com.ffii.core.entity.BaseEntity | |||||
| import com.ffii.fpsms.m18.entity.M18DataLog | |||||
| import jakarta.persistence.* | |||||
| import jakarta.validation.constraints.NotNull | |||||
| import jakarta.validation.constraints.Size | |||||
| import java.time.LocalDateTime | |||||
| import java.time.LocalDate | |||||
| import java.time.LocalTime | |||||
| @Entity | |||||
| @Table(name = "bag_lot_line") | |||||
| open class BagLotLine: BaseEntity<Long>() { | |||||
| @Column(name = "bagId", nullable = false) | |||||
| open var bagId: Long? = null | |||||
| @Column(name = "stockOutLineId", nullable = false) | |||||
| open var stockOutLineId: Long? = null | |||||
| @Column(name = "lotId", nullable = false) | |||||
| open var lotId: Long? = null | |||||
| @Column(name = "lotNo", nullable = false) | |||||
| open var lotNo: String? = null | |||||
| @Column(name = "firstUseDate", nullable = false) | |||||
| open var firstUseDate: LocalDate? = null | |||||
| @Column(name = "lastUseDate", nullable = false) | |||||
| open var lastUseDate: LocalDate? = null | |||||
| @Column(name = "startQty", nullable = false) | |||||
| open var startQty: Int? = null | |||||
| @Column(name = "consumedQty", nullable = false) | |||||
| open var consumedQty: Int? = null | |||||
| @Column(name = "scrapQty", nullable = false) | |||||
| open var scrapQty: Int? = null | |||||
| @Column(name = "balanceQty", nullable = false) | |||||
| open var balanceQty: Int? = null | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| package com.ffii.fpsms.modules.bag.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| import org.springframework.data.jpa.repository.JpaRepository | |||||
| import org.springframework.data.jpa.repository.Query | |||||
| import org.springframework.data.repository.query.Param | |||||
| import org.springframework.data.domain.Page | |||||
| import org.springframework.data.domain.Pageable | |||||
| import org.springframework.stereotype.Repository | |||||
| import java.io.Serializable | |||||
| import java.time.LocalDateTime | |||||
| @Repository | |||||
| interface JoBagConsumptionRepository : AbstractRepository<JoBagConsumption, Long> { | |||||
| } | |||||
| @@ -0,0 +1,156 @@ | |||||
| package com.ffii.fpsms.modules.bag.service | |||||
| import com.ffii.fpsms.modules.bag.entity.Bag | |||||
| import com.ffii.fpsms.modules.bag.entity.BagLotLine | |||||
| import com.ffii.fpsms.modules.bag.entity.JoBagConsumption | |||||
| import org.springframework.stereotype.Service | |||||
| import com.ffii.fpsms.modules.bag.web.model.* | |||||
| import com.ffii.fpsms.modules.bag.entity.BagRepository | |||||
| import com.ffii.fpsms.modules.bag.entity.BagLotLineRepository | |||||
| import com.ffii.fpsms.modules.bag.entity.JoBagConsumptionRepository | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| import com.ffii.fpsms.modules.stock.entity.InventoryLotRepository | |||||
| import java.time.LocalTime | |||||
| import java.time.LocalDateTime | |||||
| import java.time.LocalDate | |||||
| import com.ffii.fpsms.modules.jobOrder.entity.JobOrderRepository | |||||
| @Service | |||||
| open class BagService( | |||||
| private val bagRepository: BagRepository, | |||||
| private val bagLotLineRepository: BagLotLineRepository, | |||||
| private val joBagConsumptionRepository: JoBagConsumptionRepository, | |||||
| private val inventoryLotRepository: InventoryLotRepository, | |||||
| private val jobOrderRepository: JobOrderRepository | |||||
| ) { | |||||
| open fun createBagLotLinesByBagId(request: CreateBagLotLineRequest): MessageResponse { | |||||
| val bag = bagRepository.findById(request.bagId).orElse(null) | |||||
| val lot = inventoryLotRepository.findByLotNoAndItemId(request.lotNo, request.itemId) | |||||
| val bagLotLine = BagLotLine().apply { | |||||
| this.bagId = bag?.id | |||||
| this.lotId = lot?.id | |||||
| this.lotNo = lot?.lotNo | |||||
| this.startQty = request.stockQty | |||||
| this.consumedQty = 0 | |||||
| this.stockOutLineId = request.stockOutLineId | |||||
| this.scrapQty = 0 | |||||
| this.balanceQty = request.stockQty | |||||
| } | |||||
| bagLotLineRepository.save(bagLotLine) | |||||
| bag.takenBagBalance = (bag.takenBagBalance ?: 0) + (bagLotLine.balanceQty ?: 0) | |||||
| bagRepository.save(bag) | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = null, | |||||
| message = null, | |||||
| errorPosition = null, | |||||
| entity = null, | |||||
| ) | |||||
| } | |||||
| fun createJoBagConsumption(request: CreateJoBagConsumptionRequest): MessageResponse { | |||||
| val bag = bagRepository.findById(request.bagId).orElse(null) | |||||
| println("bagId: ${bag?.id}") | |||||
| println(request.toString()) | |||||
| if (bag == null) { | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = "error", | |||||
| message = "Bag not found with id: ${request.bagId}", | |||||
| errorPosition = null, | |||||
| entity = null, | |||||
| ) | |||||
| } | |||||
| val bagLotLine = bagLotLineRepository.findById(request.bagLotLineId).orElse(null) | |||||
| println("bagLotLineId: ${bagLotLine?.id}") | |||||
| if (bagLotLine == null) { | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = "error", | |||||
| message = "BagLotLine not found with id: ${request.bagLotLineId}", | |||||
| errorPosition = null, | |||||
| entity = null, | |||||
| ) | |||||
| } | |||||
| val startQty = bagLotLine.startQty ?: 0 | |||||
| if (startQty < request.consumedQty + request.scrapQty) { | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = "error", | |||||
| message = "Insufficient balance. Available: $startQty, Requested: ${request.consumedQty + request.scrapQty}", | |||||
| errorPosition = null, | |||||
| entity = null, | |||||
| ) | |||||
| } | |||||
| val newBalanceQty = startQty - request.consumedQty - request.scrapQty | |||||
| if (bagLotLine.firstUseDate == null) | |||||
| { | |||||
| bagLotLine.firstUseDate = LocalDate.now() | |||||
| bagLotLineRepository.save(bagLotLine) | |||||
| } | |||||
| bagLotLine.consumedQty = (bagLotLine.consumedQty ?: 0) + request.consumedQty | |||||
| bagLotLine.scrapQty = (bagLotLine.scrapQty ?: 0) + request.scrapQty | |||||
| bagLotLine.balanceQty = newBalanceQty | |||||
| bagLotLine.lastUseDate = LocalDate.now() | |||||
| bagLotLineRepository.save(bagLotLine) | |||||
| val consumedTotal = request.consumedQty + request.scrapQty | |||||
| val jobOrder = jobOrderRepository.findById(request.jobId).orElse(null) | |||||
| bag.takenBagBalance = (bag.takenBagBalance ?: 0) - consumedTotal | |||||
| bagRepository.save(bag) | |||||
| val joBagConsumption = JoBagConsumption().apply { | |||||
| this.bagId = request.bagId | |||||
| this.bagLotLineId = request.bagLotLineId | |||||
| this.jobId = request.jobId | |||||
| this.stockOutLineId = bagLotLine.stockOutLineId | |||||
| this.jobOrderCode=jobOrder?.code?:"" | |||||
| this.startQty = startQty | |||||
| this.consumedQty = request.consumedQty | |||||
| this.scrapQty = request.scrapQty | |||||
| this.endQty = newBalanceQty | |||||
| this.date = LocalDate.now() | |||||
| this.time = LocalDateTime.now() | |||||
| } | |||||
| joBagConsumptionRepository.save(joBagConsumption) | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = null, | |||||
| message = null, | |||||
| errorPosition = null, | |||||
| entity = null, | |||||
| ) | |||||
| } | |||||
| open fun getAllBagInfo(): List<BagInfo> { | |||||
| val bags = bagRepository.findAllByDeletedIsFalse() | |||||
| return bags.flatMap { bag -> | |||||
| val bagLotLines = bagLotLineRepository.findAllByBagId(bag.id) | |||||
| bagLotLines.map { bagLotLine -> | |||||
| BagInfo( | |||||
| id = bagLotLine.id, | |||||
| bagId = bag.id, | |||||
| bagName = bag?.itemName?:"", | |||||
| lotId = bagLotLine.lotId ?: 0L, | |||||
| lotNo = bagLotLine.lotNo ?: "", | |||||
| stockOutLineId = bagLotLine.stockOutLineId ?: 0L, | |||||
| code = bag?.itemCode ?: "", | |||||
| balanceQty = bagLotLine.balanceQty ?: 0, | |||||
| ) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,50 @@ | |||||
| package com.ffii.fpsms.modules.bag.web | |||||
| import com.ffii.core.response.RecordsRes | |||||
| import com.ffii.fpsms.modules.bag.service.BagService | |||||
| import jakarta.validation.Valid | |||||
| import org.springframework.web.bind.annotation.GetMapping | |||||
| import org.springframework.web.bind.annotation.ModelAttribute | |||||
| import org.springframework.web.bind.annotation.PathVariable | |||||
| import org.springframework.web.bind.annotation.PostMapping | |||||
| import org.springframework.web.bind.annotation.RequestBody | |||||
| import org.springframework.web.bind.annotation.RequestMapping | |||||
| import org.springframework.web.bind.annotation.RestController | |||||
| import com.ffii.fpsms.modules.jobOrder.service.JoPickOrderService | |||||
| import com.ffii.fpsms.modules.productProcess.service.ProductProcessService | |||||
| import com.ffii.fpsms.modules.jobOrder.web.model.* | |||||
| import com.ffii.fpsms.modules.jobOrder.web.model.ExportPickRecordRequest | |||||
| import com.ffii.fpsms.modules.jobOrder.web.model.PrintPickRecordRequest | |||||
| import com.ffii.fpsms.modules.jobOrder.web.model.SecondScanSubmitRequest | |||||
| import com.ffii.fpsms.modules.jobOrder.web.model.SecondScanIssueRequest | |||||
| import jakarta.servlet.http.HttpServletResponse | |||||
| import net.sf.jasperreports.engine.JasperExportManager | |||||
| import net.sf.jasperreports.engine.JasperPrint | |||||
| import org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException | |||||
| import org.springframework.context.NoSuchMessageException | |||||
| import java.io.OutputStream | |||||
| import java.io.UnsupportedEncodingException | |||||
| import java.text.ParseException | |||||
| import org.springframework.web.bind.annotation.* | |||||
| import org.springframework.web.bind.annotation.RequestParam | |||||
| import com.ffii.fpsms.modules.jobOrder.web.model.UpdateJoPickOrderHandledByRequest | |||||
| import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderInfo | |||||
| import com.ffii.fpsms.modules.jobOrder.entity.projections.JobOrderInfoWithTypeName | |||||
| import com.ffii.fpsms.modules.jobOrder.web.model.ExportFGStockInLabelRequest | |||||
| import com.ffii.fpsms.modules.bag.web.model.* | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| @RestController | |||||
| @RequestMapping("/bag") | |||||
| class BagController( | |||||
| private val bagService: BagService | |||||
| ) { | |||||
| @GetMapping("/bagInfo") | |||||
| fun getBagInfo(): List<BagInfo> { | |||||
| return bagService.getAllBagInfo() | |||||
| } | |||||
| @PostMapping("/createJoBagConsumption") | |||||
| fun createJoBagConsumption(@RequestBody request: CreateJoBagConsumptionRequest): MessageResponse { | |||||
| return bagService.createJoBagConsumption(request) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,19 @@ | |||||
| package com.ffii.fpsms.modules.bag.web.model | |||||
| data class GetAllBagInfoResponse( | |||||
| val bagId: Long, | |||||
| val bagName: String, | |||||
| val bags: List<BagInfo> | |||||
| ) | |||||
| data class BagInfo( | |||||
| val id: Long, | |||||
| val bagId: Long, | |||||
| val bagName: String, | |||||
| val lotId: Long, | |||||
| val lotNo: String, | |||||
| val stockOutLineId: Long, | |||||
| val code: String, | |||||
| val balanceQty: Int, | |||||
| ) | |||||
| @@ -0,0 +1,33 @@ | |||||
| package com.ffii.fpsms.modules.bag.web.model | |||||
| import java.time.LocalDate; | |||||
| import java.time.LocalTime; | |||||
| data class PickBagRequest( | |||||
| val bags: List<BagRequest> | |||||
| ) | |||||
| data class BagRequest( | |||||
| val bagId: Long, | |||||
| val consumedQty: Int, | |||||
| val scrapQty: Int | |||||
| ) | |||||
| data class CreateBagLotLineRequest( | |||||
| val bagId: Long, | |||||
| val stockOutLineId: Long, | |||||
| val lotId: Long, | |||||
| val itemId: Long, | |||||
| val lotNo: String, | |||||
| val stockQty: Int, | |||||
| val date: LocalDate, | |||||
| val time: LocalTime, | |||||
| ) | |||||
| data class CreateJoBagConsumptionRequest( | |||||
| val bagId: Long, | |||||
| val bagLotLineId: Long, | |||||
| val jobId: Long, | |||||
| //val startQty: Int, | |||||
| val consumedQty: Int, | |||||
| val scrapQty: Int, | |||||
| //val date: LocalDate, | |||||
| //val time: LocalTime, | |||||
| ) | |||||
| @@ -13,7 +13,7 @@ import jakarta.validation.constraints.NotNull | |||||
| import jakarta.validation.constraints.Size | import jakarta.validation.constraints.Size | ||||
| import java.math.BigDecimal | import java.math.BigDecimal | ||||
| import java.time.LocalDateTime | import java.time.LocalDateTime | ||||
| import com.ffii.fpsms.modules.productProcess.entity.ProductProcess | |||||
| @Entity | @Entity | ||||
| @Table(name = "job_order") | @Table(name = "job_order") | ||||
| open class JobOrder : BaseEntity<Long>() { | open class JobOrder : BaseEntity<Long>() { | ||||
| @@ -76,7 +76,8 @@ open class JobOrder : BaseEntity<Long>() { | |||||
| @JsonManagedReference | @JsonManagedReference | ||||
| @OneToMany(mappedBy = "jobOrder", cascade = [CascadeType.ALL], orphanRemoval = true) | @OneToMany(mappedBy = "jobOrder", cascade = [CascadeType.ALL], orphanRemoval = true) | ||||
| open var stockInLines: MutableList<StockInLine> = mutableListOf() | open var stockInLines: MutableList<StockInLine> = mutableListOf() | ||||
| @OneToOne(mappedBy = "jobOrder", fetch = FetchType.LAZY) | |||||
| open var productProcess: ProductProcess? = null | |||||
| @Column(name = "jobTypeId") | @Column(name = "jobTypeId") | ||||
| open var jobTypeId: Long? = null | open var jobTypeId: Long? = null | ||||
| @@ -21,4 +21,5 @@ fun findAllPickOrdersByItemId(@Param("itemId") itemId: Long): List<PickOrder> | |||||
| WHERE pol.pickOrder.id = :pickOrderId AND pol.deleted = false | WHERE pol.pickOrder.id = :pickOrderId AND pol.deleted = false | ||||
| """) | """) | ||||
| fun findAllByPickOrderId(@Param("pickOrderId") pickOrderId: Long): List<PickOrderLine> | fun findAllByPickOrderId(@Param("pickOrderId") pickOrderId: Long): List<PickOrderLine> | ||||
| fun findAllByPickOrderIdAndDeletedFalse(pickOrderId: Long): List<PickOrderLine> | |||||
| } | } | ||||
| @@ -479,6 +479,13 @@ open class StockInLineService( | |||||
| this.inventoryLot = stockInLine.inventoryLot ?: savedInventoryLot | this.inventoryLot = stockInLine.inventoryLot ?: savedInventoryLot | ||||
| this.lotNo = stockInLine.lotNo ?: savedInventoryLot?.lotNo | this.lotNo = stockInLine.lotNo ?: savedInventoryLot?.lotNo | ||||
| } | } | ||||
| if (stockInLine.jobOrder != null) { | |||||
| val jo = stockInLine.jobOrder | |||||
| jo?.apply { | |||||
| status = JobOrderStatus.STORING | |||||
| } | |||||
| jobOrderRepository.save(jo!!) | |||||
| } | |||||
| } else { | } else { | ||||
| return MessageResponse( | return MessageResponse( | ||||
| id = null, | id = null, | ||||
| @@ -32,10 +32,13 @@ import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderLineRecord | |||||
| import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderStatus | import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderStatus | ||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderLineRecordRepository | import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderLineRecordRepository | ||||
| import com.ffii.fpsms.modules.stock.web.model.UpdateStockOutLineStatusByQRCodeAndLotNoRequest | import com.ffii.fpsms.modules.stock.web.model.UpdateStockOutLineStatusByQRCodeAndLotNoRequest | ||||
| import com.ffii.fpsms.modules.bag.entity.BagRepository | |||||
| import com.ffii.fpsms.modules.bag.web.model.CreateBagLotLineRequest | |||||
| import com.ffii.fpsms.modules.common.CodeGenerator | import com.ffii.fpsms.modules.common.CodeGenerator | ||||
| import org.springframework.context.annotation.Lazy | import org.springframework.context.annotation.Lazy | ||||
| import com.ffii.fpsms.modules.bag.service.BagService | |||||
| import java.time.LocalTime | |||||
| @Service | @Service | ||||
| open class StockOutLineService( | open class StockOutLineService( | ||||
| private val jdbcDao: JdbcDao, | private val jdbcDao: JdbcDao, | ||||
| @@ -51,10 +54,12 @@ open class StockOutLineService( | |||||
| private val inventoryLotRepository: InventoryLotRepository, | private val inventoryLotRepository: InventoryLotRepository, | ||||
| private val doPickOrderRepository: DoPickOrderRepository, | private val doPickOrderRepository: DoPickOrderRepository, | ||||
| private val doPickOrderRecordRepository: DoPickOrderRecordRepository, | private val doPickOrderRecordRepository: DoPickOrderRecordRepository, | ||||
| private val bagRepository: BagRepository, | |||||
| private val deliveryOrderRepository: DeliveryOrderRepository, | private val deliveryOrderRepository: DeliveryOrderRepository, | ||||
| private val doPickOrderLineRepository: DoPickOrderLineRepository, | private val doPickOrderLineRepository: DoPickOrderLineRepository, | ||||
| private val doPickOrderLineRecordRepository: DoPickOrderLineRecordRepository, | private val doPickOrderLineRecordRepository: DoPickOrderLineRecordRepository, | ||||
| private val inventoryLotLineService: InventoryLotLineService | |||||
| private val inventoryLotLineService: InventoryLotLineService, | |||||
| private val bagService: BagService | |||||
| ): AbstractBaseEntityService<StockOutLine, Long, StockOutLIneRepository>(jdbcDao, stockOutLineRepository) { | ): AbstractBaseEntityService<StockOutLine, Long, StockOutLIneRepository>(jdbcDao, stockOutLineRepository) { | ||||
| @Throws(IOException::class) | @Throws(IOException::class) | ||||
| @Transactional | @Transactional | ||||
| @@ -541,7 +546,53 @@ private fun getStockOutIdFromPickOrderLine(pickOrderLineId: Long): Long { | |||||
| } | } | ||||
| val savedStockOutLine = stockOutLineRepository.saveAndFlush(stockOutLine) | val savedStockOutLine = stockOutLineRepository.saveAndFlush(stockOutLine) | ||||
| println("Updated StockOutLine: ${savedStockOutLine.id} with status: ${savedStockOutLine.status}") | println("Updated StockOutLine: ${savedStockOutLine.id} with status: ${savedStockOutLine.status}") | ||||
| try { | |||||
| val item = savedStockOutLine.item | |||||
| val inventoryLotLine = savedStockOutLine.inventoryLotLine | |||||
| // 只在状态为 completed 或 partially_completed,且数量增加时创建 BagLotLine | |||||
| val isCompletedOrPartiallyCompleted = request.status == "completed" || | |||||
| request.status == "partially_completed" || | |||||
| request.status == "PARTIALLY_COMPLETE" | |||||
| if (item?.isBag == true && | |||||
| inventoryLotLine != null && | |||||
| isCompletedOrPartiallyCompleted && | |||||
| request.qty != null && | |||||
| request.qty > 0) { | |||||
| println(" Item isBag=true, creating BagLotLine...") | |||||
| val bag = bagRepository.findByItemIdAndDeletedIsFalse(item.id!!) | |||||
| if (bag != null) { | |||||
| val lotNo = inventoryLotLine.inventoryLot?.lotNo | |||||
| if (lotNo != null) { | |||||
| val createBagLotLineRequest = CreateBagLotLineRequest( | |||||
| bagId = bag.id!!, | |||||
| lotId = inventoryLotLine.inventoryLot?.id ?: 0L, | |||||
| itemId = item.id!!, | |||||
| lotNo = lotNo, | |||||
| stockQty = request.qty.toInt(), | |||||
| date = LocalDate.now(), | |||||
| time = LocalTime.now(), | |||||
| stockOutLineId = savedStockOutLine.id | |||||
| ) | |||||
| bagService.createBagLotLinesByBagId(createBagLotLineRequest) | |||||
| println(" ✓ BagLotLine created successfully for item ${item.code}") | |||||
| } else { | |||||
| println(" ⚠️ Warning: lotNo is null, skipping BagLotLine creation") | |||||
| } | |||||
| } else { | |||||
| println(" ⚠️ Warning: Bag not found for itemId ${item.id}, skipping BagLotLine creation") | |||||
| } | |||||
| } | |||||
| } catch (e: Exception) { | |||||
| println(" ⚠️ Error creating BagLotLine: ${e.message}") | |||||
| e.printStackTrace() | |||||
| // 不中断主流程,只记录错误 | |||||
| } | |||||
| // 3. 如果被拒绝,触发特殊处理 | // 3. 如果被拒绝,触发特殊处理 | ||||
| if (request.status == "rejected" || request.status == "REJECTED") { | if (request.status == "rejected" || request.status == "REJECTED") { | ||||
| println("=== TRIGGERING LOT REJECTION LOGIC ===") | println("=== TRIGGERING LOT REJECTION LOGIC ===") | ||||
| @@ -554,8 +605,9 @@ private fun getStockOutIdFromPickOrderLine(pickOrderLineId: Long): Long { | |||||
| checkIsStockOutLineCompleted(pickOrderLine.id) | checkIsStockOutLineCompleted(pickOrderLine.id) | ||||
| // 5. 自动刷 pickOrder 状态 | // 5. 自动刷 pickOrder 状态 | ||||
| val pickOrder = pickOrderLine.pickOrder | val pickOrder = pickOrderLine.pickOrder | ||||
| if (pickOrder != null) { | |||||
| val allLines = pickOrder.pickOrderLines | |||||
| if (pickOrder != null && pickOrder.id != null) { | |||||
| // ✅ 修复:使用 repository 查询所有 lines,避免懒加载问题 | |||||
| val allLines = pickOrderLineRepository.findAllByPickOrderIdAndDeletedFalse(pickOrder.id!!) | |||||
| val allCompleted = allLines.all { it.status == PickOrderLineStatus.COMPLETED } | val allCompleted = allLines.all { it.status == PickOrderLineStatus.COMPLETED } | ||||
| if (allCompleted && allLines.isNotEmpty()) { | if (allCompleted && allLines.isNotEmpty()) { | ||||
| pickOrder.status = PickOrderStatus.COMPLETED | pickOrder.status = PickOrderStatus.COMPLETED | ||||
| @@ -1019,7 +1071,45 @@ open fun newBatchSubmit(request: QrPickBatchSubmitRequest): MessageResponse { | |||||
| ) | ) | ||||
| ) | ) | ||||
| } | } | ||||
| try { | |||||
| val stockOutLine = stockOutLines[line.stockOutLineId] | |||||
| val item = stockOutLine?.item | |||||
| val inventoryLotLine = line.inventoryLotLineId?.let { lotLines[it] } | |||||
| if (item?.isBag == true && inventoryLotLine != null && submitQty > BigDecimal.ZERO) { | |||||
| println(" Item isBag=true, creating BagLotLine...") | |||||
| // 根据 itemId 查找对应的 Bag | |||||
| val bag = bagRepository.findByItemIdAndDeletedIsFalse(item.id!!) | |||||
| if (bag != null) { | |||||
| val lotNo = inventoryLotLine.inventoryLot?.lotNo | |||||
| if (lotNo != null) { | |||||
| val createBagLotLineRequest = CreateBagLotLineRequest( | |||||
| bagId = bag.id!!, | |||||
| lotId = inventoryLotLine.inventoryLot?.id ?: 0L, | |||||
| itemId = item.id!!, | |||||
| stockOutLineId = stockOutLine.id , | |||||
| lotNo = lotNo, | |||||
| stockQty = submitQty.toInt(), // 转换为 Int | |||||
| date = LocalDate.now(), | |||||
| time = LocalTime.now() | |||||
| ) | |||||
| bagService.createBagLotLinesByBagId(createBagLotLineRequest) | |||||
| println(" ✓ BagLotLine created successfully for item ${item.code}") | |||||
| } else { | |||||
| println(" ⚠️ Warning: lotNo is null, skipping BagLotLine creation") | |||||
| } | |||||
| } else { | |||||
| println(" ⚠️ Warning: Bag not found for itemId ${item.id}, skipping BagLotLine creation") | |||||
| } | |||||
| } | |||||
| } catch (e: Exception) { | |||||
| println(" ⚠️ Error creating BagLotLine: ${e.message}") | |||||
| e.printStackTrace() | |||||
| // 不中断主流程,只记录错误 | |||||
| } | |||||
| processedIds += line.stockOutLineId | processedIds += line.stockOutLineId | ||||
| println(" ✓ Line processed successfully") | println(" ✓ Line processed successfully") | ||||
| } catch (e: Exception) { | } catch (e: Exception) { | ||||