Teknik Makale

Delphi'de HotPDF ile ZUGFeRD ve Factur-X E-Faturaları

HotPDF; Delphi ve C++Builder'dan ZUGFeRD ve Factur-X elektronik faturalarını oluşturur, algılar ve doğrular. AddFacturXAssociatedFile, EN 16931 fatura XML'ini bir PDF/A-3 kapsayıcısına gömer, DetectFacturXInvoice gelen bir hibrit faturayı tanır ve HPDFValidateEInvoice gömülü XML'e karşı resmi EN 16931 Schematron iş kurallarını çalıştırır. Bu makale her üç adımı da ele almakta ve doğrulama motorunun nerede durduğu konusunda dürüst davranmaktadır

Bu özellik setinin arkasındaki baskı teknik değil, mevzuat kaynaklıdır. Almanya ve Fransa, yurt içi B2B işlemleri için zorunlu yapılandırılmış e-faturalandırmayı aşamalı olarak uygulamaya koyuyor ve her iki zorunluluk da aynı hibrit modelde birleşiyor: ERP'nizin halihazırda ürettiği PDF faturası, içinde makine tarafından okunabilir bir XML ikizi taşımalıdır. Bugün düz PDF faturaları düzenleyen bir Delphi muhasebe veya ERP uygulamasının Factur-X veya ZUGFeRD düzenlemeye başlamak için kesin bir son tarihi vardır ve iki ad arasındaki fark pazarlamanın öne sürdüğünden daha küçüktür — Factur-X ve ZUGFeRD, iki etiket altında yayınlanan aynı Fransız-Alman standardıdır

Bir PDF'i geçerli bir Factur-X faturası yapan nedir?

Geçerli bir Factur-X faturası, ilişkili bir dosya olarak tam olarak bir yapılandırılmış fatura XML'ini gömen, bunu belge kataloğundan bağlayan ve XMP uzantısı meta verilerinde bildiren bir PDF/A-3 dosyasıdır (ISO 19005-3). Üç katmanın uyuşması gerekir. İlk olarak, kapsayıcı, PDF/A-1 ve PDF/A-2'nin aksine herhangi bir türdeki gömülü dosyalara izin veren arşivsel profil olan PDF/A-3'e uymalıdır. İkinci olarak, standart profiller için factur-x.xml veya Alman XRechnung varyantı için xrechnung.xml olarak adlandırılan fatura XML'i, kataloğun /AF dizisine ve /Names /EmbeddedFiles ağacına kaydedilmelidir; ekte ne olduğunu belirten bir AFRelationship girişi bulunmalıdır: Alternative, XML'in görünür faturanın eşdeğer bir temsili olduğu anlamına gelir ki bu da çoğu profilin gerektirdiği semantiktir. Üçüncü olarak, Factur-X XMP uzantı şeması, gömülü dosyayı, onun uygunluk düzeyini ve belge türünü adlandırmalıdır; böylece alıcı bir sistem XML'i hiç ayrıştırmadan faturayı sınıflandırabilir

XML yükünün kendisi, temel faturayı tanımlayan Avrupa Normu olan EN 16931 anlamsal modelini (semantic model) takip eder: Alıcı, satıcı, satır öğeleri, vergi dökümü, ödenecek tutar; her biri bir iş terimi numarasına (fatura numarası için BT-1, para birimi için BT-5 vb.) sahiptir. Bu nedenle EN 16931 doğrulaması iki farklı katmanda gerçekleşir. XML şeması doğrulaması, belgenin doğru öğe adlarıyla düzgün biçimlendirilmiş CII olduğunu kontrol eder. Schematron iş kurallararı ise içeriğin tutarlı olup olmadığını denetler — BR-CO-15'in geçerli olduğunu ve fatura toplamının aslında satır net tutarlarının toplamı artı KDV'ye eşit olduğunu, beyan edilen profil için zorunlu terimlerin mevcut olduğunu doğrular. Bir dosya şema doğrulamasını geçebilir ve yine de geçersiz bir fatura olabilir, iş kuralı katmanının var olmasının nedeni tam olarak budur

