Преглед изворни кода

make m18 syn by code appear in menu for PO/DO/Product

master
DESKTOP-064TTA1\Fai LUK пре 2 дана
родитељ
комит
bea0b2c2fe
7 измењених фајлова са 227 додато и 0 уклоњено
  1. +39
    -0
      src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt
  2. +5
    -0
      src/main/java/com/ffii/fpsms/m18/web/M18TestController.kt
  3. +42
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/scheduler/LaserBag2AutoSendScheduler.kt
  4. +93
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/LaserBag2AutoSendService.kt
  5. +21
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/web/PlasticBagPrinterController.kt
  6. +18
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/web/model/LaserBag2AutoSendReport.kt
  7. +9
    -0
      src/main/resources/application.yml

+ 39
- 0
src/main/java/com/ffii/fpsms/m18/service/M18MasterDataService.kt Прегледај датотеку

@@ -303,6 +303,45 @@ open class M18MasterDataService(
}
}

/** Sync one product/material from M18 by item code (search list, then load line — same idea as PO/DO by code). */
open fun saveProductByCode(code: String): SyncResult {
val trimmed = code.trim()
if (trimmed.isEmpty()) {
return SyncResult(totalProcessed = 1, totalSuccess = 0, totalFail = 1, query = "empty code")
}
ensureCunitSeededForAllIfEmpty()
val fromLocal = itemsService.findByCode(trimmed)?.m18Id
val m18Id = fromLocal ?: run {
val conds = "(code=equal=$trimmed)"
val listResponse = try {
getList<M18ProductListResponse>(
stSearch = StSearchType.PRODUCT.value,
params = null,
conds = conds,
request = M18CommonRequest(),
)
} catch (e: Exception) {
logger.error("(saveProductByCode) M18 search failed: ${e.message}", e)
null
}
listResponse?.values?.firstOrNull()?.id
}
if (m18Id == null) {
return SyncResult(
totalProcessed = 1,
totalSuccess = 0,
totalFail = 1,
query = "code=equal=$trimmed",
)
}
val result = saveProduct(m18Id)
return if (result != null) {
SyncResult(totalProcessed = 1, totalSuccess = 1, totalFail = 0, query = "code=equal=$trimmed")
} else {
SyncResult(totalProcessed = 1, totalSuccess = 0, totalFail = 1, query = "code=equal=$trimmed")
}
}

