PAYATHON 2026

如何在 Swiss QR invoice 中合理放置填写框

支付老李

结论

不要自行压缩或重新设计填写框。Swiss QR invoice(通常称为 Swiss QR-bill)的支付部分有明确的尺寸和排版要求,需要同时参考两份文档:

  • Swiss Implementation Guidelines QR-bill:规定 QR 数据结构、字段和业务规则。
  • Style Guide QR-bill:规定 payment part、receipt、填写框、字体、间距和分隔线等视觉样式。

右侧空间不足,通常不是规范遗漏,而是页面显示了不该出现的字段,或者没有按照 Style Guide 对地址、空金额和付款人信息进行条件排版。还要特别确认系统中的 final creditor 是否指规范中的 Ultimate Creditor。该数据组虽然存在于数据模型,但在长期发布的实施规则中一直是”保留供将来使用”的字段。能否使用,应以项目当前采用的官方规范版本为准,不能因为数据模型中有这个字段就直接显示。

先确认页面的固定尺寸

完整付款单区域位于 A4 页面底部,高度为 105 mm,总宽度为 210 mm:

  • Receipt:62 mm × 105 mm
  • Payment part:148 mm × 105 mm

Payment part 不是可以自由流动排版的普通文档区域。QR code、Account / Payable to、Reference、Additional information、Payable by、Currency 和 Amount 都有固定位置或规定的可用范围。

如果使用 HTML、PDF 表格自动布局,或者根据内容动态增加高度,很容易造成字段下移、填写框缩小或内容越界。更稳妥的做法是使用以毫米为单位的绝对坐标,并严格限制每个文本块的最大行数。

不要同时显示所有可能字段

排版时应根据数据是否存在,选择对应的显示形式,不要为所有字段预留空间。

金额

金额已知时,直接输出数值:

Currency    Amount
CHF         1 250.00

只有金额未知时,才显示手写填写区域。填写框的尺寸和位置必须符合 Style Guide,不能为了给其他文字腾出空间而随意缩小。

付款人

如果有 Ultimate Debtor 地址,显示 Payable by 和对应地址。

如果没有该地址,则显示 Payable by (name/address) 以及规定大小的空白填写框。这两种形式不能同时出现。

Ultimate Creditor

需要确认系统中的 final creditor address 是否对应规范里的 Ultimate Creditor。如果当前实施指南仍将它列为保留字段,就不应:

  • 写入 QR payload;
  • 在 payment part 上打印;
  • 为其额外预留多行空间。

这通常是出现”至少 13 行文本”问题的原因之一。

地址行数必须受控

QR-bill 的地址应采用规范支持的结构化地址或组合地址,并放在固定区域内。不要把数据库中的任意多行邮寄地址原样复制到付款单。

典型的结构化地址如下:

Company AG
Example Street 10
8000 Zurich
CH

生成器应遵守以下约束:

  1. 根据地址类型组合街道、门牌号、邮编和城市。
  2. 删除空字段造成的空行。
  3. 使用规范允许的字号和行距。
  4. 按规范处理过长内容,包括截断或缩放。
  5. 不要通过无限换行来扩大文本块。

字号也不能缩小到 Style Guide 允许的范围之外。测试数据能够放下,不代表扫描、打印和人工填写时仍然合规。

Java 实现方式

实际项目中,建议使用专门的 Swiss QR-bill 库生成支付部分,而不是只使用普通 QR code 库。普通二维码库只能编码二维码图形,无法处理版面、Swiss cross、地址规则、参考号校验和空白填写框。

Java 生态中可以考虑 qrbill-generator。下面是一个典型用法。具体包名和方法签名可能随库版本变化,应以所选版本的文档为准:

import net.codecrete.qrbill.generator.Address;
import net.codecrete.qrbill.generator.Bill;
import net.codecrete.qrbill.generator.OutputFormat;
import net.codecrete.qrbill.generator.QRBill;

import java.math.BigDecimal;

public class InvoicePaymentPart {

    public static byte[] createQrBill() {
        Bill bill = new Bill();

        bill.setAccount("CH4431999123000889012");

        Address creditor = Address.createStructuredAddress(
                "Example Company AG",
                "Example Street",
                "10",
                "8000",
                "Zurich",
                "CH"
        );
        bill.setCreditor(creditor);

        bill.setCurrency("CHF");
        bill.setAmount(new BigDecimal("1250.00"));

        bill.setReference("210000000003139471430009017");
        bill.setUnstructuredMessage("Invoice 2026-001");

        return QRBill.generate(bill, OutputFormat.PDF);
    }
}

如果金额需要由付款人填写,就不要设置金额:

bill.setCurrency("CHF");
// 不设置 amount,生成器应输出相应的手写金额区域。

如果付款人地址也需要手写,则不要设置 debtor:

// 不设置 debtor,生成器应输出 Payable by (name/address) 填写框。

如果所用版本不支持 PDF,可以先生成 SVG,再将其嵌入 PDF:

byte[] svg = QRBill.generate(bill, OutputFormat.SVG);

接口名称需要根据实际依赖版本核对,尤其是 setAmount、地址工厂方法和输出格式。不要仅根据示例固定依赖版本。

推荐的实现流程

  1. 确定业务当前采用的 Swiss QR-bill 规范版本。
  2. 下载同一版本的 Implementation Guidelines 和 Style Guide。
  3. 根据业务数据判断实际存在哪些字段。
  4. 排除当前规范禁止使用或标记为保留的字段,特别是 Ultimate Creditor。
  5. 使用现成库生成 payment part 或完整 QR-bill。
  6. 按原始物理尺寸将生成结果嵌入发票,禁止自动缩放。
  7. 使用官方或银行提供的验证工具检查 QR payload。
  8. 分别测试已知金额、空金额、已知付款人和手写付款人等组合。
  9. 打印后使用不同银行应用扫描,并检查裁切、缩放和字体效果。

常见问题

只生成二维码是否足够?

不够。Swiss QR-bill 不只规定二维码内容,也规定周围支付部分的视觉布局。二维码正确,不代表整张付款单合规。

可以调整填写框大小吗?

原则上不应自行调整。填写区域的尺寸、边框形式和位置应以当前 Style Guide 为准。如果空间不足,应先检查字段使用方式和地址换行,不要先压缩填写框。

可以把付款单缩放后放进发票吗?

不建议。PDF 查看器或打印驱动中的”适合页面”功能可能改变物理尺寸。生成 PDF 时应使用毫米设置页面和坐标,打印测试时则应选择 100% 或”实际大小”。

为什么规范正文对布局描述不多?

数据规则和视觉规则通常写在不同文档中。Implementation Guidelines 主要说明”编码什么”,Style Guide 说明”如何呈现”。实现时需要配套使用这两份文档。

备注:内容仅供参考。