ZUGFeRD 2.5 neden yeni bir kapsayıcıya (container) ihtiyaç duymaz?

ZUGFeRD 2.5, PDF kapsayıcı düzeyinde hiçbir şeyi değiştirmez: Kılavuz URN'leri, XMP şeması ve sürüm belirteci (version token) ZUGFeRD 2.3 / Factur-X 1.0 ile aynıdır. Bu, çoğu uygulayıcıyı şaşırtır, bu nedenle kaynağı alıntılamaya değer. Factur-X 1.09 spesifikasyonu, PDF/A uzantı şemasının URI'sindeki sürüm numarasının XML veri spesifikasyonunun sürüm numarasıyla ilişkili olmadığını ve Factur-X fatura örneklerinin sürümlemesinin hem XMP'deki fx:Version alanında hem de factur-x.xml dosyasının BT-24 alanında 1.0 olarak kaldığını belirtir. Resmi ZUGFeRD 2.5 örnek kümesi bunu doğrulamaktadır: Her örnek, fx:Version değeri 1.0 olan bir urn:factur-x.eu:1p0 kılavuz URN'i altında factur-x.xml gömer. 2.5'in gerçekte eklediği şey XML veri modelinin içinde yaşar — alt fatura satırları ve parti tanımlayıcıları gibi yeni öğeler — ki bu da PDF kütüphanesinin yönettiği kapsayıcı katmanı değil, uygulamanızın oluşturduğu iş katmanıdır

Delphi'den Fatura XML'ini Gömme

THotPDF.AddFacturXAssociatedFile, tek bir çağrı ile normal bir PDF/A-3 oluşturma işlemini bir Factur-X faturasına dönüştürür: XML baytlarını ilişkili bir dosya olarak gömer, factur-x.xml dosyasını kataloğun /AF dizisine ve /Names /EmbeddedFiles ağacına kaydeder ve eşleşen Factur-X XMP uzantı meta verilerini yayar. İnsan tarafından okunabilir fatura sayfasını normal HotPDF tuval (canvas) API'si ile çizersiniz; kapsayıcı işi BeginDoc ve EndDoc arasında tek bir satırdır

var
  Pdf: THotPDF;
  InvoiceXML, UBLXML: TBytes;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'invoice-2026-0042.pdf';
    Pdf.PDFACompliance := '3B';            // PDF/A-3b kapsayıcısı
    Pdf.BeginDoc;
    // EN 16931 CII fatura XML'ini factur-x.xml olarak gömün
    InvoiceXML := BuildInvoiceXML;         // iş katmanınız tarafından üretildi
    Pdf.AddFacturXAssociatedFile(InvoiceXML, 'EN 16931');
    // isteğe bağlı: ek bir temsil olarak bir UBL görünümü ekleyin
    UBLXML := BuildUBLXML;
    Pdf.AddUBLSupplementaryFile(UBLXML);   // factur-xubl.xml, Alternative
    // ... görünür fatura sayfasını burada çizin ...
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Varsayılanlar spesifikasyonu takip eder: Dosya adı factur-x.xml, ilişki Alternative, sürüm 1.0. AddUBLSupplementaryFile, aynı faturanın bir UBL temsilinin, application/xml MIME türü ve Alternative ilişkisiyle factur-xubl.xml adında ikinci bir ek olarak eşlik etmesine izin veren Factur-X 1.09 spesifikasyonunun 6.4 bölümünü uygular. Burada sıra önemlidir ve HotPDF spesifikasyonun ima ettiği kısıtlamayı uygular: UBL dosyası ek bir görünümdür, asla birincil fatura değildir, bu nedenle AddFacturXAssociatedFile CII ana belgesini kaydettikten sonra eklenmelidir. Çizilen sayfa ile gömülü XML'in aynı faturayı belirtmesi gerektiğini unutmayın — bir toplamı görüntüleyen ve bir diğerini kodlayan bir PDF, hibrit faturalandırmanın önlemek için tasarlandığı hata modunun tam kendisidir. Bu iş akışının PDF/A-3 tarafı, OutputIntent ve yazı tipi gömme dahil olmak üzere, Delphi'de PDF/A, PDF/X ve PDF/UA doğrulaması hakkındaki eşlik eden makalede daha derinlemesine ele alınmıştır

