Kaynağa Gözat

ssueTypes 改名:跳過提料(使用「已完成」)/多提/少提/擅自換批/揀錯批;Excel「問題類型」→「偏離類型」

釐清 inventoryLotLineId=實際批,對齊 actualPickLotLineId(無行為變更)
tab 數量 0 不顯示 (0);Badge→文字 (n);欄位「工單編號/貨品編號」;中文 i18n(工單流程、預計生產日期、含未按規劃完成…)
production
CANCERYS\kw093 18 saat önce
ebeveyn
işleme
85c3f9b0a1
9 değiştirilmiş dosya ile 69 ekleme ve 30 silme
  1. +2
    -2
      src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickExecutionIssueService.kt
  2. +8
    -8
      src/main/java/com/ffii/fpsms/modules/report/service/DoUserPickAuditReportService.kt
  3. +4
    -4
      src/main/java/com/ffii/fpsms/modules/report/web/DoUserPickAuditReportController.kt
  4. +22
    -3
      src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedger.kt
  5. +8
    -1
      src/main/java/com/ffii/fpsms/modules/stock/entity/SuggestedPickLot.kt
  6. +1
    -1
      src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt
  7. +21
    -8
      src/main/java/com/ffii/fpsms/modules/stock/service/StockLedgerLotSnapshot.kt
  8. +2
    -2
      src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt
  9. +1
    -1
      src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt

+ 2
- 2
src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickExecutionIssueService.kt Dosyayı Görüntüle

@@ -2370,7 +2370,7 @@ private fun updateInventoryAfterLotLineChange(lotLine: InventoryLotLine) {
e.printStackTrace() e.printStackTrace()
} }
} }
/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.0 | 2026-08-03 */
/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05 */
private fun createStockLedgerForStockOut( private fun createStockLedgerForStockOut(
stockOutLine: StockOutLine, stockOutLine: StockOutLine,
ledgerType: String? = null, ledgerType: String? = null,
@@ -2875,7 +2875,7 @@ open fun submitIssueWithQty(request: SubmitIssueWithQtyRequest): MessageResponse
} }


