跳到內容

發票與電子發票

Spec: EN 16931-1:2026, BT-24 Spec: Factur-X 1.08 Spec: ISO 32000-2:2020, §14.13 Evidence: Mixed evidence

一份現代發票,是同一個檔案裡的兩份文件:一頁給人閱讀,另一段是供稅務系統解析的機器可讀 XML 酬載。本頁從法規義務一路說到實際產出,說明混合式發票情境——ZUGFeRD 與 Factur-X 實際要求什麼、NextPDF 如何附加並檢查結構化酬載,以及合規何時不再是引擎的工作,而成為你的責任界線。

如今已有多個司法管轄區,針對企業對企業或企業對政府開立發票,強制要求使用結構化發票。陷阱在於:一份混合式發票在畫面上可能看起來完美無缺,卻仍可能遭到退件。退件針對的是內嵌的 XML,而不是畫素。如果結構化酬載缺少規格識別碼、宣告了錯誤的設定檔,或以錯誤的關聯方式附加,接收平台就會將它判為失敗。從你這一端看,這種失敗往往沒有明顯訊號,而且要到數天之後才會浮現,背後還卡著一筆被擱置的款項。

在產生檔案的那一層就把這件事一次做對,遠比等發票進入清算流程後才逐張發現問題便宜得多。

  • 一份合規的混合式發票,是一個 PDF/A 載體,搭配一段 以關聯檔案形式內嵌的合規 XML 酬載。載體的中繼資料必須宣告該設定檔。
  • 最常決定能否被接受的單一欄位,是 BT-24,也就是規格識別碼EN 16931 商業規則 BR-1 要求每一張發票都必須帶有它。其值是一個 URN,用以指明確切的設定檔——例如 EN 16931(COMFORT)設定檔的 urn:cen.eu:en16931:2017
  • NextPDF 的工作,是對呼叫端提供的 XML 進行 內嵌與結構驗證。它不會撰寫發票內容,也 並非稅務機關的驗證器
  • 簽發者仍須對法律與財稅正確性負責。乾淨的驗證結果只是該決策的其中一項輸入,並不是一張證書。

NextPDF 將結構化發票視為一份 跨層級契約,而不是單一功能。核心引擎定義介面——內嵌器、設定檔描述器、驗證器——由 Premium 層提供實作。這樣的分離是有意為之。公開介面在核心中凍結,因此無論背後是哪一層,呼叫端與測試都會以相同方式處理設定檔與結果。

此流程分為四個階段,順序很重要,因為每一個階段都依賴前一個階段。

  1. Author the invoice XML You (or your ERP) produce a UN/CEFACT CII or Peppol UBL payload. NextPDF never synthesizes invoice content.
  2. Produce the PDF/A carrier A PDF/A-3 or PDF/A-4f document is the human-readable face and the conformant container the standard requires.
  3. Embed the payload The embedder attaches the XML as an associated file with the correct AFRelationship, and injects the Factur-X XMP profile declaration.
  4. Validate, then ship A structural pass checks the root, the required sections, and BT-24 against the declared profile before the file leaves your system.
從頭到尾的混合式電子發票情境:由你撰寫 XML 並對其法律正確性負責;NextPDF 負責承載並對其進行結構檢查;接收平台做出最終的接受決策。

內嵌器契約採位元組進、位元組出:輸入一個 PDF/A 載體與一段 XML 酬載,輸出混合式 PDF 位元組。附加任何內容之前,XML 會先通過一道強化防護的解析程序;它會拒絕 DOCTYPE、限制輸入大小,並拒絕 XML 1.0 禁止的控制字元。這會從根本上消除 XML 外部實體(XXE)與 Billion-Laughs 攻擊,因為發票 XML 經常來自你的信任邊界之外。