Gelen bir PDF'te Factur-X faturasını nasıl algılarsınız?

THotPDF.DetectFacturXInvoice, zorunluluğun alıcı tarafına yanıt verir: Herhangi bir PDF'i yükleyin ve tek bir çağrıda bunun bir hibrit fatura olup olmadığını, hangi profili beyan ettiğini ve hangi ekleri taşıdığını öğrenin. İşev; gömülü XML dosya adını, XMP tarafından beyan edilen belge dosya adını ve türünü, sürüm belirtecini, uygunluk düzeyini, kılavuz URN'sini ve AFRelationship değerini içeren bir THPDFFacturXInvoiceInfo kaydı döndürür. Diğer iki alan ek görünümleri bildirir: Bir factur-xubl.xml eki mevcut olduğunda UBLFileName alanı ve bir EDIFACT görünümü eşlik ettiğinde EDIFACTFileName alanı doldurulur — bunların hiçbiri algılama kararını etkilemez, çünkü ek bir temsil birincil CII faturası olmadan var olamaz

var
  Reader: THotPDF;
  Info: THPDFFacturXInvoiceInfo;
begin
  Reader := THotPDF.Create(nil);
  try
    if Reader.LoadFromFile('incoming-invoice.pdf') <= 0 then
      raise Exception.Create('Hiçbir sayfa yüklenemedi.');
    if Reader.DetectFacturXInvoice(Info) then
    begin
      Writeln('Fatura XML:     ', string(Info.FileName));
      Writeln('Uygunluk:       ', string(Info.ConformanceLevel));
      Writeln('Kılavuz URN:    ', string(Info.GuidelineID));
      Writeln('İlişki:         ', string(Info.AFRelationship));
      if Info.UBLFileName <> '' then
        Writeln('UBL görünümü:   ', string(Info.UBLFileName));
    end
    else
      Writeln('Bir Factur-X / ZUGFeRD hibrit faturası değil.');
  finally
    Reader.Free;
  end;
end;

Algılama, yalnızca dosya adlarından tahmin etmek yerine, uyumlu bir doğrulayıcının okuduğu aynı sinyalleri — XMP uzantı şemasını ve ilişkili dosya kaydını — okur. Aynı yüklü belge nesnesi, yüklü PDF belgelerindeki meta verileri düzenleme hakkındaki makalede açıklanan iş akışıyla, inceleme veya düzeltme için XMP ve Info-sözlük meta verilerini de ortaya koyar

İş kuralları mı yoksa şema mı: EN 16931 doğrulaması ne anlama gelir?

