Просмотр исходного кода

updates for some items missing the () uom of job order list which using by python

production
[email protected] 1 неделю назад
Родитель
Сommit
306a8474c6
3 измененных файлов: 122 добавлений и 55 удалений
  1. +3
    -2
      src/main/java/com/ffii/fpsms/py/PyJobOrderListItem.kt
  2. +46
    -53
      src/main/java/com/ffii/fpsms/py/PyJobOrderListMapper.kt
  3. +73
    -0
      src/test/kotlin/com/ffii/fpsms/py/PyJobOrderListMapperTest.kt

+ 3
- 2
src/main/java/com/ffii/fpsms/py/PyJobOrderListItem.kt Просмотреть файл

@@ -8,8 +8,9 @@ import java.time.LocalDateTime
* No login required.
* stockInLineId and itemId are for QR code: {"itemId": xxx, "stockInLineId": xxx}
* lotNo replaces job order no. on the label display.
* [itemName] is BOM/item display name plus stock UOM [udfudesc] in parentheses, e.g. "名稱(單位)";
* if the name already contains both "(" and ")", the stock unit is not appended.
* [itemName] is BOM/item display name plus stock UOM [udfudesc] in parentheses, e.g. "名稱(1包X2磅)";
* stock unit is not appended when a parenthetical segment already looks like packaging UOM
* (digits + unit tokens). Usage/grade notes in parentheses, e.g. "(菠菜用)" or "(P+4)", still get UOM appended.
*/
data class PyJobOrderListItem(
val id: Long,


+ 46
- 53
src/main/java/com/ffii/fpsms/py/PyJobOrderListMapper.kt Просмотреть файл

@@ -1,96 +1,89 @@
package com.ffii.fpsms.py



import com.ffii.fpsms.modules.jobOrder.entity.JobOrder

import com.ffii.fpsms.modules.master.service.ItemUomService

import com.ffii.fpsms.modules.stock.entity.StockInLineRepository

object PyJobOrderListMapper {

private val GRADE_IN_PARENS = Regex("""^P\+\d+$""", RegexOption.IGNORE_CASE)
private val PAREN_SEGMENT = Regex("""[((]([^()()]*)[))]""")
private val UOM_UNIT_TOKEN = Regex(
"""(包|袋|磅|千克|公斤|克|毫升|公升|個|隻|斤|安士|ml|ML|kg|KG|\d+\s*[gG]\b|/包|/[磅千克克])""",
)

/**
* True when [segment] looks like stock/pack UOM text (e.g. "1包X2磅", "0.9L/包"),
* not usage/grade notes (e.g. "菠菜用", "熟", "P+4").
*/
fun looksLikePackagingUom(segment: String): Boolean {
val s = segment.trim()
if (s.isEmpty()) return false
if (GRADE_IN_PARENS.matches(s)) return false
if (!s.any { it.isDigit() }) return false
return UOM_UNIT_TOKEN.containsMatchIn(s)
}

object PyJobOrderListMapper {
/** True if any parenthetical segment in [name] is packaging/UOM-like. */
fun nameAlreadyHasPackagingUom(name: String): Boolean =
PAREN_SEGMENT.findAll(name).any { looksLikePackagingUom(it.groupValues[1]) }

fun toListItem(
/**
* Append stock [udfudesc] in parentheses when the base name lacks packaging UOM.
* Used by Bag3 / bagPrint via GET /py/job-orders.
*/
fun buildDisplayItemName(baseName: String?, stockUnitDesc: String?): String? {
val stock = stockUnitDesc?.trim().orEmpty()
val baseTrim = baseName?.trim().orEmpty()
return when {
stock.isEmpty() && baseTrim.isEmpty() -> null
stock.isEmpty() -> baseTrim
baseTrim.isEmpty() -> "($stock)"
nameAlreadyHasPackagingUom(baseTrim) -> baseTrim
stockAlreadyPresentInName(baseTrim, stock) -> baseTrim
else -> "$baseTrim($stock)"
}
}

jo: JobOrder,
private fun stockAlreadyPresentInName(name: String, stockUnitDesc: String): Boolean {
val norm = stockUnitDesc.replace(" ", "").lowercase()
if (norm.isEmpty()) return false
val nameNorm = name.replace(" ", "").lowercase()
return nameNorm.contains(norm)
}

fun toListItem(
jo: JobOrder,
printed: PrintedQtyByChannel?,

stockInLineRepository: StockInLineRepository,

itemUomService: ItemUomService,

): PyJobOrderListItem {

val itemCode = jo.bom?.item?.code ?: jo.bom?.code

val baseName = jo.bom?.name ?: jo.bom?.item?.name

val itemId = jo.bom?.item?.id

val stockUnitDesc = itemId?.let { id ->

itemUomService.findStockUnitByItemId(id)?.uom?.udfudesc

}?.trim().orEmpty()

val baseTrim = baseName?.trim().orEmpty()

val baseAlreadyHasParens = '(' in baseTrim && ')' in baseTrim

val itemName = when {

stockUnitDesc.isEmpty() && baseTrim.isEmpty() -> null

stockUnitDesc.isEmpty() -> baseTrim

baseTrim.isEmpty() -> "($stockUnitDesc)"

baseAlreadyHasParens -> baseTrim

else -> "$baseTrim($stockUnitDesc)"

}
val itemName = buildDisplayItemName(baseName, stockUnitDesc)

val stockInLine = jo.id?.let { stockInLineRepository.findFirstByJobOrder_IdAndDeletedFalse(it) }

val stockInLineId = stockInLine?.id

val lotNo = stockInLine?.lotNo

val p = printed ?: PrintedQtyByChannel()

return PyJobOrderListItem(

id = jo.id!!,

code = jo.code,

planStart = jo.planStart,

itemCode = itemCode,

itemName = itemName,

reqQty = jo.reqQty,

stockInLineId = stockInLineId,

itemId = itemId,

lotNo = lotNo,

bagPrintedQty = p.bagPrintedQty,

labelPrintedQty = p.labelPrintedQty,

laserPrintedQty = p.laserPrintedQty,

)

}

}


+ 73
- 0
src/test/kotlin/com/ffii/fpsms/py/PyJobOrderListMapperTest.kt Просмотреть файл

@@ -0,0 +1,73 @@
package com.ffii.fpsms.py

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class PyJobOrderListMapperTest {

private val stockUom = "1包X2磅"

@Test
fun looksLikePackagingUom_recognizes_standard_pack_strings() {
assertTrue(PyJobOrderListMapper.looksLikePackagingUom("1包X2磅"))
assertTrue(PyJobOrderListMapper.looksLikePackagingUom("2磅/包"))
assertTrue(PyJobOrderListMapper.looksLikePackagingUom("1KG"))
assertTrue(PyJobOrderListMapper.looksLikePackagingUom("0.9L/包"))
assertTrue(PyJobOrderListMapper.looksLikePackagingUom("900ml包"))
assertTrue(PyJobOrderListMapper.looksLikePackagingUom("10個/包"))
assertTrue(PyJobOrderListMapper.looksLikePackagingUom("1包x800毫升"))
}

@Test
fun looksLikePackagingUom_rejects_usage_and_grade_notes() {
assertFalse(PyJobOrderListMapper.looksLikePackagingUom("菠菜用"))
assertFalse(PyJobOrderListMapper.looksLikePackagingUom("熟"))
assertFalse(PyJobOrderListMapper.looksLikePackagingUom("樽裝用"))
assertFalse(PyJobOrderListMapper.looksLikePackagingUom("餐廳用"))
assertFalse(PyJobOrderListMapper.looksLikePackagingUom("無糖"))
assertFalse(PyJobOrderListMapper.looksLikePackagingUom("P+4"))
assertFalse(PyJobOrderListMapper.looksLikePackagingUom("P+10"))
}

@Test
fun buildDisplayItemName_appends_uom_when_parens_are_not_packaging() {
assertEquals(
"芝士醬(菠菜用)($stockUom)",
PyJobOrderListMapper.buildDisplayItemName("芝士醬(菠菜用)", stockUom),
)
assertEquals(
"(熟)大冬菇($stockUom)",
PyJobOrderListMapper.buildDisplayItemName("(熟)大冬菇", stockUom),
)
assertEquals(
"鮮檸檬汁(P+4)($stockUom)",
PyJobOrderListMapper.buildDisplayItemName("鮮檸檬汁(P+4)", stockUom),
)
}

@Test
fun buildDisplayItemName_skips_append_when_packaging_uom_already_in_name() {
assertEquals(
"咖哩汁(1包X2磅)",
PyJobOrderListMapper.buildDisplayItemName("咖哩汁(1包X2磅)", stockUom),
)
assertEquals(
"(樽裝用)凍咖啡底P+10(0.9L/包)",
PyJobOrderListMapper.buildDisplayItemName("(樽裝用)凍咖啡底P+10(0.9L/包)", stockUom),
)
assertEquals(
"酸辣湯(2磅/包)",
PyJobOrderListMapper.buildDisplayItemName("酸辣湯(2磅/包)", "2磅/包"),
)
}

@Test
fun buildDisplayItemName_appends_when_no_parens() {
assertEquals(
"大冬菇($stockUom)",
PyJobOrderListMapper.buildDisplayItemName("大冬菇", stockUom),
)
}
}

Загрузка…
Отмена
Сохранить