新增Win7离线构建并调整PDF采购章及供需方签章位置

This commit is contained in:
reddaniel110
2026-09-17 10:41:03 +08:00
parent 768b4705dc
commit 62cd117379
15 changed files with 656 additions and 26 deletions
+3 -2
View File
@@ -13,7 +13,7 @@ from order_logic import (ORDER_FIELDS, ITEM_FIELDS, add_log, can_edit, can_appro
can_reject, clear_approval, creation_request, get_order, make_item,
next_order_no, recalc, remember_creation, save_form, snapshot, submit,
validate_order)
from pdf_export import build_pdf, seal_layout
from pdf_export import PDF_TEMPLATE_VERSION, build_pdf, seal_layout
from order_tracking import can_follow, can_record_payment
from security import current_user, db, login_required, role_required
@@ -131,7 +131,8 @@ def register_order_routes(app):
version = db.query(OrderVersion).filter_by(order_id=oid, revision=order.revision).one()
version.pdf_data = pdf_bytes(order)
version.pdf_sha256 = hashlib.sha256(version.pdf_data).hexdigest()
version.template_version = 'po-v3-legacy-current' if version.template_version == 'legacy-current' else 'po-v3'
version.template_version = (PDF_TEMPLATE_VERSION + '-legacy-current'
if version.template_version == 'legacy-current' else PDF_TEMPLATE_VERSION)
add_log(order, '审批通过并归档正式 PDF', user, request.form.get('comment'), old)
db.commit()
flash('审批通过,正式 PDF 已归档', 'ok')
+51 -22
View File
@@ -60,6 +60,8 @@ STATUS_WATERMARK = {
SEAL_COLOR = colors.HexColor("#C8102E")
SEAL_NUMBER = "3205070994140"
PDF_TEMPLATE_VERSION = "po-v4"
PDF_SEAL_SIZE = 32 * 1.3 * mm
def _seal_arc(text, radius, start, span, font, size, bottom=False,
@@ -112,7 +114,7 @@ def seal_layout(company, seal_number=SEAL_NUMBER):
class SealFlowable(Flowable):
"""公司名和印章号码环绕一圈的采购章,不含个人及日期。"""
def __init__(self, company, title, seal_number=SEAL_NUMBER, size=32 * mm):
def __init__(self, company, title, seal_number=SEAL_NUMBER, size=PDF_SEAL_SIZE):
Flowable.__init__(self)
self.layout = seal_layout(company, seal_number)
self.title = title or u"采购专用章"
@@ -153,6 +155,38 @@ class SealFlowable(Flowable):
c.restoreState()
class ConfirmationFlowable(Flowable):
"""Keep each party's label and signing space in the same fixed-size cell."""
def __init__(self, party, width, seal=None):
Flowable.__init__(self)
self.label = u"%s确认(盖章):" % party
self.width = width
self.height = PDF_SEAL_SIZE + 4 * mm
self.seal = seal
def draw(self):
c = self.canv
c.saveState()
font_size = 9.5
center_y = self.height / 2
baseline = center_y - font_size * 0.35
c.setFont(FONT_BODY, font_size)
c.setFillColor(colors.black)
c.drawString(0, baseline, self.label)
signing_start = pdfmetrics.stringWidth(self.label, FONT_BODY, font_size) + 2 * mm
signing_end = self.width - 1 * mm
if self.seal:
# Center the seal in the buyer's signing space, next to its label.
self.seal.drawOn(c, (signing_start + signing_end - self.seal.width) / 2,
center_y - self.seal.height / 2)
else:
c.setStrokeColor(colors.HexColor("#888888"))
c.setLineWidth(0.4)
c.line(signing_start, baseline - 1.5, signing_end, baseline - 1.5)
c.restoreState()
def _find_font(candidates):
for d in FONT_DIRS:
for name in candidates:
@@ -379,29 +413,24 @@ def build_pdf(order, items, out_path, watermark=None):
sign_line = u"制单:%s\n审批:%s" % (
stamp(order.created_by_name, order.created_at),
stamp(order.approved_by, order.approved_at))
confirm_line = (u"供方确认(盖章):__________________ "
u"需方确认(盖章):__________________")
# One final approval produces one procurement seal. Historical archived
# PDFs are served unchanged by order_pdf and never regenerated here.
if order.approved_by:
seal_cell = SealFlowable(order.our_company or COMPANY_NAME, u"采购专用章")
sign_tbl = Table(
[[P(sign_line, styles["sign"]), seal_cell],
[P(confirm_line, styles["sign"]), P("", styles["sign"])]],
colWidths=[128 * mm, 58 * mm])
sign_tbl.setStyle(TableStyle([
("VALIGN", (0, 0), (0, -1), "TOP"),
("VALIGN", (1, 0), (1, -1), "CENTER"),
("LEFTPADDING", (0, 0), (-1, -1), 0),
("RIGHTPADDING", (0, 0), (-1, -1), 0),
("TOPPADDING", (0, 0), (-1, -1), 0),
("BOTTOMPADDING", (0, 0), (-1, -1), 0),
]))
story.append(KeepTogether(sign_tbl))
else:
story.append(P(sign_line, styles["sign"]))
story.append(Spacer(1, 3 * mm))
story.append(P(confirm_line, styles["sign"]))
seal = (SealFlowable(order.our_company or COMPANY_NAME, u"采购专用章")
if order.approved_by else None)
party_width = 83 * mm
confirmations = Table(
[[ConfirmationFlowable(u"供方", party_width), "",
ConfirmationFlowable(u"需方", party_width, seal)]],
colWidths=[party_width, 20 * mm, party_width])
confirmations.setStyle(TableStyle([
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("LEFTPADDING", (0, 0), (-1, -1), 0),
("RIGHTPADDING", (0, 0), (-1, -1), 0),
("TOPPADDING", (0, 0), (-1, -1), 0),
("BOTTOMPADDING", (0, 0), (-1, -1), 0),
]))
story.append(KeepTogether([P(sign_line, styles["sign"]),
Spacer(1, 3 * mm), confirmations]))
return story
doc.build(make_story())