CANCERYS\kw093 преди 1 ден
родител
ревизия
8534521ab0
променени са 6 файла, в които са добавени 228 реда и са изтрити 44 реда
  1. +1
    -1
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/JobOrderBomMaterialService.kt
  2. +3
    -3
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/JobOrderService.kt
  3. +6
    -1
      src/main/java/com/ffii/fpsms/modules/master/entity/BomMaterial.kt
  4. +208
    -37
      src/main/java/com/ffii/fpsms/modules/master/service/BomService.kt
  5. +3
    -2
      src/main/java/com/ffii/fpsms/modules/productProcess/entity/ProductProcessLineRepository.kt
  6. +7
    -0
      src/main/resources/db/changelog/changes/20260204_Enson/01_add_bom_materail.sql

+ 1
- 1
src/main/java/com/ffii/fpsms/modules/jobOrder/service/JobOrderBomMaterialService.kt Целия файл

@@ -34,7 +34,7 @@ open class JobOrderBomMaterialService(
joId = joId,
itemId = bm.item?.id,
//reqQty = (bm.qty?.times(proportion) ?: zero).setScale(0,RoundingMode.CEILING),
reqQty = (bm.saleQty?.times(proportion) ?: zero).setScale(0, RoundingMode.CEILING),
reqQty = (bm.stockQty?.times(proportion) ?: zero).setScale(0, RoundingMode.CEILING),
uomId = stockUnit?.uom?.id
)
} ?: listOf()


+ 3
- 3
src/main/java/com/ffii/fpsms/modules/jobOrder/service/JobOrderService.kt Целия файл