設定檔描述器回答下游系統會問的四個問題:標準設定檔 URN、要主張的 BT-24 值、供記錄使用的穩定名稱,以及一個與層級無關的判別值,讓對等性測試能夠將結果分組。描述器也誠實呈現缺漏之處。ZUGFeRD MINIMUM 設定檔不帶有 BT-24 規格識別碼,描述器對它回傳 null 而不是捏造一個。 這也是為什麼 MINIMUM 與 BASIC WL 並非 EN 16931 合規。 引擎是把基數規定如實編入其中,而不是把它藏起來。

上述行為有三個依據,而每一處承載的證據種類都不相同。

標準 定義義務。 Spec: EN 16931-1:2026, BR-1 讓規格識別碼成為每一張發票的強制項目。 Factur-X 技術附錄為每個設定檔固定了 URN 值,包括 EN 16931 設定檔的 urn:cen.eu:en16931:2017。 載體本身是一個 PDF 層面的問題: Spec: ISO 32000-2:2020, §9 指出最可預測、最可靠的呈現,會在所有字型皆內嵌時發生——這與發票直接相關,因為一張十年後仍須能被閱讀的發票,不能依賴閱讀者的字型環境。

程式碼 承載著契約。 Evidence: Code-backed 核心的 EmbedderInterfaceProfileInterfaceValidatorInterface 是真實存在、且與層級無關的介面。 ProfileType::isEn16931Conformant() 在型別系統中編入 MINIMUM/BASIC WL 的排除規則。 ValidationResult 是一個不可變的 DTO,其 isValid 同時要求「無錯誤發現」與「無致命規則違反」成立。

行為 則以 Premium 層的能力描述記載: Evidence: Standard-backed 內嵌器會把呼叫端提供的 ZUGFeRD 2.4/Factur-X 1.08 CII 或 Peppol UBL XML,附加到 PDF/A-4fPDF/A-3b 載體上,並設定正確的關聯檔案關係。 驗證器會檢查 EN 16931 語意模型,以及 BT-24 識別碼。 Schematron 階段會執行已編譯為 XSLT 的 CEN 規則集。 其中沒有任何部分會產生或修正發票內容。

以下範例只是用來說明整合接點,並非可直接複製貼上的整合。載體的建構與內嵌器來自 Premium 層,而 XML 是你的。

<?php
declare(strict_types=1);
use NextPDF\Contracts\EInvoice\ProfileType;
use NextPDF\Contracts\EInvoice\ValidatorContext;
use NextPDF\Contracts\EInvoice\ValidatorInterface;
use NextPDF\Contracts\EInvoice\EmbedderInterface;
use NextPDF\Contracts\EInvoice\EmbedderOptions;
use Psr\Log\LoggerInterface;
/**
* Validate first, embed second, never ship an invalid payload.
*
* @param non-empty-string $carrierPdf PDF/A-3 or PDF/A-4f carrier bytes
* @param non-empty-string $ciiXml Caller-authored UN/CEFACT CII XML
*
* @return non-empty-string Hybrid invoice bytes, ready to deliver
*/
function buildHybridInvoice(
ValidatorInterface $validator,
EmbedderInterface $embedder,
LoggerInterface $logger,
string $carrierPdf,
string $ciiXml,
): string {
// STRICT mode: a missing BT-24 is a hard error, not a warning.
$context = new ValidatorContext(
profile: ProfileType::EN16931,
strictMode: true,
);
$result = $validator->validate($ciiXml, $context);
if (!$result->isValid) {
foreach ($result->getErrors() as $finding) {
$logger->error('invoice.structural_finding', [
'message' => $finding->message,
]);
}
// A failed structural check is your signal to stop, not to ship.
throw new \RuntimeException('Invoice XML failed structural validation.');
}
$options = new EmbedderOptions(profile: ProfileType::EN16931);
return $embedder->embed($carrierPdf, $ciiXml, $options);
}

重點正在於順序。相較於一張被退件的發票與一筆被延遲的款項,驗證的成本很低,因此它會在酬載被附加之前先行執行。

