Browse Source

Merge remote-tracking branch 'origin/master'

master
CANCERYS\kw093 3 weeks ago
parent
commit
3b33fabab1
4 changed files with 205 additions and 25 deletions
  1. +138
    -0
      src/main/java/com/ffii/core/utils/CanonPrinterUtil.kt
  2. +39
    -21
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt
  3. +27
    -3
      src/main/java/com/ffii/fpsms/modules/jobOrder/service/JobOrderService.kt
  4. +1
    -1
      src/main/java/com/ffii/fpsms/modules/master/service/BomService.kt

+ 138
- 0
src/main/java/com/ffii/core/utils/CanonPrinterUtil.kt View File

@@ -0,0 +1,138 @@
package com.ffii.core.utils

import org.apache.pdfbox.pdmodel.PDDocument
import java.io.File
import java.io.OutputStream
import java.net.Socket

/**
* Utility class for generating and sending print jobs to a Canon printer using PDF.
* This class requires the 'org.apache.pdfbox:pdfbox' dependency to be included in your project.
*/
open class CanonPrinterUtil {

// Enum to represent valid duplex print modes
enum class DuplexMode {
SIMPLEX, // Single-sided printing
DUPLEX_LONG_EDGE, // Double-sided, flip on long edge (portrait binding)
DUPLEX_SHORT_EDGE // Double-sided, flip on short edge (landscape binding)
}

companion object {
/**
* Detects if a PDF document is in landscape (horizontal) orientation.
*
* @param pdfFile The PDF file to check.
* @return true if the document is landscape, false if portrait.
*/
fun isLandscape(pdfFile: File): Boolean {
if (!pdfFile.exists() || !pdfFile.canRead()) {
return false
}

try {
PDDocument.load(pdfFile).use { document ->
if (document.numberOfPages > 0) {
val page = document.getPage(0)
val mediaBox = page.mediaBox
val width = mediaBox.width
val height = mediaBox.height

// Landscape if width > height
return width > height
}
}
} catch (e: Exception) {
println("DEBUG: Error detecting PDF orientation: ${e.message}")
}
return false
}

/**
* Sends a PDF document directly to the specified Canon printer with duplex printing support.
*
* @param pdfFile The PDF file to be printed.
* @param printerIp The IP address of the Canon printer.
* @param printerPort The port of the Canon printer, typically 9100.
* @param printQty The qty of print, default 1
* @param duplexMode Valid values: SIMPLEX (single-sided), DUPLEX_LONG_EDGE (portrait), DUPLEX_SHORT_EDGE (landscape)
* @throws Exception if there is an error during file processing or printing.
*/
fun printPdfToCanon(pdfFile: File, printerIp: String, printerPort: Int, printQty: Int? = 1, duplexMode: DuplexMode = DuplexMode.DUPLEX_LONG_EDGE) {

// Check if the file exists and is readable
if (!pdfFile.exists() || !pdfFile.canRead()) {
throw IllegalArgumentException("Error: File not found or not readable at path: ${pdfFile.absolutePath}")
}

try {
// 1. Build PJL (Printer Job Language) commands for Canon printers
val pjlCommands = StringBuilder()

// PJL job start
pjlCommands.append("\u001B%-12345X@PJL\n")
pjlCommands.append("@PJL JOB NAME=\"PDF Print\"\n")

// 2. Set duplex mode
when (duplexMode) {
DuplexMode.SIMPLEX -> {
pjlCommands.append("@PJL SET DUPLEX=OFF\n")
}
DuplexMode.DUPLEX_LONG_EDGE -> {
pjlCommands.append("@PJL SET DUPLEX=ON\n")
pjlCommands.append("@PJL SET BINDING=LONGEDGE\n")
}
DuplexMode.DUPLEX_SHORT_EDGE -> {
pjlCommands.append("@PJL SET DUPLEX=ON\n")
pjlCommands.append("@PJL SET BINDING=SHORTEDGE\n")
}
}

// 3. Set number of copies
if ((printQty ?: 1) > 1) {
pjlCommands.append("@PJL SET COPIES=${printQty ?: 1}\n")
}

// 4. Set paper size to A4
pjlCommands.append("@PJL SET PAPER=A4\n")

// 5. Enter PDF language mode
pjlCommands.append("@PJL ENTER LANGUAGE=PDF\n")

// PJL job end marker (before PDF content)
pjlCommands.append("\u001B%-12345X\n")

// 6. Read PDF file content
val pdfContent = pdfFile.readBytes()

println("DEBUG: PDF file size: ${pdfContent.size} bytes")

// Print each copy for the specified quantity
repeat(printQty ?: 1) { copyIndex ->
println("DEBUG: Printing copy ${copyIndex + 1} of ${printQty ?: 1}")

// 7. Send to printer via TCP/IP socket
Socket(printerIp, printerPort).use { socket ->
val os: OutputStream = socket.getOutputStream()

// Send PJL commands
val printData = pjlCommands.toString().toByteArray(Charsets.US_ASCII)
os.write(printData)

// Send PDF content
os.write(pdfContent)

// Send job end marker
os.write("\u001B%-12345X".toByteArray(Charsets.US_ASCII))

os.flush()
println("DEBUG: Copy ${copyIndex + 1} sent to printer")
}
}
} catch (e: Exception) {
// Re-throw the exception with a more descriptive message
throw Exception("Error processing print job for PDF: ${e.message}", e)
}
}
}
}