// New: Create stock ledger with explicit balance (to avoid double subtraction) // New: Create stock ledger with explicit balance (to avoid double subtraction)
/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.0 | 2026-08-03 */
/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05 */
private fun createStockLedgerForStockOutWithBalance( private fun createStockLedgerForStockOutWithBalance(
stockOutLine: StockOutLine, stockOutLine: StockOutLine,
balance: Double, balance: Double,


+ 8
- 8
src/main/java/com/ffii/fpsms/modules/report/service/DoUserPickAuditReportService.kt Dosyayı Görüntüle

@@ -8,10 +8,10 @@ class DoUserPickAuditReportService(
private val jdbcDao: JdbcDao, private val jdbcDao: JdbcDao,
) { ) {
/** /**
* FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.0 | 2026-08-03
* FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.1 | 2026-08-05
* DO workbench user-audit rows (Just issue only). * DO workbench user-audit rows (Just issue only).
* issueTypes may combine: 不正常已完成+超出提料+未完全提料+不正常換批.
* 未完全提料/超出提料 use POL-level SUM(stock_out_line.qty) vs pol.qty (multi-lot split OK if total matches).
* issueTypes may combine: 跳過提料(使用「已完成」)+多提+少提+擅自換批/揀錯批.
* 少提/多提 use POL-level SUM(stock_out_line.qty) vs pol.qty (multi-lot split OK if total matches).
* Only completed tickets (`dop.ticketStatus = completed`) are included. * Only completed tickets (`dop.ticketStatus = completed`) are included.
* *
* Perf: filter day/completed SOL first (`day_sol`) by pickTime only (idx_sol_pickTime_deleted), * Perf: filter day/completed SOL first (`day_sol`) by pickTime only (idx_sol_pickTime_deleted),
@@ -120,14 +120,14 @@ class DoUserPickAuditReportService(
IFNULL(d.isIssueJustComplete, 0) AS issueJustComplete, IFNULL(d.isIssueJustComplete, 0) AS issueJustComplete,
COALESCE(u.name, d.handlerName, '') AS user, COALESCE(u.name, d.handlerName, '') AS user,
TRIM(BOTH '+' FROM CONCAT_WS('+', TRIM(BOTH '+' FROM CONCAT_WS('+',
CASE WHEN IFNULL(d.isIssueJustComplete, 0) = 1 THEN '不正常已完成' ELSE NULL END,
CASE WHEN IFNULL(d.isIssueJustComplete, 0) = 1 THEN '跳過提料(使用「已完成」)' ELSE NULL END,
CASE WHEN d.polQty IS NOT NULL CASE WHEN d.polQty IS NOT NULL
AND COALESCE(pp.pickedTotal, 0) > d.polQty THEN '超出提料' ELSE NULL END,
AND COALESCE(pp.pickedTotal, 0) > d.polQty THEN '多提' ELSE NULL END,
CASE WHEN d.polQty IS NOT NULL CASE WHEN d.polQty IS NOT NULL
AND COALESCE(pp.pickedTotal, 0) < d.polQty AND COALESCE(pp.pickedTotal, 0) < d.polQty
AND d.inventoryLotLineId IS NOT NULL THEN '未完全提料' ELSE NULL END,
AND d.inventoryLotLineId IS NOT NULL THEN '少提' ELSE NULL END,
CASE WHEN sug_lot.lotNo IS NOT NULL AND act_lot.lotNo IS NOT NULL CASE WHEN sug_lot.lotNo IS NOT NULL AND act_lot.lotNo IS NOT NULL
AND sug_lot.lotNo <> act_lot.lotNo THEN '不正常換批' ELSE NULL END
AND sug_lot.lotNo <> act_lot.lotNo THEN '擅自換批/揀錯批' ELSE NULL END
)) AS issueTypes, )) AS issueTypes,
d.solId AS stockOutLineId d.solId AS stockOutLineId
FROM day_sol d FROM day_sol d
@@ -183,7 +183,7 @@ class DoUserPickAuditReportService(
return jdbcDao.queryForList(sql, args) as List<Map<String, Any?>> return jdbcDao.queryForList(sql, args) as List<Map<String, Any?>>
} }


/** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.0 | 2026-08-03 */
/** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.1 | 2026-08-05 */
fun getDistinctHandlers(): List<String> { fun getDistinctHandlers(): List<String> {
val sql = """ val sql = """
SELECT DISTINCT TRIM(COALESCE(u.name, dop.handlerName, '')) AS handler SELECT DISTINCT TRIM(COALESCE(u.name, dop.handlerName, '')) AS handler


+ 4
- 4
src/main/java/com/ffii/fpsms/modules/report/web/DoUserPickAuditReportController.kt Dosyayı Görüntüle

@@ -23,11 +23,11 @@ import java.io.ByteArrayOutputStream
class DoUserPickAuditReportController( class DoUserPickAuditReportController(
private val doUserPickAuditReportService: DoUserPickAuditReportService, private val doUserPickAuditReportService: DoUserPickAuditReportService,
) { ) {
/** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.0 | 2026-08-03 */
/** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.1 | 2026-08-05 */
@GetMapping("/do-user-pick-audit-handlers") @GetMapping("/do-user-pick-audit-handlers")
fun handlers(): List<String> = doUserPickAuditReportService.getDistinctHandlers() fun handlers(): List<String> = doUserPickAuditReportService.getDistinctHandlers()


/** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.0 | 2026-08-03 */
/** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.1 | 2026-08-05 */
@GetMapping("/print-do-user-pick-audit-excel") @GetMapping("/print-do-user-pick-audit-excel")
fun exportExcel( fun exportExcel(
@RequestParam(required = false) dateStart: String?, @RequestParam(required = false) dateStart: String?,
@@ -93,9 +93,9 @@ class DoUserPickAuditReportController(
"actualQty" to "實際提料數量", "actualQty" to "實際提料數量",
"lotBeforeQty" to "提料前庫存", "lotBeforeQty" to "提料前庫存",
"lotAfterQty" to "提料後庫存", "lotAfterQty" to "提料後庫存",
"issueJustComplete" to "不正常已完成",
"issueJustComplete" to "跳過提料(使用「已完成」)",
"user" to "提料人", "user" to "提料人",
"issueTypes" to "問題類型",
"issueTypes" to "偏離類型",
) )


var r = 0 var r = 0


+ 22
- 3
src/main/java/com/ffii/fpsms/modules/stock/entity/StockLedger.kt Dosyayı Görüntüle

@@ -21,7 +21,20 @@ open class StockLedger: BaseEntity<Long>() {
@JoinColumn(name = "stockOutLineId") @JoinColumn(name = "stockOutLineId")
open var stockOutLine: StockOutLine? = null open var stockOutLine: StockOutLine? = null


/** Lot line for this movement; prefer this over resolving via stock in/out line. */
/**
* FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05
*
* stock_ledger.inventoryLotLineId = the **actual** inventory_lot_line.id this
* in/out movement posted against (the lot whose qty changed).
*
* Not a suggested lot. For pick-order flows (FG / JO / PO), this must align with
* suggested_pick_lot.actualPickLotLineId (and stock_out_line.inventoryLotLineId),
* NOT suggested_pick_lot.suggestedLotLineId.
* If the picker switches lot (suggested A, scan B), ledger points to B.
*
* Prefer reading this column directly; do not infer lot only via stockInLine /
* stockOutLine when this is populated.
*/
@ManyToOne @ManyToOne
@JoinColumn(name = "inventoryLotLineId") @JoinColumn(name = "inventoryLotLineId")
open var inventoryLotLine: InventoryLotLine? = null open var inventoryLotLine: InventoryLotLine? = null
@@ -40,11 +53,17 @@ open class StockLedger: BaseEntity<Long>() {
@Column(name = "balance") @Column(name = "balance")
open var balance: Double? = null open var balance: Double? = null


/** Lot available qty (in−out) before this movement; null for pre-V2 rows. */
/**
* FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05
* Available qty of that same actual lot (in−out) **before** this movement; null for pre-V2 rows.
*/
@Column(name = "lotQtyBefore", precision = 14, scale = 2) @Column(name = "lotQtyBefore", precision = 14, scale = 2)
open var lotQtyBefore: BigDecimal? = null open var lotQtyBefore: BigDecimal? = null


/** Lot available qty (in−out) after this movement; null for pre-V2 rows. */
/**
* FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05
* Available qty of that same actual lot (in−out) **after** this movement; null for pre-V2 rows.
*/
@Column(name = "lotQtyAfter", precision = 14, scale = 2) @Column(name = "lotQtyAfter", precision = 14, scale = 2)
open var lotQtyAfter: BigDecimal? = null open var lotQtyAfter: BigDecimal? = null




+ 8
- 1
src/main/java/com/ffii/fpsms/modules/stock/entity/SuggestedPickLot.kt Dosyayı Görüntüle

@@ -29,7 +29,14 @@ open class SuggestedPickLot: BaseEntity<Long>() {
@JoinColumn(name = "suggestedLotLineId") @JoinColumn(name = "suggestedLotLineId")
open var suggestedLotLine: InventoryLotLine? = null open var suggestedLotLine: InventoryLotLine? = null


/** Actual picked lot line; switch/scan updates this without changing [suggestedLotLine]. */
/**
* FP-MTMS Version Checklist | Functions Ref. No. 33 | v1.0.2 | 2026-08-03
*
* Actual picked inventory_lot_line.id.
* On create: init = suggestedLotLineId; lot switch/scan updates this only (suggested stays).
* Downstream (display, COALESCE reads, stock_ledger.inventoryLotLineId / SOL.inventoryLotLineId)
* must use this, not [suggestedLotLine].
*/
@ManyToOne @ManyToOne
@JoinColumn(name = "actualPickLotLineId") @JoinColumn(name = "actualPickLotLineId")
open var actualPickLotLine: InventoryLotLine? = null open var actualPickLotLine: InventoryLotLine? = null


+ 1
- 1
src/main/java/com/ffii/fpsms/modules/stock/service/StockInLineService.kt Dosyayı Görüntüle

@@ -1378,7 +1378,7 @@ open class StockInLineService(
} }
@Transactional @Transactional


/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.0 | 2026-08-03 */
/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05 */
private fun createStockLedgerForStockIn(stockInLine: StockInLine, inQty: Double) { private fun createStockLedgerForStockIn(stockInLine: StockInLine, inQty: Double) {
val _t0 = System.nanoTime() val _t0 = System.nanoTime()
fun _msSince(t: Long): Double = (System.nanoTime() - t) / 1_000_000.0 fun _msSince(t: Long): Double = (System.nanoTime() - t) / 1_000_000.0


+ 21
- 8
src/main/java/com/ffii/fpsms/modules/stock/service/StockLedgerLotSnapshot.kt Dosyayı Görüntüle

@@ -5,15 +5,28 @@ import com.ffii.fpsms.modules.stock.entity.StockLedger
import java.math.BigDecimal import java.math.BigDecimal


/** /**
* FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.0 | 2026-08-03
* Fills [StockLedger.inventoryLotLine], [lotQtyBefore], [lotQtyAfter].
* Prefer explicit [inventoryLotLine]; else fall back to stockOutLine / stockInLine related lot.
* FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05
* *
* [lotAvailableAfterMove] = lot (in−out) **after** this movement has already been applied on the lot line.
* [signedDelta] = +inQty or −outQty for this ledger row (stock-in positive, stock-out negative of posted qty).
* Fills [StockLedger.inventoryLotLine], [lotQtyBefore], [lotQtyAfter] for each movement.
*
* [StockLedger.inventoryLotLine] / inventoryLotLineId = **actual** moved lot line id
* (the lot whose qty changed). Prefer explicit [inventoryLotLine]; else fall back to
* stockOutLine / stockInLine related lot.
*
* On pick/suggestion flows: pass/resolve the lot that was actually picked/posted
* (= suggested_pick_lot.actualPickLotLineId / stock_out_line.inventoryLotLineId),
* never suggested_pick_lot.suggestedLotLineId alone. Lot switch (suggested A, scan B)
* → ledger must point to B.
*
* [lotQtyBefore]/[lotQtyAfter] are snapshots of that same actual lot's available qty.
* [lotAvailableAfterMove] = lot (in−out) **after** this movement has already been applied.
* [signedDelta] = +inQty or −outQty for this ledger row (stock-in positive, stock-out negative).
*/ */
object StockLedgerLotSnapshot { object StockLedgerLotSnapshot {
/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.0 | 2026-08-03 */
/**
* FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05
* Sets ledger.inventoryLotLine to the actual lot, then lotQtyBefore/After from that lot.
*/
fun apply( fun apply(
ledger: StockLedger, ledger: StockLedger,
inventoryLotLine: InventoryLotLine? = null, inventoryLotLine: InventoryLotLine? = null,
@@ -34,12 +47,12 @@ object StockLedgerLotSnapshot {
ledger.lotQtyBefore = lotAvailableAfterMove.subtract(signedDelta) ledger.lotQtyBefore = lotAvailableAfterMove.subtract(signedDelta)
} }


/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.0 | 2026-08-03 */
/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05 */
fun availableQty(ill: InventoryLotLine): BigDecimal = fun availableQty(ill: InventoryLotLine): BigDecimal =
(ill.inQty ?: BigDecimal.ZERO).subtract(ill.outQty ?: BigDecimal.ZERO) (ill.inQty ?: BigDecimal.ZERO).subtract(ill.outQty ?: BigDecimal.ZERO)


/** /**
* FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.0 | 2026-08-03
* FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05
* Ledger UOM must follow the lot line's stock ItemUom → uom.id * Ledger UOM must follow the lot line's stock ItemUom → uom.id
* (same item may have lots with different UOMs; item stockUnit flag can change later). * (same item may have lots with different UOMs; item stockUnit flag can change later).
*/ */


+ 2
- 2
src/main/java/com/ffii/fpsms/modules/stock/service/StockOutLineService.kt Dosyayı Görüntüle

@@ -1509,7 +1509,7 @@ open fun newBatchSubmit(request: QrPickBatchSubmitRequest): MessageResponse {
} }
} }
@Transactional @Transactional
/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.0 | 2026-08-03 */
/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05 */
private fun createStockLedgerForStockOut(stockOutLine: StockOutLine) { private fun createStockLedgerForStockOut(stockOutLine: StockOutLine) {
val item = stockOutLine.item ?: return val item = stockOutLine.item ?: return
val inventory = itemUomService.findInventoryForItemBaseUom(item.id!!) ?: return val inventory = itemUomService.findInventoryForItemBaseUom(item.id!!) ?: return
@@ -1757,7 +1757,7 @@ open fun newBatchSubmit(request: QrPickBatchSubmitRequest): MessageResponse {
} }




/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.0 | 2026-08-03 */
/** FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05 */
private fun createStockLedgerForPickDelta( private fun createStockLedgerForPickDelta(
stockOutLine: StockOutLine, stockOutLine: StockOutLine,
deltaQty: BigDecimal, deltaQty: BigDecimal,


+ 1
- 1
src/main/java/com/ffii/fpsms/modules/stock/service/StockTakeRecordService.kt Dosyayı Görüntüle

@@ -2488,7 +2488,7 @@ private fun applyVarianceAdjustment(
} }
val newBalance = previousBalance - qtyToRemove.toDouble() val newBalance = previousBalance - qtyToRemove.toDouble()


// FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.0 | 2026-08-03
// FP-MTMS Version Checklist | Functions Ref. No. 46 | v1.0.1 | 2026-08-05
// Snapshot from live lot line (in−out) at approve time — not stock_take_record.bookQty. // Snapshot from live lot line (in−out) at approve time — not stock_take_record.bookQty.
val lotAfterAvail = StockLedgerLotSnapshot.availableQty(latestLine).subtract(qtyToRemove) val lotAfterAvail = StockLedgerLotSnapshot.availableQty(latestLine).subtract(qtyToRemove)




Yükleniyor…
İptal
Kaydet