fix(corporate-bank-account-payment-order): 恢复制单表头富文本并标识行号

这个提交包含在:
2026-08-03 08:54:02 +08:00
父节点 23c3768c46
当前提交 483f7ae6bf
共修改 9 个文件,包含 160 行新增和 9 行删除
@@ -13,6 +13,7 @@ import sys
try:
import xlrd
import xlwt
from xlutils.filter import process, XLRDReader, XLWTWriter
except ImportError:
sys.stderr.write("[payment-order-template][ERROR] runtime_dependency_unavailable\n")
@@ -26,6 +27,17 @@ COLUMN_COUNT = 15
TEMPLATE_DATA_ROW = 1
MAX_INPUT_BYTES = 2 * 1024 * 1024
MAX_ROWS = 5000
EXPECTED_RICH_TEXT_CELLS = {
(0, 0),
(0, 1),
(0, 2),
(0, 3),
(0, 4),
(0, 5),
(0, 9),
(0, 10),
(0, 12),
}
class TemplateFillError(Exception):
@@ -78,6 +90,58 @@ def read_template() -> tuple[bytes, xlrd.book.Book]:
return template_bytes, book
def copy_template_font(source: xlrd.formatting.Font) -> xlwt.Font:
target = xlwt.Font()
target.height = source.height
target.italic = source.italic
target.struck_out = source.struck_out
target.outline = source.outline
target.shadow = source.shadow
target.colour_index = source.colour_index
target.bold = source.bold
target._weight = source.weight
target.escapement = source.escapement
target.underline = source.underline_type
target.family = source.family
target.charset = source.character_set
target.name = source.name
return target
def restore_template_rich_text(
source_book: xlrd.book.Book,
writer: XLWTWriter,
target_sheet: xlwt.Worksheet,
) -> None:
source_sheet = source_book.sheet_by_index(0)
rich_text_runs = source_sheet.rich_text_runlist_map
if not EXPECTED_RICH_TEXT_CELLS.issubset(rich_text_runs):
raise TemplateFillError("template_structure_mismatch")
for (row, column), runs in sorted(rich_text_runs.items()):
text = source_sheet.cell_value(row, column)
if not isinstance(text, str) or not runs:
raise TemplateFillError("template_structure_mismatch")
parts: list[object] = []
first_offset = runs[0][0]
if first_offset < 0 or first_offset >= len(text):
raise TemplateFillError("template_structure_mismatch")
if first_offset > 0:
parts.append(text[:first_offset])
for index, (offset, font_index) in enumerate(runs):
end = runs[index + 1][0] if index + 1 < len(runs) else len(text)
if offset < first_offset or end <= offset or end > len(text):
raise TemplateFillError("template_structure_mismatch")
try:
source_font = source_book.font_list[font_index]
except IndexError:
raise TemplateFillError("template_structure_mismatch") from None
parts.append((text[offset:end], copy_template_font(source_font)))
style_index = source_sheet.cell_xf_index(row, column)
target_sheet.write_rich_text(row, column, parts, writer.style_list[style_index])
def fill_workbook(rows: list[list[object]], source_book: xlrd.book.Book) -> bytes:
writer = XLWTWriter()
try:
@@ -86,6 +150,7 @@ def fill_workbook(rows: list[list[object]], source_book: xlrd.book.Book) -> byte
source_sheet = source_book.sheet_by_index(0)
target_sheet = target_book.get_sheet(0)
target_sheet._cell_overwrite_ok = True
restore_template_rich_text(source_book, writer, target_sheet)
source_row_info = source_sheet.rowinfo_map.get(TEMPLATE_DATA_ROW)
source_row_height = source_row_info.height if source_row_info else 735
+1 -1
查看文件
@@ -13,7 +13,7 @@ class PaymentOrderXlsError extends Error {
}
function buildCustomerSerial(batchNo, rowNumber) {
const serial = `${String(batchNo).trim()}-${String(rowNumber).padStart(3, "0")}`;
const serial = `${String(batchNo).trim()}-R${String(rowNumber).padStart(3, "0")}`;
if (serial.length > 32) {
throw new PaymentOrderXlsError("customer_serial_too_long");
}