HotPDF는 Delphi 및 C++Builder에서 ZUGFeRD 및 Factur-X 전자 송장(e-invoices)을 생성, 감지 및 검증합니다. AddFacturXAssociatedFile은 EN 16931 송장 XML을 PDF/A-3 컨테이너에 임베드하고, DetectFacturXInvoice는 유입되는 하이브리드 송장을 감지하며, HPDFValidateEInvoice는 임베드된 XML에 대해 공식 EN 16931 Schematron 비즈니스 규칙을 실행합니다. 본 기사에서는 이 세 가지 단계를 살펴보고 검증 엔진이 지원하지 않는 제약 조건에 대해 솔직하게 설명합니다
이 기능 세트를 개발하게 된 계기는 기술적인 문제라기보다는 규제 때문입니다. 독일과 프랑스는 국내 B2B 거래에 대해 구조화된 전자 송장 발행을 의무화하고 있으며, 두 규제 모두 동일한 하이브리드 모델로 수렴합니다. 즉, 기존 ERP에서 생성하는 PDF 송장 내부에 기계가 읽을 수 있는 XML twin(쌍)을 포함해야 합니다. 오늘날 일반 PDF 송장만 발행하는 Delphi 회계 또는 ERP 애플리케이션은 Factur-X 또는 ZUGFeRD 송장을 발행해야 하는 엄격한 기한에 직면해 있습니다. 사실 두 명칭의 차이는 마케팅에서 제시하는 것보다 작습니다. Factur-X와 ZUGFeRD는 두 가지 이름으로 발표된 동일한 독-불 표준 규격입니다
어떤 요소가 PDF를 유효한 Factur-X 송장으로 만듭니까?
유효한 Factur-X 송장은 연관 파일(associated file)로서 정확히 하나의 구조화된 송장 XML을 임베드하고, 이를 문서 카탈로그로부터 링크하며, XMP 확장 메타데이터에 이를 선언하는 PDF/A-3 파일(ISO 19005-3)입니다. 세 가지 레이어가 조화를 이루어야 합니다. 첫째, 컨테이너는 PDF/A-1 및 PDF/A-2와 달리 모든 형식의 파일 임베딩을 허용하는 아카이브 프로필인 PDF/A-3 규격을 준수해야 합니다. 둘째, 표준 프로필의 경우 factur-x.xml 또는 독일 XRechnung 변형의 경우 xrechnung.xml로 이름 지정된 송장 XML은 카탈로그 /AF 배열 및 /Names /EmbeddedFiles 트리에 등록되어야 하며, 첨부 파일의 성격을 정의하는 AFRelationship 항목을 포함해야 합니다: Alternative는 XML이 눈에 보이는 송장의 동등한 표현임을 의미하며, 이는 대부분의 프로필이 요구하는 의미 구조입니다. 셋째, Factur-X XMP 확장 스키마는 임베드된 파일 이름, 준수 수준 및 문서 유형을 명시해야 하므로 수신 시스템은 XML을 직접 파싱하지 않고도 송장을 분류할 수 있습니다
XML 페이로드 자체는 핵심 송장 정보(구매자, 판매자, 라인 항목, 세금 내역, 지불 금액 등, 각각 BT-1은 송장 번호, BT-5는 통화 등 비즈니스 용어 번호로 식별됨)를 정의하는 유럽 표준인 EN 16931 의미론적 모델을 따릅니다. 따라서 EN 16931 검증은 두 가지 개별 계층에서 수행됩니다. XML 스키마 검증은 문서가 올바른 요소 이름을 가진 유효한 CII 형식인지 확인합니다. Schematron 비즈니스 규칙은 콘텐츠의 정합성을 검증합니다. 즉, BR-CO-15가 성립하여 송장 총액이 실제로 각 라인의 순 금액 합계에 부가세를 더한 값과 일치하는지, 선언된 프로필에 대해 필수 용어가 존재하는지 검사합니다. 스키마 검증을 통과하더라도 비즈니스 규칙상 무효한 송장일 수 있으므로 비즈니스 규칙 계층이 별도로 존재합니다
ZUGFeRD 2.5에 새로운 컨테이너가 필요하지 않은 이유
ZUGFeRD 2.5는 PDF 컨테이너 수준에서 변경 사항이 없습니다: 가이드라인 URN, XMP 스키마 및 버전 토큰은 ZUGFeRD 2.3 / Factur-X 1.0과 동일합니다. 이는 많은 개발자들을 놀라게 하는 사실이므로 규격 문서 내용을 직접 인용해 설명하겠습니다. Factur-X 1.09 사양은 PDF/A 확장 스키마의 URI에 명시된 버전 번호가 XML 데이터 사양의 버전 번호와 관련이 없으며, Factur-X 송장 인스턴스의 버전 관리는 XMP fx:Version 및 factur-x.xml의 BT-24 모두에서 1.0으로 계속 유지된다고 기술하고 있습니다. 공식 ZUGFeRD 2.5 샘플 데이터셋도 이를 확인해 줍니다: 모든 샘플은 factur-x.xml을 1.0의 fx:Version과 함께 urn:factur-x.eu:1p0 가이드라인 URN 아래에 임베드합니다. 2.5 버전에서 실제로 추가된 내용은 XML 데이터 모델 내부(하위 송장 라인 및 배치 식별자와 같은 새로운 요소)에 존재하며, 이는 여러분의 애플리케이션 비즈니스 레이어가 생성하는 부분이지 PDF 라이브러리가 관리하는 컨테이너 레이어의 변경 사항이 아닙니다
HotPDF는 이 규격을 직접 지원합니다. AddFacturXAssociatedFile은 Version 인수를 수용하고 XMP를 작성하기 전에 HPDFFacturXNormalizeVersion을 통해 이를 정규화하므로, 호출자가 2p5 별칭을 전달하더라도 검증기가 수락하지 않을 임의의 2p5 XMP 버전을 생성하는 대신 스펙을 준수하는 토큰을 안정적으로 내보냅니다. 감지 도우미 모듈도 읽기 시 2p5를 동등한 값으로 처리하므로 양방향 처리가 대칭을 유지합니다. 만약 어떤 라이브러리나 도구가 특별한 ZUGFeRD 2.5 전용 컨테이너를 작성한다고 설명한다면, 사양서 내용 기준 그러한 구현체는 실체가 없는 것과 같습니다
Delphi에서 송장 XML 임베드하기
THotPDF.AddFacturXAssociatedFile은 단 한 번의 호출로 일반 PDF/A-3 생성 프로세스를 Factur-X 송장으로 전환합니다: XML 바이트 데이터를 연관 파일로 임베드하고, 카탈로그 /AF 배열 및 /Names /EmbeddedFiles 트리에 factur-x.xml을 등록하며, 이에 부합하는 Factur-X XMP 확장 메타데이터를 내보냅니다. 일반적인 HotPDF 캔버스 API를 사용하여 눈에 보이는 송장 페이지를 그리면 되며, 컨테이너 구성 작업은 BeginDoc과 EndDoc 사이의 단 한 줄의 코드로 완료됩니다
var
Pdf: THotPDF;
InvoiceXML, UBLXML: TBytes;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'invoice-2026-0042.pdf';
Pdf.PDFACompliance := '3B'; // PDF/A-3b container
Pdf.BeginDoc;
// embed the EN 16931 CII invoice XML as factur-x.xml
InvoiceXML := BuildInvoiceXML; // produced by your business layer
Pdf.AddFacturXAssociatedFile(InvoiceXML, 'EN 16931');
// optional: attach a UBL view as a supplementary representation
UBLXML := BuildUBLXML;
Pdf.AddUBLSupplementaryFile(UBLXML); // factur-xubl.xml, Alternative
// ... draw the visible invoice page here ...
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
수신된 PDF에서 Factur-X 송장을 감지하는 방법은 무엇입니까?
기본값은 사양을 따릅니다: 파일 이름은 factur-x.xml, 관계는 Alternative, 버전은 1.0입니다. AddUBLSupplementaryFile은 Factur-X 1.09 사양의 6.4절을 구현하여, 동일한 송장의 UBL 버전을 MIME 유형 application/xml 및 Alternative 관계를 가진 factur-xubl.xml이라는 이름의 두 번째 첨부 파일로 동반할 수 있도록 허용합니다. 순서가 매우 중요하며 HotPDF는 사양이 함축하는 제약 조건을 엄격히 준수합니다: UBL 파일은 보조 뷰일 뿐 결코 메인 송장 역할을 대체할 수 없으므로, 반드시 AddFacturXAssociatedFile이 CII 마스터를 등록한 후에 추가해야 합니다. 드로잉된 페이지 내용과 임베드된 XML 데이터는 동일한 송장 정보를 나타내야 함을 주의하십시오 — 페이지에 표시된 합계 금액과 XML 내부의 금액 데이터가 상이한 오류 상황은 바로 하이브리드 송장 제도가 방지하고자 하는 대표적인 사례입니다. OutputIntent 및 글꼴 임베딩을 포함한 이 워크플로의 PDF/A-3 기술 사양은 Delphi에서의 PDF/A, PDF/X 및 PDF/UA 검증 기사에서 심도 있게 다룹니다
수신된 PDF에서 Factur-X 송장을 감지하는 방법은 무엇입니까?
THotPDF.DetectFacturXInvoice는 의무 수신 규정을 처리합니다: 임의의 PDF를 로드하고 단 한 번의 호출로 그것이 하이브리드 송장인지, 어떤 프로필을 선언하는지, 어떤 첨부 파일을 포함하는지 파악합니다. 이 함수는 임베드된 XML 파일 이름, XMP-declared 문서 파일 이름 및 유형, 버전 토큰, 준수 수준, 가이드라인 URN 및 AFRelationship 값을 포함하는 THPDFFacturXInvoiceInfo 레코드를 반환합니다. 추가적인 두 필드는 보조 뷰를 보고합니다: factur-xubl.xml 첨부가 존재할 때 UBLFileName이 채워지고, EDIFACT 뷰가 동반될 때 EDIFACTFileName이 채워집니다 — 두 항목 모두 감지 판정에는 영향을 주지 않는데, 보조 표현은 기본 CII 송장 없이는 단독으로 존재할 수 없기 때문입니다
var
Reader: THotPDF;
Info: THPDFFacturXInvoiceInfo;
begin
Reader := THotPDF.Create(nil);
try
if Reader.LoadFromFile('incoming-invoice.pdf') <= 0 then
raise Exception.Create('No pages loaded.');
if Reader.DetectFacturXInvoice(Info) then
begin
Writeln('Invoice XML: ', string(Info.FileName));
Writeln('Conformance: ', string(Info.ConformanceLevel));
Writeln('Guideline URN: ', string(Info.GuidelineID));
Writeln('Relationship: ', string(Info.AFRelationship));
if Info.UBLFileName <> '' then
Writeln('UBL view: ', string(Info.UBLFileName));
end
else
Writeln('Not a Factur-X / ZUGFeRD hybrid invoice.');
finally
Reader.Free;
end;
end;
감지 모듈은 파일 이름만으로 유추하는 것이 아니라, 검증기와 마찬가지로 XMP 확장 스키마 및 연관 파일 레지스트리와 같은 동일한 규격 신호를 읽습니다. 동일하게 로드된 문서 객체는 검사 또는 조정을 위해 XMP 및 Info-사전 메타데이터도 노출하며, 이에 관한 워크플로는 로드된 PDF 문서의 메타데이터 편집 기사에서 설명합니다
비즈니스 규칙 대 스키마: EN 16931 검증의 의미는 무엇입니까?
HPDFEInvoiceValidator 유닛의 독립형 함수인 HPDFValidateEInvoice는 두 검증 계층을 순서대로 실행합니다: 첫째, ValidateFacturXInvoice를 통한 컨테이너 구조 검사, 둘째, 추출된 송장 XML에 대한 EN 16931 Schematron 비즈니스 규칙 평가입니다. HotPDF는 Lib/resources/Schematron/ 디렉터리 아래에 5가지 공식 Factur-X 1.09 규칙 파일(MINIMUM, BASIC WL, BASIC, EN 16931, EXTENDED)을 포함하여 제공하며, HPDFSchematronFileForProfile은 감지된 준수 수준에 맞는 파일을 선택하므로 EN 16931 송장은 자동으로 Factur-X_1.09_EN16931.sch를 기준으로 검사됩니다. 이 함수는 컨테이너가 유효하고 위반된 비즈니스 규칙이 없는 경우에만 True를 반환합니다
uses HPDFEInvoiceValidator;
var
Reader: THotPDF;
Report: THPDFEInvoiceValidationReport;
I: Integer;
begin
Reader := THotPDF.Create(nil);
try
Reader.LoadFromFile('incoming-invoice.pdf');
if HPDFValidateEInvoice(Reader, SchematronDir, Report) then
Writeln('Container and business rules: OK')
else
Writeln('Validation found issues.');
if Report.BusinessRulesEvaluated then
begin
Writeln(Report.BusinessSummary.Evaluated, ' rules evaluated, ',
Report.BusinessSummary.Skipped, ' skipped (XPath 2.0)');
for I := 0 to High(Report.BusinessRules) do
if (not Report.BusinessRules[I].Skipped) and
(Report.BusinessRules[I].Severity = stsError) then
Writeln(string(Report.BusinessRules[I].RuleID), ': ',
string(Report.BusinessRules[I].Message));
end;
finally
Reader.Free;
end;
end;
BusinessRules의 각 항목은 검증문 텍스트로부터 파싱한 규칙 식별자(BR-45, BR-CO-17 및 기타 EN 16931 명명 체계 요소를 포함함), 규칙 컨텍스트 XPath, 테스트 식, 그리고 Schematron 플래그 속성을 반영한 중요도를 포함합니다. 이를 통해 검증 보고서를 즉시 활용할 수 있습니다: 단순 성공/실패 여부가 아니라 정합성이 깨진 정확한 비즈니스 용어를 알려주므로, 고객이 송장 반려 이유를 문의할 때 지원 팀에 꼭 필요한 정보가 됩니다. 아카이브용 PDF에 대해 이미 구조화된 적합성 보고서를 생성하고 있는 개발 팀은 이 결과를 PDF 프리플라이트 보고서 자동화 기사에 소개된 것과 동일한 파이프라인에 통합할 수 있습니다
검증 엔진의 명확한 한계점
Schematron 엔진은 XPath 1.0을 평가하는 MSXML을 기반으로 빌드되었습니다. EN 16931 규칙 파일은 queryBinding="xslt2"를 선언하고 424개의 검증문을 포함하며, 대부분은 string-length 및 substring-after와 같은 XPath 1.0 함수만 사용하므로 네이티브로 실행됩니다. 극히 일부 규칙은 xs:decimal 형변환이나 exists()와 같은 XPath 2.0 구조에 의존합니다; HotPDF는 조용히 잘못 실행될 수 있는 위험을 피하기 위해 각 테스트 식에서 알려진 XPath 2.0 토큰을 미리 검색하고, 해당 규칙을 평가 대상에서 제외(Skipped)하고 중요도를 info로 표시합니다. 요약 레코드는 평가된 규칙 수와 건너뛴 규칙 수를 각각 보고하므로, 로그에는 항상 규칙 세트가 얼마나 실행되었는지 정확히 기록됩니다. MSXML 바인딩을 사용할 수 없는 Delphi 7의 경우, 이 유닛은 컨테이너 구조 판단에 영향을 주지 않고 엔진을 사용할 수 없음으로 보고하는 스텁(stub)을 컴파일합니다; 완전한 엔진 작동을 위해서는 Delphi XE2 이상 버전이 필요합니다
두 번째 제약 조건은 더욱 중요합니다. HPDFValidateEInvoice 검증에 성공(green)했다는 것은 컨테이너 구조가 부합하고 평가된 비즈니스 규칙 중에 실패한 항목이 없음을 의미할 뿐이며, 세무 상의 준수 여부(tax-compliance)를 보증하는 것은 아닙니다. 국가별 확장 규칙, 수신자별 전용 요건 및 송장 내용에 관한 법적 의무 사항들은 EN 16931 표준 규격 위에 존재하며 라이브러리 범위를 벗어납니다. 따라서 이 검증기를 구조가 손상된 송장의 발송을 방지하고 수신된 불합리한 송장을 필터링하는 게이트 역할로 취급하고, 인증 절차상 필요한 경우 프로덕션 파이프라인에 완전한 XPath 2.0 검증기를 실행하며, 세무 관련 사항은 세무 전문가와 상의해 처리하십시오. 여기에 소개된 임베딩, 감지 및 검증 API는 7가지 ZUGFeRD 및 Factur-X 프로필을 모두 다루는 완전한 전자 송장 예제와 함께 Delphi 및 C++Builder용 표준 HotPDF Component의 일부로 제공됩니다