HPDFEInvoiceValidator ünitesinde bağımsız bir işlev olan HPDFValidateEInvoice, her iki doğrulama katmanını sırayla çalıştırır: Önce ValidateFacturXInvoice aracılığıyla kapsayıcı yapısı kontrolü, ardından ayıklanan fatura XML'ine karşı EN 16931 Schematron iş kuralları. HotPDF, beş resmi Factur-X 1.09 kural dosyasını (MINIMUM, BASIC WL, BASIC, EN 16931 ve EXTENDED) Lib/resources/Schematron/ altında gönderir ve HPDFSchematronFileForProfile algılanan uygunluk seviyesiyle eşleşen dosyayı seçer; böylece bir EN 16931 faturası Factur-X_1.09_EN16931.sch dosyasına karşı otomatik olarak kontrol edilir. İşlev, yalnızca kapsayıcı geçerli olduğunda ve hiçbir iş kuralı tetiklenmediğinde True değerini döndürür

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('Kapsayıcı ve iş kuralları: Tamam')
    else
      Writeln('Doğrulamada sorunlar bulundu.');
    if Report.BusinessRulesEvaluated then
    begin
      Writeln(Report.BusinessSummary.Evaluated, ' kural değerlendirildi, ',
        Report.BusinessSummary.Skipped, ' atlandı (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 dizisindeki her giriş, iddia metninden ayrıştırılan kural tanımlayıcısını (BR-45, BR-CO-17 ve EN 16931 adlandırma şemasının geri kalanı), kural bağlamı XPath'ini, test ifadesini ve Schematron bayrak özniteliğini yansıtan önem derecesini taşır. Bu, raporu uygulanabilir kılar: Yalın bir geçti/kaldı sonucu yerine, tutarsız olan tam iş terimini alırsınız; bu da bir müşteri faturanın neden reddedildiğini sorduğunda destek ekibinizin ihtiyaç duyduğu şeydir. Arşivsel PDF'ler için halihazırda yapılandırılmış uygunluk raporları oluşturan ekipler, bu sonuçları PDF ön uçuş raporlarını otomatikleştirmeyle ilgili makalede açıklanan süreç hattına dahil edebilirler

Doğrulayıcının dürüstçe durduğu yer

Schematron motoru, XPath 1.0'ı değerlendiren MSXML üzerine inşa edilmiştir. EN 16931 kural dosyası queryBinding="xslt2" bildirir ve 424 iddia taşır; bunların çoğu yalnızca yerel olarak çalışan string-length ve substring-after gibi XPath 1.0 işlevlerini kullanır. Az bir kısmı ise xs:decimal dönüştürmeleri veya exists() gibi XPath 2.0 yapılarına dayanır; HotPDF, sessizce yanlış sonuçlanacak bir değerlendirme girişiminde bulunmak yerine, her test ifadesini bilinen XPath 2.0 belirteçleri için önceden tarar ve bu kuralları bilgi (info) önem derecesiyle Skipped (Atlandı) olarak işaretler. Özet kaydı, değerlendirilen ve atlanan sayıları ayrı ayrı rapor eder, böylece günlüğünüz her zaman kural setinin tam olarak ne kadarının çalıştırıldığını belirtir. MSXML bağlamalarının bulunmadığı Delphi 7'de, ünite, kapsayıcı kararını bozmadan motorun kullanılamaz olduğunu bildiren bir taslak (stub) derler; tam motor Delphi XE2 veya sonrasını gerektirir

İkinci sınır daha da önemlidir. HPDFValidateEInvoice işlevinden alınan yeşil sonuç, kapsayıcı yapısının uygun olduğu ve değerlendirilen hiçbir iş kuralının tetiklenmediği anlamına gelir — vergi uyumluluğu onayı değildir. Ulusal uzantı kuralları, alıcıya özel gereksinimler ve fatura içeriğine ilişkin yasal yükümlülükler EN 16931 çekirdeğinin üzerinde ve herhangi bir kütüphanenin dışındadır. Doğrulayıcıyı, yapısal olarak bozuk faturaları giden kutunuzdan uzak tutan ve gelen kutunuzdaki tutarsız olanları işaretleyen kapı olarak ele alın; sertifikasyon gerektirdiğinde sürüm süreç hattınızda tam bir XPath 2.0 doğrulayıcı çalıştırın ve vergi danışmanlarınızın uyumluluk konusunu üstlenmesine izin verin. Burada gösterilen gömme, algılama ve doğrulama API'leri, yedi ZUGFeRD ve Factur-X profilinin tamamını kapsayan eksiksiz bir E-Fatura örneğiyle birlikte, Delphi ve C++Builder için HotPDF Bileşeni'nin bir parçasıdır