139 lines
3.9 KiB
Python
139 lines
3.9 KiB
Python
"""Generate PDF: IPD Filing Receipt (native text PDF, bilingual)."""
|
|
|
|
from pathlib import Path
|
|
from reportlab.lib.pagesizes import A4
|
|
from reportlab.lib.units import mm
|
|
from reportlab.pdfgen import canvas
|
|
from reportlab.lib.colors import HexColor
|
|
from generators.cjk_font import register_cjk_font
|
|
|
|
|
|
def _set_font(c, bold=False, size=10):
|
|
"""Set font with CJK support."""
|
|
cjk = register_cjk_font()
|
|
if cjk != "Helvetica":
|
|
c.setFont(cjk, size)
|
|
else:
|
|
c.setFont("Helvetica-Bold" if bold else "Helvetica", size)
|
|
|
|
|
|
def _has_cjk(text):
|
|
"""Check if text contains CJK characters."""
|
|
return any(ord(ch) > 0x2E80 for ch in text)
|
|
|
|
|
|
def generate(
|
|
output_path: Path,
|
|
ipd: dict,
|
|
tm_number: str,
|
|
tm_text: str,
|
|
applicant: str,
|
|
applicant_address: str,
|
|
agent: str,
|
|
agent_address: str,
|
|
filing_date: str,
|
|
response_deadline: str,
|
|
nice_class: str,
|
|
class_description: str,
|
|
):
|
|
"""Generate an IPD filing receipt PDF."""
|
|
cjk = register_cjk_font()
|
|
c = canvas.Canvas(str(output_path), pagesize=A4)
|
|
w, h = A4
|
|
|
|
def draw_text(x, y_pos, text, size=10, bold=False, centered=False):
|
|
"""Draw text, auto-switching to CJK font if needed."""
|
|
if _has_cjk(text) and cjk != "Helvetica":
|
|
c.setFont(cjk, size)
|
|
else:
|
|
c.setFont("Helvetica-Bold" if bold else "Helvetica", size)
|
|
if centered:
|
|
c.drawCentredString(x, y_pos, text)
|
|
else:
|
|
c.drawString(x, y_pos, text)
|
|
|
|
# Header
|
|
draw_text(w / 2, h - 50, ipd["name"], 12, bold=True, centered=True)
|
|
draw_text(w / 2, h - 66, ipd["chinese_name"], 10, centered=True)
|
|
draw_text(
|
|
w / 2,
|
|
h - 82,
|
|
"The Government of the Hong Kong Special Administrative Region",
|
|
10,
|
|
centered=True,
|
|
)
|
|
|
|
# Divider
|
|
c.setStrokeColor(HexColor("#333333"))
|
|
c.setLineWidth(1)
|
|
c.line(50, h - 95, w - 50, h - 95)
|
|
|
|
# Title
|
|
draw_text(
|
|
w / 2,
|
|
h - 120,
|
|
"E-Filing Receipt / Acknowledgment",
|
|
14,
|
|
bold=True,
|
|
centered=True,
|
|
)
|
|
|
|
# Receipt details
|
|
y = h - 160
|
|
fields = [
|
|
("Receipt No.:", f"EF-{tm_number[-6:]}"),
|
|
("Application No. / 申請編號:", tm_number),
|
|
("Trade Mark Text / 商標文字:", tm_text),
|
|
("Mark Type / 商標種類:", "Ordinary"),
|
|
("Class No. / 類別編號:", nice_class),
|
|
("Specification / 貨品/服務說明:", class_description),
|
|
("", ""),
|
|
("Applicant / 申請人:", applicant),
|
|
("Address / 地址:", applicant_address),
|
|
("", ""),
|
|
("Agent / 代理人:", agent),
|
|
("Agent Address / 代理人地址:", agent_address),
|
|
("", ""),
|
|
("Date of Filing / 提交日期:", filing_date),
|
|
("Date of Receipt / 確認日期:", filing_date),
|
|
]
|
|
|
|
for label, value in fields:
|
|
if not label and not value:
|
|
y -= 10
|
|
continue
|
|
draw_text(50, y, label, 10, bold=True)
|
|
# Wrap long values
|
|
if len(value) > 60:
|
|
draw_text(250, y, value[:60], 10)
|
|
y -= 16
|
|
draw_text(250, y, value[60:120], 10)
|
|
else:
|
|
draw_text(250, y, value, 10)
|
|
y -= 18
|
|
|
|
# Response deadline (highlighted)
|
|
y -= 15
|
|
c.setStrokeColor(HexColor("#cc0000"))
|
|
c.setLineWidth(0.5)
|
|
c.rect(40, y - 10, w - 80, 40, stroke=1, fill=0)
|
|
|
|
c.setFillColor(HexColor("#cc0000"))
|
|
draw_text(50, y + 12, "IMPORTANT / 重要通知:", 11, bold=True)
|
|
c.setFillColor(HexColor("#000000"))
|
|
draw_text(50, y - 4, f"Response deadline / 回覆限期: {response_deadline}", 10)
|
|
|
|
# Footer
|
|
y -= 50
|
|
c.setFillColor(HexColor("#666666"))
|
|
draw_text(
|
|
w / 2,
|
|
y,
|
|
"This is a computer-generated receipt. No signature is required.",
|
|
8,
|
|
centered=True,
|
|
)
|
|
draw_text(w / 2, y - 14, "此為電腦自動產生之收據,毋須簽署。", 8, centered=True)
|
|
|
|
c.save()
|