Ver código fonte

no message

master
Fai Luk 1 dia atrás
pai
commit
797c33da12
6 arquivos alterados com 135 adições e 6 exclusões
  1. +1
    -1
      python/bag2_settings.json
  2. +7
    -1
      src/main/java/com/ffii/fpsms/modules/common/scheduler/service/SchedulerService.kt
  3. +5
    -4
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/PlasticBagPrinterService.kt
  4. +28
    -0
      src/main/java/com/ffii/fpsms/modules/jobOrder/web/PlasticBagPrinterController.kt
  5. +92
    -0
      src/main/java/com/ffii/fpsms/modules/stock/service/SearchCompletedDnService.kt
  6. +2
    -0
      src/main/resources/application-prod.yml

+ 1
- 1
python/bag2_settings.json Ver arquivo

@@ -1,5 +1,5 @@
{
"api_ip": "10.10.0.81",
"api_ip": "127.0.0.1",
"api_port": "8090",
"dabag_ip": "192.168.18.27",
"dabag_port": "3008",


+ 7
- 1
src/main/java/com/ffii/fpsms/modules/common/scheduler/service/SchedulerService.kt Ver arquivo

@@ -33,6 +33,7 @@ import kotlin.jvm.optionals.getOrNull
open class SchedulerService(
@Value("\${scheduler.postCompletedDnGrn.enabled:true}") val postCompletedDnGrnEnabled: Boolean,
@Value("\${scheduler.postCompletedDnGrn.receiptDate:}") val postCompletedDnGrnReceiptDate: String,
@Value("\${scheduler.postCompletedDnGrn.retryMissingGrnLookbackDays:7}") val postCompletedDnGrnRetryMissingGrnLookbackDays: Int,
@Value("\${scheduler.grnCodeSync.enabled:true}") val grnCodeSyncEnabled: Boolean,
@Value("\${scheduler.grnCodeSync.syncOffsetDays:0}") val grnCodeSyncSyncOffsetDays: Int,
@Value("\${scheduler.m18Units.enabled:true}") val m18UnitsSchedulerEnabled: Boolean,
@@ -422,7 +423,12 @@ open class SchedulerService(
) {
logger.info("Scheduler - Post completed DN and process GRN")
val date = receiptDate ?: java.time.LocalDate.now().minusDays(1)
searchCompletedDnService.postCompletedDnAndProcessGrn(receiptDate = date, skipFirst = skipFirst, limitToFirst = limitToFirst)
searchCompletedDnService.postCompletedDnAndProcessGrnWithMissingRetry(
receiptDate = date,
skipFirst = skipFirst,
limitToFirst = limitToFirst,
retryLookbackDays = postCompletedDnGrnRetryMissingGrnLookbackDays,
)
}

open fun getM18MasterData() {


+ 5
- 4
src/main/java/com/ffii/fpsms/modules/jobOrder/service/PlasticBagPrinterService.kt Ver arquivo

@@ -14,7 +14,6 @@ import com.ffii.fpsms.modules.settings.service.SettingsService
import com.ffii.fpsms.modules.stock.entity.StockInLineRepository
import com.ffii.fpsms.py.PyJobOrderListItem
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.awt.Color
import java.awt.Font
import java.awt.Graphics2D
@@ -46,7 +45,7 @@ import java.time.LocalDate
data class BitmapResult(val bytes: ByteArray, val width: Int)

@Service
open class PlasticBagPrinterService(
class PlasticBagPrinterService(
val jobOrderRepository: JobOrderRepository,
private val jdbcDao: JdbcDao,
private val stockInLineRepository: StockInLineRepository,
@@ -82,9 +81,11 @@ open class PlasticBagPrinterService(
/**
* Same criteria as [com.ffii.fpsms.py.PyController.listJobOrders], filtered by [SettingNames.LASER_PRINT_ITEM_CODES]
* (comma-separated item codes). Blank / whitespace-only setting value means no filter (all packaging job orders).
*
* No Transactional annotation on this class: CGLIB subclassing plus Kotlin breaks constructor-injected deps on the proxy.
* Rely on default OSIV for lazy BOM access within the HTTP request.
*/
@Transactional(readOnly = true)
open fun listLaserPrintJobOrders(planStart: LocalDate): List<PyJobOrderListItem> {
fun listLaserPrintJobOrders(planStart: LocalDate): List<PyJobOrderListItem> {
val dayStart = planStart.atStartOfDay()
val dayEndExclusive = planStart.plusDays(1).atStartOfDay()
val orders = jobOrderRepository.findByDeletedFalseAndPlanStartBetweenAndBomProcessNameOrderByIdAsc(


+ 28
- 0
src/main/java/com/ffii/fpsms/modules/jobOrder/web/PlasticBagPrinterController.kt Ver arquivo

@@ -18,12 +18,14 @@ import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.*
import java.time.LocalDate
import org.springframework.http.ResponseEntity
import org.slf4j.LoggerFactory

@RestController
@RequestMapping("/plastic")
class PlasticBagPrinterController(
private val plasticBagPrinterService: PlasticBagPrinterService,
) {
private val logger = LoggerFactory.getLogger(javaClass)

/** System defaults + current values from [LASER_PRINT.host] / [LASER_PRINT.port] / [LASER_PRINT.itemCodes] (see Liquibase). */
@GetMapping("/laser-bag2-settings")
@@ -97,6 +99,19 @@ class PlasticBagPrinterController(
response.contentType = "text/plain;charset=UTF-8"
response.writer.write(e.message ?: "Invalid request")
response.writer.flush()
} catch (e: Exception) {
logger.error("POST /plastic/download-onpack-qr failed", e)
try {
if (!response.isCommitted) {
response.reset()
}
} catch (_: Exception) {
/* ignore */
}
response.status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR
response.contentType = "text/plain;charset=UTF-8"
response.writer.write(e.message ?: "Download failed")
response.writer.flush()
}
}

@@ -121,6 +136,19 @@ class PlasticBagPrinterController(
response.contentType = "text/plain;charset=UTF-8"
response.writer.write(e.message ?: "Invalid request")
response.writer.flush()
} catch (e: Exception) {
logger.error("POST /plastic/download-onpack-qr-text failed", e)
try {
if (!response.isCommitted) {
response.reset()
}
} catch (_: Exception) {
/* ignore */
}
response.status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR
response.contentType = "text/plain;charset=UTF-8"
response.writer.write(e.message ?: "Download failed")
response.writer.flush()
}
}



+ 92
- 0
src/main/java/com/ffii/fpsms/modules/stock/service/SearchCompletedDnService.kt Ver arquivo

@@ -1,6 +1,7 @@
package com.ffii.fpsms.modules.stock.service

import com.ffii.core.support.JdbcDao
import com.ffii.fpsms.m18.entity.M18GoodsReceiptNoteLogRepository
import com.ffii.fpsms.modules.stock.entity.StockInLine
import com.ffii.fpsms.modules.stock.entity.StockInLineRepository
import com.ffii.fpsms.modules.stock.web.model.SearchCompletedDnResult
@@ -20,6 +21,7 @@ open class SearchCompletedDnService(
private val jdbcDao: JdbcDao,
private val stockInLineRepository: StockInLineRepository,
private val stockInLineService: StockInLineService,
private val m18GoodsReceiptNoteLogRepository: M18GoodsReceiptNoteLogRepository,
) {
private val logger = LoggerFactory.getLogger(SearchCompletedDnService::class.java)

@@ -107,4 +109,94 @@ open class SearchCompletedDnService(
}
return toProcess.size
}

/**
* Retry GRN creation for completed stock-in lines where the PO does not have a SUCCESS log in
* `m18_goods_receipt_note_log`.
*
* Grouping behavior matches normal scheduler:
* - iterate by `receiptDate` day window
* - for each day, group by `PO (purchaseOrderId)`
* - process one GRN per PO using the first line from that PO group
*/
@Transactional
open fun postCompletedDnAndProcessGrnWithMissingRetry(
receiptDate: LocalDate = LocalDate.now().minusDays(1),
skipFirst: Int = 0,
limitToFirst: Int? = null,
retryLookbackDays: Int = 0,
): Int {
val lookback = retryLookbackDays.coerceAtLeast(0)
var totalProcessed = 0

// Requirement: never process today's completed stock-in lines in retry mode.
val today = LocalDate.now()
var processedDayCount = 0

// For each offset, day = receiptDate minus offset. Example: job runs 27/3 00:01, receiptDate=yesterday=26/3,
// lookback=6 => days 26,25,24,23,22,21,20 (skip any day equal to today).
for (offset in 0..lookback) {
val day = receiptDate.minusDays(offset.toLong())
if (day.isEqual(today)) {
logger.info(
"[postCompletedDnAndProcessGrnWithMissingRetry] Skipping receiptDate=today=$today " +
"(offset=$offset) to avoid creating GRN from today's completed stock-in lines."
)
continue
}

val daySkipFirst = if (processedDayCount == 0) skipFirst else 0
val dayLimitToFirst = if (processedDayCount == 0) limitToFirst else null

val processedForDay = postCompletedDnAndProcessMissingGrnForReceiptDate(
receiptDate = day,
skipFirst = daySkipFirst,
limitToFirst = dayLimitToFirst,
)
totalProcessed += processedForDay
processedDayCount++
logger.info(
"[postCompletedDnAndProcessGrnWithMissingRetry] offset=$offset day=$day processedForDay=$processedForDay totalProcessed=$totalProcessed"
)
}

return totalProcessed
}

private fun postCompletedDnAndProcessMissingGrnForReceiptDate(
receiptDate: LocalDate,
skipFirst: Int,
limitToFirst: Int?,
): Int {
val lines = searchCompletedDn(receiptDate)
val byPo = lines.groupBy { it.purchaseOrder?.id ?: 0L }.filterKeys { it != 0L }
val entries = byPo.entries.toList()

// Only retry POs that do NOT have any successful GRN log.
val missingEntries = entries.filter { (poId, _) ->
!m18GoodsReceiptNoteLogRepository.existsByPurchaseOrderIdAndStatusTrue(poId)
}

val toProcess = missingEntries
.drop(skipFirst)
.let { if (limitToFirst != null) it.take(limitToFirst) else it }

logger.info(
"[postCompletedDnAndProcessMissingGrnForReceiptDate] receiptDate=$receiptDate foundLines=${lines.size} " +
"poTotal=${byPo.size} poMissingSuccess=${missingEntries.size} processing=${toProcess.size} " +
"(skipFirst=$skipFirst, limitToFirst=$limitToFirst)"
)

toProcess.forEach { (poId, silList) ->
silList.firstOrNull()?.let { first ->
try {
stockInLineService.processPurchaseOrderForGrn(first)
} catch (e: Exception) {
logger.error("[postCompletedDnAndProcessMissingGrnForReceiptDate] Failed for PO id=$poId: ${e.message}", e)
}
}
}

return toProcess.size
}
}

+ 2
- 0
src/main/resources/application-prod.yml Ver arquivo

@@ -24,6 +24,8 @@ spring:
scheduler:
postCompletedDnGrn:
enabled: true
# Missing-success GRN retry window: receiptDate (default yesterday) back N days inclusive. E.g. run 27/3 with receiptDate=26/3 and N=6 => 20/3–26/3.
retryMissingGrnLookbackDays: 6
grnCodeSync:
enabled: true
syncOffsetDays: 10 # from (today − 10) 00:00 to now, rows missing grn_code


Carregando…
Cancelar
Salvar