@@ -454,10 +454,10 @@ open class JobOrderService(
}
// ✅ 使用 stockReqQty (bomMaterial.saleQty) 和 stockUom (bomMaterial.salesUnit)
val stockReqQty = jobm.reqQty ?: bomMaterial?.saleQty ?: BigDecimal.ZERO
val stockUomId = bomMaterial?.salesUnit?.id
val stockReqQty = jobm.reqQty ?: bomMaterial?.stockQty ?: BigDecimal.ZERO
val stockUomId = bomMaterial?.stockUnit?.toLong()
?: itemUomService.findStockUnitByItemId(itemId)?.uom?.id // Fallback: 从 Item 获取库存单位
?: jobm.uom?.id // 最后的 fallback
?: jobm.uom?.id // 最后的 fallback
SavePickOrderLineRequest(
itemId = itemId,


+ 6
- 1
src/main/java/com/ffii/fpsms/modules/master/entity/BomMaterial.kt Целия файл

@@ -52,7 +52,12 @@ open class BomMaterial : BaseEntity<Long>() {
open var baseUnit: Integer? = null
@Column(name = "baseUnitName", length = 100)
open var baseUnitName: String? = null
@Column(name = "stockQty", precision = 14, scale = 2)
open var stockQty: BigDecimal? = null
@Column(name = "stockUnit", nullable = false)
open var stockUnit: Integer? = null
@Column(name = "stockUnitName", length = 100)
open var stockUnitName: String? = null
@NotNull
@ManyToOne(optional = false)
@JoinColumn(name = "bomId", nullable = false)


+ 208
- 37
src/main/java/com/ffii/fpsms/modules/master/service/BomService.kt Целия файл

@@ -150,23 +150,25 @@ open class BomService(
var baseUnit: Integer? = null
var baseUnitName: String? = null

var stockQty: BigDecimal? = null
var stockUnit: Integer? = null
var stockUnitName: String? = null

if (item?.id != null) {
val itemId = item.id!!
try {
// ---- 1) 获取 item 的真实 stock unit ----
val stockItemUom = itemUomService.findStockUnitByItemId(itemId)
val itemStockUnit = stockItemUom?.uom
// ---- 1) 获取 item 的真实 sale unit ----
val saleItemUom = itemUomService.findSalesUnitByItemId(itemId)
val itemSaleUnit = saleItemUom?.uom
// saleUnitId: 使用 item 的 stock unit uom id
saleUnitId = itemStockUnit?.id

// saleUnitCode: 从 Excel 数据查找 uom_conversion,如果失败则使用 Excel 数据本身
// ---- 2) 确定 sale unit(来自 Excel column 7)----
if (excelSalesUnit != null) {
// Excel 找到了 uom_conversion
saleUnitId = excelSalesUnit.id
saleUnitCode = excelSalesUnit.udfudesc
// 检查 Excel sales unit 与 item stock unit 是否匹配
if (itemStockUnit != null && excelSalesUnit.id != itemStockUnit.id) {
// 检查 Excel sales unit 与 item sale unit 是否匹配
if (itemSaleUnit != null && excelSalesUnit.id != itemSaleUnit.id) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
@@ -174,7 +176,7 @@ open class BomService(
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Excel sales unit (${excelSalesUnit.code}/${excelSalesUnit.udfudesc}) does not match item stock unit (${itemStockUnit.code}/${itemStockUnit.udfudesc})",
reason = "Excel sales unit (${excelSalesUnit.code}/${excelSalesUnit.udfudesc}) does not match item sale unit (${itemSaleUnit.code}/${itemSaleUnit.udfudesc})",
srcQty = excelSaleQty,
srcUomCode = excelSalesUnit.code
)
@@ -182,7 +184,7 @@ open class BomService(
}
} else {
// Excel 没有找到 uom_conversion,使用 Excel 数据本身
saleUnitCode = excelSalesUnitCode ?: itemStockUnit?.udfudesc
saleUnitCode = excelSalesUnitCode
if (excelSalesUnitCode != null) {
bomMaterialImportIssues.add(
@@ -200,26 +202,85 @@ open class BomService(
}
}

// ---- 2) 从 saleQty + item 的真实 stock unit 转换为 baseQty ----
if (excelSaleQty != null && itemStockUnit != null) {
val baseResult = itemUomService.convertUomByItem(
ConvertUomByItemRequest(
itemId = itemId,
qty = excelSaleQty,
uomId = itemStockUnit.id!!,
targetUnit = "baseUnit"
// ---- 3) 从 saleQty(sale unit)转换为 baseQty(base unit)----
if (excelSaleQty != null && excelSalesUnit != null && excelSalesUnit.id != null) {
try {
// 先检查 item 是否有 base unit
val baseItemUom = itemUomService.findBaseUnitByItemId(itemId)
if (baseItemUom == null) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
bomCode = bomCode,
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to baseQty: item base unit not found",
srcQty = excelSaleQty,
srcUomCode = excelSalesUnit.code
)
)
} else {
val baseResult = itemUomService.convertUomByItem(
ConvertUomByItemRequest(
itemId = itemId,
qty = excelSaleQty,
uomId = excelSalesUnit.id!!,
targetUnit = "baseUnit"
)
)
baseQty = baseResult.newQty
// 获取 base unit 信息
baseUnit = baseItemUom.uom?.id?.toInt()?.let { Integer.valueOf(it) } as? Integer
baseUnitName = baseItemUom.uom?.udfudesc
// 验证转换结果
if (baseQty == null) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
bomCode = bomCode,
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to baseQty: conversion returned null",
srcQty = excelSaleQty,
srcUomCode = excelSalesUnit.code
)
)
}
}
} catch (e: IllegalArgumentException) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
bomCode = bomCode,
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to baseQty: ${e.message ?: "IllegalArgumentException"}",
srcQty = excelSaleQty,
srcUomCode = excelSalesUnit.code
)
)
)
baseQty = baseResult.newQty
}

// ---- 3) 获取 item 的真实 base unit ----
val baseItemUom = itemUomService.findBaseUnitByItemId(itemId)
baseUnit = baseItemUom?.uom?.id?.toInt()?.let { Integer.valueOf(it) } as? Integer
baseUnitName = baseItemUom?.uom?.udfudesc

// 如果 baseQty 转换失败,记录问题
if (baseQty == null && excelSaleQty != null && itemStockUnit != null) {
println("【BOM Import Warning】bomCode=$bomCode, item=${item.code} 转 baseQty 失败: ${e.message}")
} catch (e: Exception) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
bomCode = bomCode,
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to baseQty: ${e.javaClass.simpleName} - ${e.message ?: "Unknown error"}",
srcQty = excelSaleQty,
srcUomCode = excelSalesUnit.code
)
)
println("【BOM Import Error】bomCode=$bomCode, item=${item.code} 转 baseQty 失败: ${e.message}")
}
} else if (excelSaleQty != null && excelSalesUnit == null) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
@@ -227,12 +288,92 @@ open class BomService(
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to baseQty: conversion failed",
reason = "Cannot convert saleQty to baseQty: Excel sales unit not found",
srcQty = excelSaleQty,
srcUomCode = itemStockUnit.code
srcUomCode = excelSalesUnitCode
)
)
} else if (excelSaleQty != null && itemStockUnit == null) {
}