open fun saveProducts(request: M18CommonRequest): SyncResult {
logger.info("--------------------------------------------Start - Saving M18 Products / Materials--------------------------------------------")
ensureCunitSeededForAllIfEmpty()


+ 5
- 0
src/main/java/com/ffii/fpsms/m18/web/M18TestController.kt Прегледај датотеку

@@ -74,6 +74,11 @@ class M18TestController (
fun testSyncDoByCode(@RequestParam code: String): SyncResult {
return m18DeliveryOrderService.saveDeliveryOrderByCode(code)
}

@GetMapping("/test/product-by-code")
fun testSyncProductByCode(@RequestParam code: String): SyncResult {
return m18MasterDataService.saveProductByCode(code)
}
// --------------------------------------------- Scheduler --------------------------------------------- ///
// @GetMapping("/schedule/po")
// fun schedulePo(@RequestParam @Valid newCron: String) {


+ 42
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/scheduler/LaserBag2AutoSendScheduler.kt Прегледај датотеку

@@ -0,0 +1,42 @@
package com.ffii.fpsms.modules.jobOrder.scheduler

import com.ffii.fpsms.modules.jobOrder.service.LaserBag2AutoSendService
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
import java.time.LocalDate

/**
* Periodically runs the same laser TCP send as /laserPrint (DB LASER_PRINT.host / port / itemCodes).
* Disabled by default; set laser.bag2.auto-send.enabled=true.
*/
@Component
class LaserBag2AutoSendScheduler(
private val laserBag2AutoSendService: LaserBag2AutoSendService,
@Value("\${laser.bag2.auto-send.enabled:false}") private val enabled: Boolean,
@Value("\${laser.bag2.auto-send.limit-per-run:1}") private val limitPerRun: Int,
) {
private val logger = LoggerFactory.getLogger(javaClass)

@Scheduled(fixedRateString = "\${laser.bag2.auto-send.interval-ms:60000}")
fun tick() {
if (!enabled) {
return
}
try {
val report = laserBag2AutoSendService.runAutoSend(
planStart = LocalDate.now(),
limitPerRun = limitPerRun,
)
logger.info(
"Laser Bag2 scheduler: processed {}/{} job orders for {}",
report.jobOrdersProcessed,
report.jobOrdersFound,
report.planStart,
)
} catch (e: Exception) {
logger.error("Laser Bag2 scheduler failed", e)
}
}
}

+ 93
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/service/LaserBag2AutoSendService.kt Прегледај датотеку

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

import com.ffii.fpsms.modules.jobOrder.web.model.LaserBag2AutoSendReport
import com.ffii.fpsms.modules.jobOrder.web.model.LaserBag2JobSendResult
import com.ffii.fpsms.modules.jobOrder.web.model.LaserBag2SendRequest
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.time.LocalDate

/**
* Finds packaging job orders for [planStart] using the same filter as [PlasticBagPrinterService.listLaserPrintJobOrders]
* ([LASER_PRINT.itemCodes]), then sends Bag2-style laser TCP payloads via [PlasticBagPrinterService.sendLaserBag2Job],
* which uses [com.ffii.fpsms.modules.common.SettingNames.LASER_PRINT_HOST] / [LASER_PRINT_PORT] from the database.
*
* Matches /laserPrint row click: [sendsPerJob] rounds with [delayBetweenSendsMs] between rounds (default 3 × 3s like the frontend).
*/
@Service
class LaserBag2AutoSendService(
private val plasticBagPrinterService: PlasticBagPrinterService,
) {
private val logger = LoggerFactory.getLogger(javaClass)

companion object {
/** Same as LaserPrint page (3 sends per row click). */
const val DEFAULT_SENDS_PER_JOB = 3
const val DEFAULT_DELAY_BETWEEN_SENDS_MS = 3000L
}

fun runAutoSend(
planStart: LocalDate,
limitPerRun: Int = 0,
sendsPerJob: Int = DEFAULT_SENDS_PER_JOB,
delayBetweenSendsMs: Long = DEFAULT_DELAY_BETWEEN_SENDS_MS,
): LaserBag2AutoSendReport {
val orders = plasticBagPrinterService.listLaserPrintJobOrders(planStart)
val toProcess = if (limitPerRun > 0) orders.take(limitPerRun) else orders
val results = mutableListOf<LaserBag2JobSendResult>()

logger.info(
"Laser Bag2 auto-send: planStart={}, found={}, processing={}, sendsPerJob={}",
planStart,
orders.size,
toProcess.size,
sendsPerJob,
)

for (jo in toProcess) {
var lastMsg = ""
var overallOk = true
for (attempt in 1..sendsPerJob) {
val resp = plasticBagPrinterService.sendLaserBag2Job(
LaserBag2SendRequest(
itemId = jo.itemId,
stockInLineId = jo.stockInLineId,
itemCode = jo.itemCode,
itemName = jo.itemName,
),
)
lastMsg = resp.message
if (!resp.success) {
overallOk = false
logger.warn("Laser send failed jobOrderId={} attempt={}: {}", jo.id, attempt, resp.message)
break
}
if (attempt < sendsPerJob) {
try {
Thread.sleep(delayBetweenSendsMs)
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
overallOk = false
lastMsg = "Interrupted"
break
}
}
}
results.add(
LaserBag2JobSendResult(
jobOrderId = jo.id,
itemCode = jo.itemCode,
success = overallOk,
message = lastMsg,
),
)
}

return LaserBag2AutoSendReport(
planStart = planStart,
jobOrdersFound = orders.size,
jobOrdersProcessed = toProcess.size,
results = results,
)
}
}

+ 21
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/web/PlasticBagPrinterController.kt Прегледај датотеку

@@ -1,9 +1,11 @@
package com.ffii.fpsms.modules.jobOrder.web

import com.ffii.fpsms.modules.jobOrder.service.LaserBag2AutoSendService
import com.ffii.fpsms.modules.jobOrder.service.PlasticBagPrinterService
import com.ffii.fpsms.modules.jobOrder.web.model.PrintRequest
import com.ffii.fpsms.modules.jobOrder.web.model.LaserRequest
import com.ffii.fpsms.modules.jobOrder.web.model.Laser2Request
import com.ffii.fpsms.modules.jobOrder.web.model.LaserBag2AutoSendReport
import com.ffii.fpsms.modules.jobOrder.web.model.LaserBag2SendRequest
import com.ffii.fpsms.modules.jobOrder.web.model.LaserBag2SendResponse
import com.ffii.fpsms.modules.jobOrder.web.model.LaserBag2SettingsResponse
@@ -25,6 +27,7 @@ import org.slf4j.LoggerFactory
@RequestMapping("/plastic")
class PlasticBagPrinterController(
private val plasticBagPrinterService: PlasticBagPrinterService,
private val laserBag2AutoSendService: LaserBag2AutoSendService,
) {
private val logger = LoggerFactory.getLogger(javaClass)

@@ -59,6 +62,24 @@ class PlasticBagPrinterController(
}
}

/**
* Same as /laserPrint row workflow: list job orders for [planStart] filtered by LASER_PRINT.itemCodes,
* then for each (up to [limitPerRun], 0 = all) send laser TCP commands using LASER_PRINT.host/port (3× with 3s gap per job).
* For manual runs from /testing; scheduler uses [LaserBag2AutoSendScheduler].
*/
@PostMapping("/laser-bag2-auto-send")
fun runLaserBag2AutoSend(
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) planStart: LocalDate?,
@RequestParam(required = false, defaultValue = "0") limitPerRun: Int,
): ResponseEntity<LaserBag2AutoSendReport> {
val date = planStart ?: LocalDate.now()
val report = laserBag2AutoSendService.runAutoSend(
planStart = date,
limitPerRun = limitPerRun,
)
return ResponseEntity.ok(report)
}

@PostMapping("/check-printer")
fun checkPrinter(@RequestBody request: PrinterStatusRequest): ResponseEntity<PrinterStatusResponse> {
val (connected, message) = plasticBagPrinterService.checkPrinterConnection(


+ 18
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/web/model/LaserBag2AutoSendReport.kt Прегледај датотеку

@@ -0,0 +1,18 @@
package com.ffii.fpsms.modules.jobOrder.web.model

import java.time.LocalDate

/** Result of [com.ffii.fpsms.modules.jobOrder.service.LaserBag2AutoSendService.runAutoSend]. */
data class LaserBag2AutoSendReport(
val planStart: LocalDate,
val jobOrdersFound: Int,
val jobOrdersProcessed: Int,
val results: List<LaserBag2JobSendResult>,
)

data class LaserBag2JobSendResult(
val jobOrderId: Long,
val itemCode: String?,
val success: Boolean,
val message: String,
)

+ 9
- 0
src/main/resources/application.yml Прегледај датотеку

@@ -55,6 +55,15 @@ logging:
ngpcl:
push-url: ${NGPCL_PUSH_URL:}

# Laser Bag2 (/laserPrint) auto-send: same as listing + TCP send using DB LASER_PRINT.host / port / itemCodes.
# Scheduler is off by default. limit-per-run: max job orders per tick (1 = first matching only); 0 = all matches (heavy).
laser:
bag2:
auto-send:
enabled: false
interval-ms: 60000
limit-per-run: 1

bom:
import:
temp-dir: ${java.io.tmpdir}/fpsms-bom-import


Loading…
Откажи
Сачувај