+ 39
- 21
src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt View File

@@ -71,6 +71,7 @@ import com.ffii.fpsms.modules.stock.entity.SuggestPickLotRepository
import com.ffii.fpsms.modules.stock.service.SuggestedPickLotService // 添加这行
import com.ffii.fpsms.modules.deliveryOrder.web.models.*
import com.ffii.fpsms.modules.pickOrder.entity.PickExecutionIssueRepository // 添加
import com.ffii.core.utils.CanonPrinterUtil

@Service
open class DeliveryOrderService(
@@ -928,36 +929,53 @@ open class DeliveryOrderService(
)
}

//Print Delivery Note
@Transactional
open fun printDeliveryNote(request: PrintDeliveryNoteRequest) {
//val printer = printerService.findById(request.printerId) ?: throw java.util.NoSuchElementException("No such printer")

val pdf = exportDeliveryNote(
ExportDeliveryNoteRequest(
doPickOrderId = request.doPickOrderId,
numOfCarton = request.numOfCarton,
isDraft = request.isDraft
)
//Print Delivery Note
@Transactional
open fun printDeliveryNote(request: PrintDeliveryNoteRequest) {
val printer = printerService.findById(request.printerId) ?: throw java.util.NoSuchElementException("No such printer")

val pdf = exportDeliveryNote(
ExportDeliveryNoteRequest(
doPickOrderId = request.doPickOrderId,
numOfCarton = request.numOfCarton,
isDraft = request.isDraft
)
)

val jasperPrint = pdf["report"] as JasperPrint
val jasperPrint = pdf["report"] as JasperPrint

val tempPdfFile = File.createTempFile("print_job_", ".pdf")
val tempPdfFile = File.createTempFile("print_job_", ".pdf")

try {
JasperExportManager.exportReportToPdfFile(jasperPrint, tempPdfFile.absolutePath)
try {
JasperExportManager.exportReportToPdfFile(jasperPrint, tempPdfFile.absolutePath)

//val printQty = if (request.printQty == null || request.printQty <= 0) 1 else request.printQty
//printer.ip?.let { ip -> printer.port?.let { port ->
// ZebraPrinterUtil.printPdfToZebra(tempPdfFile, ip, port, printQty, ZebraPrinterUtil.PrintDirection.ROTATED)
//}}
} finally {
//tempPdfFile.delete()
val printQty = if (request.printQty == null || request.printQty <= 0) 1 else request.printQty
val duplexMode = if (CanonPrinterUtil.isLandscape(tempPdfFile)) {
CanonPrinterUtil.DuplexMode.DUPLEX_SHORT_EDGE // Landscape: flip on short edge
} else {
CanonPrinterUtil.DuplexMode.DUPLEX_LONG_EDGE // Portrait: flip on long edge
}

println("DEBUG: PDF orientation detected - Landscape: ${CanonPrinterUtil.isLandscape(tempPdfFile)}, Duplex mode: $duplexMode")

printer.ip?.let { ip ->
printer.port?.let { port ->
CanonPrinterUtil.printPdfToCanon(
tempPdfFile,
ip,
port,
printQty,
duplexMode
)
}
}
} finally {
//tempPdfFile.delete()
}

}

//Carton Labels
open fun exportDNLabels(request: ExportDNLabelsRequest): Map<String, Any> {
val DNLABELS_PDF = "DeliveryNote/DeliveryNoteCartonLabelsPDF.jrxml"


+ 27
- 3
src/main/java/com/ffii/fpsms/modules/jobOrder/service/JobOrderService.kt View File

@@ -2,6 +2,7 @@ package com.ffii.fpsms.modules.jobOrder.service

import com.ffii.core.exception.BadRequestException
import com.ffii.core.response.RecordsRes
import com.ffii.core.utils.CanonPrinterUtil
import com.ffii.core.utils.GsonUtils
import com.ffii.core.utils.PdfUtils
import com.ffii.core.utils.QrCodeUtil
@@ -395,7 +396,7 @@ open class JobOrderService(
params["FGCode"] = pickRecordInfo.firstOrNull()?.get("fgCode") as? String ?: "N/A"
params["FGName"] = pickRecordInfo.firstOrNull()?.get("fgName") as? String ?: "N/A"

/*// Debug UOM information
/* Debug UOM information
val bomItemUomIdRaw = pickRecordInfo.firstOrNull()?.get("bomItemUomId")
val bomItemId = pickRecordInfo.firstOrNull()?.get("bomItemId")
val uomCode = pickRecordInfo.firstOrNull()?.get("uomCode") as? String
@@ -420,9 +421,10 @@ open class JobOrderService(
)
}

//Print Pick Record
@Transactional
open fun printPickRecord(request: PrintPickRecordRequest){
//val printer = printerService.findById(request.printerId) ?: throw java.util.NoSuchElementException("No such printer")
val printer = printerService.findById(request.printerId) ?: throw java.util.NoSuchElementException("No such printer")

val pdf = exportPickRecord(
ExportPickRecordRequest(
@@ -437,8 +439,30 @@ open class JobOrderService(
try{
JasperExportManager.exportReportToPdfFile(jasperPrint,tempPdfFile.absolutePath)

val printQty = if (request.printQty == null || request.printQty <= 0) 1 else request.printQty

// Auto-detect orientation and set duplex mode accordingly
val duplexMode = if (CanonPrinterUtil.isLandscape(tempPdfFile)) {
CanonPrinterUtil.DuplexMode.DUPLEX_SHORT_EDGE // Landscape: flip on short edge
} else {
CanonPrinterUtil.DuplexMode.DUPLEX_LONG_EDGE // Portrait: flip on long edge
}

println("DEBUG: PDF orientation detected - Landscape: ${CanonPrinterUtil.isLandscape(tempPdfFile)}, Duplex mode: $duplexMode")

printer.ip?.let { ip ->
printer.port?.let { port ->
CanonPrinterUtil.printPdfToCanon(
tempPdfFile,
ip,
port,
printQty,
duplexMode
)
}
}
} finally {
//tempPdfFile.delete
//tempPdfFile.delete()
}
}



+ 1
- 1
src/main/java/com/ffii/fpsms/modules/master/service/BomService.kt View File

@@ -492,7 +492,7 @@ open class BomService(
// val folder = File(folderPath)
val resolver = PathMatchingResourcePatternResolver()
// val excels = resolver.getResources("bomImport/*.xlsx")
val excels = resolver.getResources("file:C:/Users/ffii_/Downloads/bom/new/*.xlsx")
val excels = resolver.getResources("file:C:/Users/Kelvin YAU/Downloads/bom/*.xlsx")
// val excels = resolver.getResources("file:C:/Users/2Fi/Desktop/Third Wave of BOM Excel/*.xlsx")
println("size: ${excels.size}")
val logExcel = ClassPathResource("excelTemplate/bom_excel_issue_log.xlsx")


Loading…
Cancel
Save