#process#report#hierarchy#pdf#thai-font#big-rat
การจัดกลุ่มหลายระดับและการพิมพ์ PDF รายงาน (Report hierarchy & PDF)
หลัง RunReport ได้แถวและยอดรวมแล้ว มี 2 งานต่อท้าย: (1) สร้างต้นไม้กลุ่มหลายระดับพร้อมยอดย่อยแบบ *big.Rat (2) เมื่อเรียก /report/pdf เรนเดอร์ผลเดียวกันเป็น PDF ภาษาไทยด้วย gopdf ฟอนต์ที่ฝังในโค้ด
ทำงานอย่างไร
การจัดกลุ่มหลายระดับ (buildReportMultiLevelHierarchy)
- ผลลัพธ์ใส่ใน
res.HierarchyLevels([]ReportHierarchyLevel:level,keyColumn,labelColumn,extraColumns,titlePrefix) และres.GroupNodes([]ReportGroupNode:groupKey,groupLabel,openingValueจากแถว "ยอดยกมา",rowCount,rowIndices,subtotals,children) - ระดับมาจาก 2 ทาง: ตรวจโครงสร้างอัตโนมัติ (
inferReportHierarchyLevelsเช่น เคลื่อนไหวสินค้า/บัตรสินค้า/ยอดคงเหลือตามคลัง/เคลื่อนไหวเจ้าหนี้-ลูกหนี้/สมุดรายวัน) หรือผู้ใช้เลือกgroupByColumn+subGroupByColumn(1-2 ระดับ) กับรายงานใดก็ได้รวมถึง Custom SQL - ถ้าผู้ใช้เลือกกลุ่มเอง
ensureRowsContiguousForLevelsจัดแถวให้ติดกันตามคีย์ โดยคงลำดับเวลาภายในกลุ่ม - ยอดย่อยของกลุ่ม (
computeGroupNodeSubtotals) คำนวณด้วย*big.Rat
รายงานแบบยอดสะสม (running balance)
isRunningBalanceReportถือว่าเป็นรายงานยอดสะสมเมื่อReportTypeCodeมีSTK_MOVE/STK_CARDหรือเท่ากับIC_REPORT_PRODUCT_MATERIAL,IC_REPORT_TRANSFER_STANDARD,AP_MOVEMENT,AR_MOVEMENTหรือมีชุดคอลัมน์ (จำนวนเพิ่ม/จำนวนลด/ยอดคงเหลือ,ยอดเพิ่มหนี้/ยอดลดหนี้/ยอดคงค้าง,เดบิต/เครดิต/ยอดคงเหลือ)- กฎ: คอลัมน์เคลื่อนไหว (เพิ่ม/ลด) รวมทุกบรรทัดของกลุ่ม; คอลัมน์ยอดคงเหลือ/ยอดคงค้าง/มูลค่า/ต้นทุนเฉลี่ย ใช้ค่าแถวสุดท้ายของกลุ่ม และ ยอดรวมทั้งรายงาน = ผลรวมของยอดปลายงวดของแต่ละกลุ่มระดับ 1 (ไม่รวมยอดสะสมทุกบรรทัดซ้ำซ้อน) ผ่าน
applyRunningBalanceGrandTotalsซึ่งแก้res.Totals
การพิมพ์ PDF (RenderReportPDF)
- ทางเข้า
POST /process/report/pdf(สิทธิ์เหมือนreport/run) ->Handler.RenderReportPDFตั้ง provider/database/username จาก claims RenderReportPDFเรียกRunReportด้วยเงื่อนไขชุดเดียวกับหน้าจอ แล้วโหลดหัวบริษัทจากerp_company_profile(company_name_1/2,address_1/2,tax_number; timeout 3 วินาที; ถ้าไม่มีข้อมูลใช้ชื่อเริ่มต้นของระบบ)- ถ้า
reportLang = enโหลดตารางแปลชื่อไทย->อังกฤษ (loadBilingualDataMap, สูงสุด 10,000 คู่ จากic_inventory,ic_unit,ar_customer,ap_supplier,gl_chart_of_account) แล้วแทนค่าข้อความในเซลล์ที่ตรงกันพอดี buildReportPDFBytesใช้ตัวเลือกจากRunReportInput:paperSize(A4 ค่าเริ่มต้น, A3, Letter, Legal, A5, Continuous/9X11),orientation(auto= แนวนอนเมื่อคอลัมน์เกิน 7),fontSizePt(ค่าเริ่มต้น 8.5 และหนีบ 6.5-13.0),density(compact/comfortable/ปกติ),printTheme,colorMode(monochrome/grayscale/สี),showZebra,showRowNumber,showCompanyHeader,showSignatureBlock(บล็อกลายเซ็น 3 ช่อง ความสูง 62),signatureLabels,footerNote- ชื่อไฟล์:
<menuKey>_<yyyymmdd_hhmm>.pdf(ใช้sml_reportถ้าไม่มี menuKey) - ฟอนต์ไทย 2 ไฟล์ฝังด้วย
//go:embedจากโฟลเดอร์fonts/:thai-regular.ttf,thai-bold.ttf - การตัดบรรทัดไทย: แบ่งตาม grapheme cluster และโทเค็นคำ (
splitIntoGraphemeClusters,segmentThaiTokens,wrapTextToLines), ปรับสระ/วรรณยุกต์บน (normalizeThaiUpstairsMarks), คำนวณความกว้างคอลัมน์ให้ตัวเลขไม่ถูกตัด (fitPDFNumbers,widenPDFNumericColumns) และนับเลขหน้าแบบ "X/Y" โดยทำ 2 รอบ (pdfPageBreakBeforeใช้ทั้งสองรอบ) pageBreakColumn(ตั้งโดยตัวสร้างรายงาน) ทำให้ขึ้นหน้าใหม่เมื่อค่าคอลัมน์เปลี่ยน (C#new_page_by_ar_code)
จุดที่ต้องระวัง
- ข้อความหัวบริษัทเริ่มต้นใน
loadCompanyHeaderInfoเป็นค่าฮาร์ดโค้ด ใช้เมื่อไม่มีerp_company_profile - PDF ใช้แถวหลังผ่าน
RunReportทั้งหมด จึงมีข้อจำกัดเดียวกัน เช่น Custom SQL ที่ถูกปฏิเสธเพราะต้นทุน - การแปลเป็นภาษาอังกฤษแทนเฉพาะค่าที่ตรงกับ
name_1ทั้งข้อความ ไม่แปลข้อความผสม
ที่มาในโค้ด
backend/internal/application/process/report_hierarchy.go:27-49-ReportHierarchyLevel,ReportGroupNodebackend/internal/application/process/report_hierarchy.go:51-buildReportMultiLevelHierarchybackend/internal/application/process/report_hierarchy.go:97-applyRunningBalanceGrandTotalsbackend/internal/application/process/report_hierarchy.go:124-inferReportHierarchyLevelsbackend/internal/application/process/report_hierarchy.go:625-isRunningBalanceReportbackend/internal/application/process/report_pdf.go:23-27- ฝังฟอนต์ไทยbackend/internal/application/process/report_pdf.go:35-loadCompanyHeaderInfobackend/internal/application/process/report_pdf.go:76-loadBilingualDataMapbackend/internal/application/process/report_pdf.go:111-RenderReportPDFbackend/internal/application/process/report_pdf.go:318-resolvePaperDimensionsbackend/internal/application/process/report_pdf.go:525-buildReportPDFBytesbackend/internal/application/process/report_pdf.go:1298-pdfPageBreakBeforebackend/internal/adapter/inbound/http/process/handler.go:270- handlerRenderReportPDF