// ---- 4) 从 saleQty(sale unit)转换为 stockQty(stock unit)----
if (excelSaleQty != null && excelSalesUnit != null && excelSalesUnit.id != null) {
try {
// 先检查 item 是否有 stock unit
val stockItemUom = itemUomService.findStockUnitByItemId(itemId)
if (stockItemUom == null) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
bomCode = bomCode,
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to stockQty: item stock unit not found",
srcQty = excelSaleQty,
srcUomCode = excelSalesUnit.code
)
)
} else {
val stockResult = itemUomService.convertUomByItem(
ConvertUomByItemRequest(
itemId = itemId,
qty = excelSaleQty,
uomId = excelSalesUnit.id!!,
targetUnit = "stockUnit"
)
)
stockQty = stockResult.newQty
// 获取 stock unit 信息
stockUnit = stockItemUom.uom?.id?.toInt()?.let { Integer.valueOf(it) } as? Integer
stockUnitName = stockItemUom.uom?.udfudesc
// 验证转换结果
if (stockQty == null) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
bomCode = bomCode,
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to stockQty: conversion returned null",
srcQty = excelSaleQty,
srcUomCode = excelSalesUnit.code
)
)
}
}
} catch (e: IllegalArgumentException) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
bomCode = bomCode,
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to stockQty: ${e.message ?: "IllegalArgumentException"}",
srcQty = excelSaleQty,
srcUomCode = excelSalesUnit.code
)
)
println("【BOM Import Warning】bomCode=$bomCode, item=${item.code} 转 stockQty 失败: ${e.message}")
} catch (e: Exception) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
bomCode = bomCode,
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to stockQty: ${e.javaClass.simpleName} - ${e.message ?: "Unknown error"}",
srcQty = excelSaleQty,
srcUomCode = excelSalesUnit.code
)
)
println("【BOM Import Error】bomCode=$bomCode, item=${item.code} 转 stockQty 失败: ${e.message}")
}
} else if (excelSaleQty != null && excelSalesUnit == null) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
@@ -240,13 +381,37 @@ open class BomService(
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to baseQty: item stock unit not found",
reason = "Cannot convert saleQty to stockQty: Excel sales unit not found",
srcQty = excelSaleQty,
srcUomCode = null
srcUomCode = excelSalesUnitCode
)
)
}

// 最终检查:如果 stockQty 仍然为 null,记录问题
if (stockQty == null && excelSaleQty != null && excelSalesUnit != null && excelSalesUnit.id != null) {
// 检查是否已经记录过这个问题(避免重复)
val alreadyReported = bomMaterialImportIssues.any { issue ->
issue.itemId == item.id &&
issue.reason.contains("stockQty", ignoreCase = true) &&
issue.srcQty == excelSaleQty
}
if (!alreadyReported) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
bomId = bomId,
bomCode = bomCode,
itemId = item.id,
itemCode = item.code,
itemName = item.name,
reason = "Cannot convert saleQty to stockQty: conversion failed (final check)",
srcQty = excelSaleQty,
srcUomCode = excelSalesUnit.code
)
)
}
}

} catch (e: IllegalArgumentException) {
bomMaterialImportIssues.add(
BomMaterialImportIssue(
@@ -301,15 +466,21 @@ open class BomService(
this.uom = req.uom // BOM 原始 UOM(column 3,保留)
this.uomName = req.uomName

// 新逻辑:使用 Excel column 6 的 saleQty 和 item stock unit
// 新逻辑:使用 Excel column 6 的 saleQty 和 column 7 的 sales unit
this.saleQty = saleQty
this.salesUnit = item?.id?.let { itemUomService.findStockUnitByItemId(it)?.uom }
this.salesUnit = excelSalesUnit // 使用 Excel 的 sales unit,不是 item 的 stock unit
this.salesUnitCode = saleUnitCode

// 从 sale unit 转换为 base unit
this.baseQty = baseQty
this.baseUnit = baseUnit
this.baseUnitName = baseUnitName

// 从 sale unit 转换为 stock unit(新增)
this.stockQty = stockQty
this.stockUnit = stockUnit
this.stockUnitName = stockUnitName

this.bom = req.bom
}
return bomMaterialRepository.saveAndFlush(bomMaterial)


+ 3
- 2
src/main/java/com/ffii/fpsms/modules/productProcess/entity/ProductProcessLineRepository.kt Целия файл

@@ -2,12 +2,13 @@ package com.ffii.fpsms.modules.productProcess.entity

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
import org.springframework.data.jpa.repository.Query
@Repository
interface ProductProcessLineRepository : JpaRepository<ProductProcessLine, Long> {
fun findByProductProcess_Id(productProcessId: Long): List<ProductProcessLine>
fun findByProductProcess_IdAndHandler_Id(productProcessId: Long, handlerId: Long): List<ProductProcessLine>
fun findByHandler_IdAndStartTimeIsNotNullAndEndTimeIsNull(handlerId: Long): List<ProductProcessLine>
fun findByProductProcess_IdIn(ids: List<Long>): List<ProductProcessLine>

@Query("SELECT l FROM ProductProcessLine l LEFT JOIN FETCH l.equipment WHERE l.productProcess.id = :productProcessId")
fun findByProductProcess_IdWithEquipment(productProcessId: Long): List<ProductProcessLine>
}

+ 7
- 0
src/main/resources/db/changelog/changes/20260204_Enson/01_add_bom_materail.sql Целия файл

@@ -0,0 +1,7 @@
-- liquibase formatted sql
-- changeset KelvinY:add_baseScore_to_bom

ALTER TABLE `fpsmsdb`.`bom_material`
ADD COLUMN `stockQty` DECIMAL(14, 2) NULL DEFAULT NULL AFTER `salesUnitCode`,
ADD COLUMN `stockUnit` INTEGER NULL DEFAULT NULL AFTER `stockQty`,
ADD COLUMN `stockUnitName` VARCHAR(255) NULL DEFAULT NULL AFTER `stockUnit`;

Зареждане…
Отказ
Запис