最昂貴的誤解是 「NextPDF 讓我的發票變得合規。」 它不會,而且它也明確地這麼說。引擎只會內嵌並結構檢查你撰寫的 XML。一個通過的結構結果,意味著酬載具有 EN 16931 所預期的形狀,並宣告了你所要求的設定檔。它 並不 意味著該發票在法律上充分、經稅務機關核可,或保證會被任何清算平台接受。國家層級的擴充與清算傳輸,在引擎層級屬於範圍之外。正如 EN 16931-1 自身所說明,核心模型承載著支援合規所需的資訊。簽發者有責任滿足相關法律規定。

第二個更不醒目的陷阱是:支援某項標準,並不等於符合該標準。合規是最終檔案加上一個驗證器所構成的性質,而不是產生它的函式庫本身具備的性質。

  • NextPDF 不會撰寫或修正發票內容。 呼叫端必須提供有效的 XML,並且仍是發票的簽發者。一份空的發現清單,並不能讓一段不合規的酬載變得合規。
  • 結構化內嵌與 Schematron 驗證屬於 Premium 層能力。 核心定義契約;實作則需要商業套件。請參閱下方的界線。
  • 驗證器僅檢查 EN 16931 語意模型,以及 ZUGFeRD/Factur-X/UBL 容器。 它並非稅務機關的驗證器。SDI、Chorus Pro 與 XRechnung 的傳輸,在傳輸層級屬於範圍之外。
  • MINIMUM 與 BASIC WL 設定檔並非 EN 16931 合規,且不帶有 BT-24 規格識別碼——這是刻意設計,反映的是標準的基數規定,而非引擎的限制。
  • Schematron 引擎需要 ext-xsl 規則集會在建置時編譯。執行階段只會執行預先編譯好的 XSLT,並停用網路與檔案系統的資源載入。
  • 本頁所描述的是能力層級行為。它並未主張會獲得任何特定機關或平台接受。
Structured e-invoice embedding and validation — edition availability
Edition Availability
Core

核心定義跨層級契約(EmbedderInterfaceProfileInterfaceValidatorInterface),但不隨附任何結構化發票的實作。 一個沒有結構化酬載的純 PDF 載體,就是僅核心的結果。

Pro

可使用將 Factur-X 1.08 CII 內嵌到 PDF/A 載體,以及 EN 16931 設定檔描述器。

Enterprise

新增 Peppol BIS 3.0 UBL 內嵌、XRechnung B2G CIUS、COMPAT/STRICT XML 驗證,以及行程內的 Schematron 規則引擎。

  • 封存與 PDF/A——為什麼發票載體是一個 PDF/A 檔案,以及它對長期可讀性提供什麼保證。
  • 整合決策指南——哪一個生態系套件適合你的開立發票管線(佇列化產生、框架橋接,或 Connect)。
  • 在正式環境中運行 NextPDF——當發票大量流動時,如何觀測驗證發現與失敗。
  • 混合式發票——單一 PDF 檔案,同時包含人類可讀頁面與機器可讀的內嵌 XML 發票酬載。
  • ZUGFeRD/Factur-X——同一種混合式發票做法的德文與法文名稱:一段內嵌於 PDF/A 載體中的 UN/CEFACT 跨產業發票(CII)XML 酬載。
  • EN 16931——用來定義電子發票核心元素之語意資料模型的歐洲標準。
  • BT-24(規格識別碼)——EN 16931 商業術語,其值是一個 URN,用以指明發票所遵循的確切設定檔。由商業規則 BR-1 要求。
  • 設定檔——也稱為合規等級(MINIMUM、BASIC WL、BASIC、EN 16931、EXTENDED、XRECHNUNG)。決定一張發票必須帶有哪些商業術語。
  • 關聯檔案——一個附加於 PDF 內部的檔案,帶有宣告好的關係(AFRelationship),描述它如何與可見文件相關聯;也就是承載發票 XML 的機制。
  • Schematron——一種用來表達 EN 16931 商業規則的規則語言。NextPDF 會執行已編譯為 XSLT 的 CEN 規則集。