forked from erp-dev/erp
feat: added print-template(test) and sync_mdy_plate_order beat task setting
This commit is contained in:
109
printing/test_docx_pagination.py
Normal file
109
printing/test_docx_pagination.py
Normal file
@@ -0,0 +1,109 @@
|
||||
import re
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
|
||||
class DocxPaginationTest(SimpleTestCase):
|
||||
def _read_document_xml(self, docx_path: str) -> str:
|
||||
with zipfile.ZipFile(docx_path, "r") as zf:
|
||||
return zf.read("word/document.xml").decode("utf-8", errors="replace")
|
||||
|
||||
def _extract_pages_text(self, docx_path: str) -> list[str]:
|
||||
"""
|
||||
Extract per-page plain text by walking body elements and splitting on page breaks.
|
||||
|
||||
Important: we extract w:t texts, so assertions won't be broken by XML tag boundaries.
|
||||
"""
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
xml = self._read_document_xml(docx_path)
|
||||
ns = {"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"}
|
||||
root = ET.fromstring(xml)
|
||||
|
||||
body = root.find("w:body", ns)
|
||||
if body is None:
|
||||
return []
|
||||
|
||||
pages: list[list[str]] = [[]]
|
||||
|
||||
def has_page_break(el) -> bool:
|
||||
for br in el.findall(".//w:br", ns):
|
||||
if br.attrib.get(f"{{{ns['w']}}}type") == "page":
|
||||
return True
|
||||
return False
|
||||
|
||||
def collect_text(el) -> str:
|
||||
ts = [(t.text or "") for t in el.findall(".//w:t", ns)]
|
||||
return "".join(ts)
|
||||
|
||||
for child in list(body):
|
||||
text = collect_text(child)
|
||||
if text:
|
||||
pages[-1].append(text)
|
||||
if has_page_break(child):
|
||||
pages.append([])
|
||||
|
||||
return ["".join(p) for p in pages if "".join(p).strip()]
|
||||
|
||||
def test_render_pages_per_page_totals(self):
|
||||
template = str(Path(settings.BASE_DIR) / "print-template.docx")
|
||||
out = str(Path(settings.BASE_DIR) / ".tmp_docx" / "rendered-pages-test.docx")
|
||||
Path(out).parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
from printing.docx_template import render_docx_template_pages
|
||||
|
||||
prefix = "打印-销售单(8*9)."
|
||||
|
||||
# Page 1: two non-empty qty cells => 匹数=2, 总数量=111.11
|
||||
page1 = {
|
||||
f"{prefix}当前页码": "1",
|
||||
f"{prefix}总页数": "2",
|
||||
f"{prefix}匹数": "2",
|
||||
f"{prefix}总数量": "111.11",
|
||||
# Put a couple of quantities too (indices exist 1..72)
|
||||
f"{prefix}销售数量1": "11.11",
|
||||
f"{prefix}销售数量2": "100",
|
||||
# Fill one product line (index 1 exists for product fields)
|
||||
f"{prefix}产品名称1": "P1-产品",
|
||||
f"{prefix}幅宽1": "150cm",
|
||||
f"{prefix}规格1": "规格A",
|
||||
f"{prefix}单位1": "米",
|
||||
}
|
||||
|
||||
# Page 2: one non-empty qty cell => 匹数=1, 总数量=222.22
|
||||
page2 = {
|
||||
f"{prefix}当前页码": "2",
|
||||
f"{prefix}总页数": "2",
|
||||
f"{prefix}匹数": "1",
|
||||
f"{prefix}总数量": "222.22",
|
||||
f"{prefix}销售数量1": "222.22",
|
||||
f"{prefix}产品名称1": "P2-产品",
|
||||
f"{prefix}幅宽1": "160cm",
|
||||
f"{prefix}规格1": "规格B",
|
||||
f"{prefix}单位1": "码",
|
||||
}
|
||||
|
||||
render_docx_template_pages(
|
||||
template_path=template,
|
||||
output_path=out,
|
||||
pages_contexts=[page1, page2],
|
||||
clear_unresolved=True,
|
||||
)
|
||||
|
||||
pages_text = self._extract_pages_text(out)
|
||||
self.assertGreaterEqual(len(pages_text), 2, msg="未生成两页文本(可能分页符缺失)")
|
||||
|
||||
p1, p2 = pages_text[0], pages_text[1]
|
||||
self.assertIn("P1-产品", p1)
|
||||
self.assertIn("111.11", p1)
|
||||
self.assertIn("P2-产品", p2)
|
||||
self.assertIn("222.22", p2)
|
||||
|
||||
# No raw placeholders should remain (check on plain text concatenation)
|
||||
all_text = "".join(pages_text)
|
||||
self.assertIsNone(re.search(r"#\{.{1,300}?\}", all_text, flags=re.S))
|
||||
self.assertIsNone(re.search(r"(?<!#)\{[^{}\r\n]{1,200}\}", all_text))
|
||||
|
||||
Reference in New Issue
Block a user