"""打印中心模型:PrintSettings(租户抬头)+ PrintTemplate(单据模板)。""" from django.db import models from apps.core.base_models import TenantScopedModel class PrintSettings(TenantScopedModel): """租户打印抬头(单例:每租户一条,code 固定 default)。""" company_name = models.CharField(max_length=128, blank=True, default="") phone = models.CharField(max_length=64, blank=True, default="") address = models.CharField(max_length=255, blank=True, default="") bank_info = models.CharField(max_length=255, blank=True, default="", help_text="开户行/账号") footer_note = models.CharField(max_length=255, blank=True, default="", help_text="页脚备注(如:货已验收,概不退换)") logo_url = models.URLField(blank=True, default="") class Meta: db_table = "printing_settings" verbose_name_plural = "打印抬头" ordering = ["id"] def __str__(self): return f"{self.company_name or '未设置抬头'}" class PrintTemplate(TenantScopedModel): """打印模板(用户可编辑的 HTML 片段,使用安全占位符语法)。 doc_type: sales_bill / purchase_bill 语法:{{path}} 取值、{{#each lines}}…{{/each}} 行循环(循环内用 {{item.xxx}})。 自研占位符渲染,不走 Django 模板引擎,杜绝模板注入。 """ DOC_TYPE_CHOICES = [ ("sales_bill", "销售单/送货单"), ("purchase_bill", "采购单/进货单"), ] code = models.CharField(max_length=64, help_text="模板代码(租户内唯一)") name = models.CharField(max_length=128) doc_type = models.CharField(max_length=32, choices=DOC_TYPE_CHOICES) body_html = models.TextField(help_text="模板正文(安全占位符语法)") paper_size = models.CharField(max_length=16, default="A4") is_default = models.BooleanField(default=False, help_text="该单据类型的默认模板") class Meta: db_table = "printing_template" unique_together = [("tenant", "code")] verbose_name_plural = "打印模板" ordering = ["doc_type", "code"] def __str__(self): return f"[{self.doc_type}] {self.code}"