Kaynağa Gözat

make onpack zip for expiry now separate by -1, -2 ...

production
Fai Luk 2 hafta önce
ebeveyn
işleme
8eeccd35cd
2 değiştirilmiş dosya ile 103 ekleme ve 33 silme
  1. +71
    -33
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/PlasticBagPrinterService.kt
  2. +32
    -0
      src/test/kotlin/com/ffii/fpsms/modules/jobOrder/service/OnPackExpiryZipStemTest.kt

+ 71
- 33
src/main/java/com/ffii/fpsms/modules/jobOrder/service/PlasticBagPrinterService.kt Dosyayı Görüntüle

@@ -69,6 +69,8 @@ data class OnPackZipResult(

private data class OnPackBmpExportItem(
val codeLower: String,
/** ZIP / template file stem (e.g. `pp2211` or `pp2211-2` for expiry multi-JO). */
val fileStem: String,
val itemId: Long,
val stockInLineId: Long,
val itemCode: String,
@@ -149,6 +151,19 @@ class PlasticBagPrinterService(
fun laserAckLooksInvalid(ack: String?): Boolean =
ack?.contains("invalid", ignoreCase = true) == true

/** Expiry 汁水機 ZIP: one file set per job order, ordered by job order no then id. */
fun sortOnPackExportJobOrders(
orders: List<OnPackQrJobOrderRequest>,
jobOrdersById: Map<Long, JobOrder>,
): List<OnPackQrJobOrderRequest> =
orders.sortedWith(
compareBy<OnPackQrJobOrderRequest> { jobOrdersById[it.jobOrderId]?.code?.trim().orEmpty() }
.thenBy { it.jobOrderId },
)

fun onPackExpiryFileStem(itemCodeLower: String, indexOneBased: Int): String =
"$itemCodeLower-$indexOneBased"

/** ISO `yyyy-MM-dd`, compact `yyyyMMdd`, or already `Expiry Date yyyyMMdd`. */
fun formatLaserExpiryParam(expiryDate: String?): String {
val raw = expiryDate?.trim().orEmpty()
@@ -285,6 +300,36 @@ class PlasticBagPrinterService(
.toSet()
}

private fun toOnPackBmpExportItem(
codeLower: String,
fileStem: String,
order: OnPackQrJobOrderRequest,
expiryPrintNames: Map<String, String>,
jobOrder: JobOrder?,
): OnPackBmpExportItem? {
val stockInLine = stockInLineRepository.findFirstByJobOrder_IdAndDeletedFalse(order.jobOrderId)
?: return null
val itemId = stockInLine.item?.id ?: return null
val stockInLineId = stockInLine.id ?: return null
val jo = jobOrder ?: jobOrderRepository.findById(order.jobOrderId).orElse(null)
val baseName = jo?.bom?.name ?: stockInLine.item?.name
val stockDesc = itemUomService.findStockUnitByItemId(itemId)?.uom?.udfudesc
val computedName = PyJobOrderListMapper.buildDisplayItemName(baseName, stockDesc)
val itemCode = (stockInLine.item?.code ?: stockInLine.itemNo ?: codeLower).trim().uppercase()
val productName = expiryPrintNames[itemCode]?.trim()?.takeIf { it.isNotEmpty() }
?: computedName
?: itemCode
return OnPackBmpExportItem(
codeLower = codeLower,
fileStem = fileStem,
itemId = itemId,
stockInLineId = stockInLineId,
itemCode = itemCode,
productName = productName,
planDate = jo?.planStart?.toLocalDate(),
)
}

/**
* Bag2.py [send_job_to_laser] / [send_job_to_laser_with_retry]: UTF-8 TCP payload and optional ack read.
*/
@@ -725,30 +770,23 @@ class PlasticBagPrinterService(
emptyMap()
}

val jobOrdersById = jobOrderRepository.findAllById(
packagingJobOrders.map { it.jobOrderId }.distinct(),
).associateBy { it.id!! }
val exportItemsRaw = packagingJobOrders
.groupBy { it.itemCode.trim().lowercase() }
.mapNotNull { (codeLower, orders) ->
val order = orders.firstOrNull() ?: return@mapNotNull null
val stockInLine = stockInLineRepository.findFirstByJobOrder_IdAndDeletedFalse(order.jobOrderId)
?: return@mapNotNull null
val itemId = stockInLine.item?.id ?: return@mapNotNull null
val stockInLineId = stockInLine.id ?: return@mapNotNull null
val jo = jobOrderRepository.findById(order.jobOrderId).orElse(null)
val baseName = jo?.bom?.name ?: stockInLine.item?.name
val stockDesc = itemUomService.findStockUnitByItemId(itemId)?.uom?.udfudesc
val computedName = PyJobOrderListMapper.buildDisplayItemName(baseName, stockDesc)
val itemCode = (stockInLine.item?.code ?: stockInLine.itemNo ?: codeLower).trim().uppercase()
val productName = expiryPrintNames[itemCode]?.trim()?.takeIf { it.isNotEmpty() }
?: computedName
?: itemCode
OnPackBmpExportItem(
codeLower,
itemId,
stockInLineId,
itemCode,
productName,
jo?.planStart?.toLocalDate(),
)
.flatMap { (codeLower, orders) ->
val sorted = sortOnPackExportJobOrders(orders, jobOrdersById)
val selected = if (includeExpiry) sorted else listOfNotNull(sorted.firstOrNull())
selected.mapIndexedNotNull { index, order ->
toOnPackBmpExportItem(
codeLower = codeLower,
fileStem = if (includeExpiry) onPackExpiryFileStem(codeLower, index + 1) else codeLower,
order = order,
expiryPrintNames = expiryPrintNames,
jobOrder = jobOrdersById[order.jobOrderId],
)
}
}

require(exportItemsRaw.isNotEmpty()) { "No OnPack QR files could be generated for the selected date" }
@@ -808,12 +846,12 @@ class PlasticBagPrinterService(
ZipOutputStream(baos).use { zos ->
val addedEntries = linkedSetOf<String>()
exportItems.forEach { item ->
val codeLower = item.codeLower
val fileStem = item.fileStem
val imageTemplate = if (includeExpiry) {
val master = expiryMasterImage ?: return@forEach
OnPackPp1181Master.rewriteImageBytes(master, codeLower)
OnPackPp1181Master.rewriteImageBytes(master, fileStem)
} else {
loadOnPackImageTemplateOrNull(codeLower, forExpiry = false) ?: return@forEach
loadOnPackImageTemplateOrNull(item.codeLower, forExpiry = false) ?: return@forEach
}

val qrContent = """{"itemId": ${item.itemId}, "stockInLineId": ${item.stockInLineId}}"""
@@ -821,13 +859,13 @@ class PlasticBagPrinterService(
// Width = 386 + (42 * 2) = 470
// Height = 386 + (1 * 2) = 388 (~389)
val bmp = createQrCodeBitmap(qrContent, contentSize = 386, horizontalPadding = 42, verticalPadding = 1)
val qrBmpFileName = "${codeLower}qr.bmp"
val imageFileName = "$codeLower.image"
val qrBmpFileName = "${fileStem}qr.bmp"
val imageFileName = "$fileStem.image"
var imageContent = withOnPackLogo4Bmp(imageTemplate, qrBmpFileName)
if (includeExpiry) {
val productFile = "${codeLower}Product.bmp"
val codeFile = "${codeLower}Code.bmp"
val dateFile = "${codeLower}Date.bmp"
val productFile = "${fileStem}Product.bmp"
val codeFile = "${fileStem}Code.bmp"
val dateFile = "${fileStem}Date.bmp"
val productBmp = createMonochromeBitmapFixed(
item.productName,
ONPACK_PRODUCT_BMP_WIDTH,
@@ -857,7 +895,7 @@ class PlasticBagPrinterService(
}
}
val expiryLabel = if (includeExpiry) {
itemDefaultShelfLifeService.expiryDatePrintLabel(codeLower, effectivePrintDate)
itemDefaultShelfLifeService.expiryDatePrintLabel(item.itemCode, effectivePrintDate)
} else {
null
}
@@ -867,7 +905,7 @@ class PlasticBagPrinterService(
ONPACK_EXPIRY_BMP_WIDTH,
ONPACK_EXPIRY_BMP_HEIGHT,
)
val expBmpFileName = "${codeLower}exp.bmp"
val expBmpFileName = "${fileStem}exp.bmp"
imageContent = withOnPackExpiryLogo(imageContent, expBmpFileName, expBmp.width)
if (addedEntries.add(expBmpFileName)) {
addToZip(zos, expBmpFileName, expBmp.bytes)
@@ -893,7 +931,7 @@ class PlasticBagPrinterService(
addToZip(zos, bmpName, bmpBytes)
}
}
val jobFileName = "${codeLower}.job"
val jobFileName = "$fileStem.job"
if (includeExpiry) {
val masterJob = expiryMasterJob
if (masterJob != null && addedEntries.add(jobFileName)) {


+ 32
- 0
src/test/kotlin/com/ffii/fpsms/modules/jobOrder/service/OnPackExpiryZipStemTest.kt Dosyayı Görüntüle

@@ -0,0 +1,32 @@
package com.ffii.fpsms.modules.jobOrder.service

import com.ffii.fpsms.modules.jobOrder.entity.JobOrder
import com.ffii.fpsms.modules.jobOrder.web.model.OnPackQrJobOrderRequest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class OnPackExpiryZipStemTest {

@Test
fun expiry_file_stem_appends_one_based_index() {
assertEquals("pp2211-1", PlasticBagPrinterService.onPackExpiryFileStem("pp2211", 1))
assertEquals("pp2211-2", PlasticBagPrinterService.onPackExpiryFileStem("pp2211", 2))
}

@Test
fun export_job_orders_sort_by_job_order_code_then_id() {
val jo10 = JobOrder().apply { id = 10L; code = "JO-002" }
val jo20 = JobOrder().apply { id = 20L; code = "JO-001" }
val jo30 = JobOrder().apply { id = 30L; code = "JO-001" }
val byId = mapOf(10L to jo10, 20L to jo20, 30L to jo30)
val sorted = PlasticBagPrinterService.sortOnPackExportJobOrders(
listOf(
OnPackQrJobOrderRequest(10, "PP2211"),
OnPackQrJobOrderRequest(30, "PP2211"),
OnPackQrJobOrderRequest(20, "PP2211"),
),
byId,
)
assertEquals(listOf(20L, 30L, 10L), sorted.map { it.jobOrderId })
}
}

Yükleniyor…
İptal
Kaydet