Một hóa đơn Factur-X hay ZUGFeRD là hai tài liệu trong một tên tệp. Tài liệu bên ngoài là một container PDF/A-3 mà trình đọc lưu trữ phải chấp nhận trong mười năm tới. Tài liệu bên trong là một hóa đơn XML mà hệ thống kế toán của người mua phải phân tích cú pháp theo EN 16931. Sai lầm khiến các hóa đơn bị lỗi đi vào môi trường sản xuất là tin rằng làm đúng cái đầu tiên sẽ tự động cho ra cái thứ hai. Điều đó không đúng. Một tệp có thể là PDF/A-3 hoàn hảo nhưng vẫn chứa XML mà không cơ quan thuế nào chấp nhận, và nó cũng có thể chứa XML EN 16931 chuẩn mực trong một container không vượt qua xác thực lưu trữ. Hai lớp được xác thực bởi hai công cụ khác nhau, không biết gì về nhau, và một quy trình thực sự phải thỏa mãn cả hai
Hai bộ xác thực, hai câu hỏi khác nhau
veraPDF là triển khai tham chiếu cho PDF/A. Trỏ nó vào một hóa đơn và nó trả lời một câu hỏi: đây có phải là tệp PDF/A-3 tuân thủ không. Nó kiểm tra những gì ISO 19005-3 quan tâm. Mọi phông chữ có được nhúng không. Có OutputIntent không. Siêu dữ liệu XMP có khai báo đúng phần và mức tuân thủ không. Đối với hóa đơn điện tử, nó cũng kiểm tra cấu trúc tệp liên kết mà PDF/A-3 yêu cầu, vì XML đi kèm như một tệp nhúng với /AFRelationship và một mục trong mảng /AF của danh mục tài liệu. veraPDF không nói gì về việc tổng hóa đơn có đúng không, vì đó không phải nhiệm vụ của nó
Mustang là bộ xác thực mã nguồn mở từ dự án Mustangproject. Nó đặt câu hỏi trực giao: XML nhúng có phải là hóa đơn hợp lệ không. Nó chạy XML đối chiếu với lược đồ của hồ sơ đã khai báo, sau đó áp dụng các quy tắc kinh doanh EN 16931 và các bộ quy tắc theo quốc gia xếp chồng lên, trong đó có CIUS của XRechnung. Nó kiểm tra xem mã định danh VAT của người bán có hiện diện khi tổng số tiền yêu cầu không, các khoản giảm giá và phụ phí có khớp với tổng tài liệu không, URN hồ sơ trong XML có khớp với những gì tệp tuyên bố hay không. Mustang không quan tâm đến việc PDF xung quanh có nhúng phông chữ không, vì đó là công việc của veraPDF
Không công cụ nào là tập hợp cha của cái kia. veraPDF thông qua một container có cấu trúc hoàn hảo xung quanh XML vô nghĩa. Mustang thông qua XML hoàn hảo được bao bọc trong một container thiếu OutputIntent. Mỗi công cụ chỉ bắt đúng loại lỗi mà cái kia không nhìn thấy, đó là lý do duy nhất tại sao một bộ xác thực nghiêm túc chạy cả hai và chỉ coi một tệp là có thể gửi khi cả hai đồng ý
Ma trận xác thực
Để chứng minh thư viện tạo ra các tệp vượt qua cả hai cổng, bộ kiểm thử xây dựng một ma trận. Sáu hồ sơ hóa đơn bao quát phạm vi mà một quy trình châu Âu gặp phải trong thực tế: Factur-X EN 16931, Factur-X BASIC, biến thể Factur-X EXTENDED cho B2B Pháp, XRechnung 3.0, ZUGFeRD 1.0 COMFORT, và ZUGFeRD 2.0 BASIC. Mỗi hồ sơ được tạo ra đối chiếu với hai mức tuân thủ PDF/A, 3b và 3u, vì các yêu cầu mức B và mức U khác nhau về ánh xạ Unicode và một tệp vượt qua mức này có thể thất bại ở mức kia. Sáu hồ sơ nhân với hai mức là mười hai tệp, tất cả được xây dựng không đầu bởi cùng một đường dẫn mã mà mẫu GUI sử dụng, vì vậy các tệp được kiểm thử không phải được tinh chỉnh thủ công cho bài kiểm thử
Trình tạo ghi tất cả mười hai tệp và một script nạp từng tệp vào cả hai bộ xác thực. Trong lần chạy đầy đủ đầu tiên, veraPDF thông qua tất cả mười hai tệp. Cấu trúc container hoàn toàn chính xác: các tệp liên kết đã được đăng ký, XMP tuân thủ đã được khai báo, output intent đã có mặt. Mustang thông qua tám tệp. Bốn hóa đơn là tệp PDF/A-3 có cấu trúc hợp lệ nhưng mang XML mà bộ xác thực quy tắc kinh doanh từ chối, đây chính xác là sự phân tách mà phương pháp hai công cụ tồn tại để phát hiện. Nếu bộ kiểm thử chỉ tin vào veraPDF, bốn tệp đó sẽ trông như đã hoàn thành
Hai bản sửa lỗi đã lấp đầy khoảng cách
Bốn lỗi Mustang xuất phát từ hai nguyên nhân riêng biệt, và cách sửa của mỗi cái là chi tiết đáng biết trước khi bạn tự tạo các hồ sơ này
Nguyên nhân đầu tiên là hồ sơ Factur-X EXTENDED France B2B. Trình tạo ban đầu truyền nhãn nội bộ làm mức tuân thủ và URN nội bộ làm hướng dẫn, và Mustang từ chối tệp với lỗi giá trị tuân thủ không hợp lệ theo sau bởi lỗi loại hồ sơ không được hỗ trợ. Lý do là trường XMP fx:ConformanceLevel không phải là ô văn bản tự do cho tên hồ sơ của riêng bạn. Factur-X định nghĩa chính xác năm giá trị chuẩn cho nó: MINIMUM, BASIC WL, BASIC, EN 16931, và EXTENDED. Một hóa đơn B2B dành riêng cho Pháp vẫn là tài liệu hồ sơ EXTENDED theo siêu dữ liệu XMP. Đặc điểm Pháp của hóa đơn không được thể hiện bằng cách đặt ra giá trị tuân thủ thứ sáu. Nó được thể hiện bằng mã quốc gia, FR, và bằng định danh hướng dẫn bên trong XML, phải mang tiền tố urn:cen.eu:en16931:2017#conformant# đánh dấu CIUS tuân thủ EN 16931. Truyền giá trị EXTENDED chuẩn với FR làm mã quốc gia và URN hướng dẫn đúng đã làm cho tệp tuân thủ
Trong API thư viện, đó là lời gọi đến AddFacturXAssociatedFileFromString với mức tuân thủ, quốc gia và hướng dẫn được căn chỉnh. Tham số mức tuân thủ mang token chuẩn, tham số mã quốc gia mang FR, và URN hướng dẫn nằm trong các byte XML bạn truyền vào
var
FileID: Integer;
begin
PDF.SetPDFAMode(5); // PDF/A-3b
PDF.NewDocument;
// ... draw the human-readable invoice page ...
// ExtendedXML carries an EN 16931 guideline URN of the form
// urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
FileID := PDF.AddFacturXAssociatedFileFromString(
ExtendedXML,
'EXTENDED', // standard fx:ConformanceLevel, not an internal label
'factur-x.xml',
'Factur-X EXTENDED invoice',
'Alternative', // /AFRelationship
'1.0',
'FR'); // France B2B marked by country code, not by conformance
if FileID = 0 then
raise Exception.Create('Factur-X attachment rejected');
PDF.SaveToFile('02_Factur-X-EXTENDED-FR_PDFA-3b.pdf');
end;
Nguyên nhân thứ hai là hồ sơ ZUGFeRD 1.0 COMFORT, và nó không liên quan gì đến siêu dữ liệu. ZUGFeRD 1.0 được xác thực đối chiếu với XSD :1p0, vốn nghiêm ngặt hơn về cardinality so với những gì tóm tắt văn xuôi gợi ý. XSD yêu cầu tóm tắt thanh toán quyết toán tiêu đề, ram:SpecifiedTradeSettlementMonetarySummation, phải chứa ram:ChargeTotalAmount và ram:AllowanceTotalAmount mỗi cái chính xác một lần. XML được tạo ra đã bỏ qua cả hai, vì vậy Mustang báo cáo rằng các phần tử phải xuất hiện đúng một lần. Chúng không phải là tùy chọn khi lược đồ nói minOccurs là một. Phát ra cả hai theo thứ tự XSD, ngay sau ram:LineTotalAmount, với giá trị 0.00 khi không có phụ phí hay giảm giá, đã thỏa mãn lược đồ. Số không là phần tử hiện diện; phần tử vắng mặt là vi phạm lược đồ. Với hai bản sửa lỗi đó, ma trận đã đạt mười hai trên mười hai với Mustang trong khi vẫn đạt mười hai trên mười hai với veraPDF
Các trường XRechnung chuyển đổi trạng thái không hợp lệ thành hợp lệ
XRechnung xứng đáng có ghi chú riêng vì CIUS của Đức thêm các quy tắc kinh doanh vắng mặt trong bộ EN 16931 cơ sở, và chúng thất bại theo cách trông như không có gì sai với tài liệu khi nhìn sơ qua. Hai trong số chúng liên quan đến địa chỉ điện tử. BT-34 là địa chỉ điện tử của người bán và BT-49 là địa chỉ điện tử của người mua, các điểm định tuyến mà cổng thông tin khu vực công của Đức sử dụng để phân phối và xác nhận hóa đơn. Mô hình EN 16931 cơ sở coi chúng là tùy chọn. XRechnung thì không. Bỏ qua một trong hai và hóa đơn hợp lệ về cấu trúc, hợp lệ về lược đồ, và bị từ chối
Cái thứ ba là quy tắc BR-DE-6, yêu cầu số điện thoại liên hệ của người bán phải có mặt. Đây là loại trường mà nhà phát triển bỏ qua vì nó có vẻ là trình bày hơn là dữ liệu, và sự vắng mặt của nó tạo ra lỗi xác thực trỏ vào nhóm liên hệ người bán hơn là bất cứ điều gì rõ ràng còn thiếu. Cung cấp BT-34, BT-49 và số điện thoại người bán là những gì chuyển đổi tệp XRechnung từ không hợp lệ sang hợp lệ theo Mustang, và không điều nào trong số đó thay đổi bất cứ điều gì veraPDF thấy, vì tất cả ba đều nằm trong XML
Kết nối đầu ra thư viện với bộ xác thực
Điểm kiến trúc đằng sau bộ kiểm thử khái quát hóa cho bất kỳ hệ thống kinh doanh nào. Thư viện PDF ghi một container tuân thủ và nhúng XML. Nó không nên, và không nên cố gắng, trở thành cơ quan quyền lực về quy tắc kinh doanh EN 16931. ValidateFacturXInvoice trong thư viện kiểm tra tính nhất quán của container, rằng mảng /AF trong catalog, cây tên tệp nhúng, DocumentFileName XMP, hồ sơ, hướng dẫn và /AFRelationship đều đồng ý, nhưng nó không xác thực mã thuế hay đối chiếu số tiền. Phân công lao động đúng đắn là để hệ thống kinh doanh trích xuất XML và giao nó cho bộ xác thực hóa đơn chuyên dụng, chính xác như bộ kiểm thử giao nó cho Mustang
Đọc tệp trở lại cho bạn biết những gì thực sự được ghi. DetectFacturXInvoice báo cáo xem hóa đơn có được nhận ra hay không, và GetFacturXInvoiceInfo đọc các trường siêu dữ liệu theo thẻ: thẻ 1 là tên tệp nhúng, thẻ 2 là DocumentFileName XMP, thẻ 5 là mức tuân thủ, thẻ 6 là định danh hướng dẫn, và thẻ 7 là /AFRelationship. Xác nhận rằng mức tuân thủ bạn đọc lại là token chuẩn chứ không phải nhãn nội bộ là cách rẻ nhất để bắt lỗi EXTENDED trước khi tệp rời khỏi bản dựng của bạn
function ExtractAndInspect(const PdfPath: string): AnsiString;
var
Profile, Guideline: WideString;
begin
Result := '';
PDF.LoadFromFile(PdfPath);
if PDF.DetectFacturXInvoice = 1 then
begin
Profile := PDF.GetFacturXInvoiceInfo(5); // fx:ConformanceLevel
Guideline := PDF.GetFacturXInvoiceInfo(6); // XML guideline ID
Writeln('Profile: ', Profile);
Writeln('Guideline: ', Guideline);
// Hand the raw XML to a dedicated EN 16931 / Mustang validator.
Result := PDF.ExtractFacturXXMLToString;
end;
end;
ExtractFacturXXMLToString trả về các byte XML thô dưới dạng AnsiString, sẵn sàng để ghi vào tệp hoặc truyền vào tiến trình xác thực. Trong bộ kiểm thử, mục tiêu đó là Mustang, được gọi thông qua jar dòng lệnh của nó, với veraPDF chạy trong cùng một lần qua cùng một tệp. Cấu trúc nhỏ gọn: trình tạo console, EInvoiceValidation.dpr, ghi mười hai tệp bằng mô hình hóa đơn chia sẻ từ mẫu, và một script, run-validation.ps1, chạy cả hai bộ xác thực trên thư mục đầu ra và in bảng thành công và thất bại. Cùng hình dạng hai bước đó, tạo bằng thư viện và xác minh bằng bộ xác thực bên ngoài, là những gì công việc tích hợp liên tục nên chạy trên mỗi thay đổi đối với việc tạo hóa đơn, vì cách duy nhất để biết một tệp thỏa mãn cả hai lớp là hỏi cả hai công cụ
Nếu quy trình của bạn cũng phải chứng nhận container trước khi ký, phần preflighting của công việc này được đề cập trong hướng dẫn preflighting PDF/A và PDF/UA trong Delphi của chúng tôi, và luồng chứng nhận rồi ký rộng hơn được mô tả trong bàn làm việc tuân thủ và ký. Cả hai đều được xây dựng trên cùng đường dẫn tạo đi kèm như một phần của Delphi PDF Library cho Delphi và C++Builder, cùng với các API PDF/A, tệp liên kết và siêu dữ liệu được sử dụng ở đây