مقاله فنی

اعتبارسنجی صورتحساب‌های الکترونیکی: veraPDF و Mustang در Delphi

یک فاکتور Factur-X یا ZUGFeRD دو سند است که یک نام فایل را بر تن دارند. سند بیرونی یک کانتینر PDF/A-3 است که یک خواننده آرشیوی باید برای ده سال آینده آن را بپذیرد. سند داخلی یک فاکتور XML است که سیستم حسابداری خریدار باید آن را در برابر EN 16931 تجزیه کند. اشتباهی که فاکتورهای خراب را به مرحله تولید می‌فرستد این باور است که درست بودن اولین مورد، دومی را به صورت رایگان فراهم می‌کند. اینطور نیست. یک فایل می‌تواند یک PDF/A-3 بی‌نقص باشد و همچنان دارای XML باشد که هیچ اداره مالیاتی آن را قبول نکند، و می‌تواند دارای XML دقیقاً مطابق با استاندارد EN 16931 در داخل کانتینری باشد که در اعتبارسنجی آرشیوی شکست می‌خورد. این دو لایه توسط دو ابزار متفاوت که هیچ چیزی از یکدیگر نمی‌دانند تأیید می‌شوند و یک خط لوله واقعی باید هر دو را برآورده کند

دو اعتبارسنج، دو سوال متفاوت

veraPDF پیاده‌سازی مرجع برای PDF/A است. آن را روی یک فاکتور قرار دهید و به یک سوال پاسخ می‌دهد: آیا این یک فایل منطبق با PDF/A-3 است. مواردی را که ISO 19005-3 به آنها اهمیت می‌دهد بررسی می‌کند. آیا هر فونت تعبیه شده است. آیا OutputIntent وجود دارد. آیا اَبَرداده XMP بخش و سطح انطباق صحیح را اعلام می‌کند. برای یک صورتحساب الکترونیکی، لوله‌کشی فایل مرتبط را که PDF/A-3 به آن نیاز دارد نیز بررسی می‌کند، زیرا XML به عنوان یک فایل تعبیه‌شده با /AFRelationship و یک ورودی در آرایه /AF کاتالوگ سند همراه می‌شود. veraPDF هیچ چیزی در مورد اینکه آیا مجموع فاکتور جمع می‌شود یا خیر نمی‌گوید، زیرا این در حیطه وظایف آن نیست

Mustang اعتبارسنج منبع باز از پروژه Mustangproject است. این سوال متعامدی را می‌پرسد: آیا XML تعبیه شده یک فاکتور معتبر است. XML را در برابر طرحواره برای نمایه اعلام شده اجرا می‌کند و سپس قوانین تجاری EN 16931 و مجموعه‌های قوانین خاص کشور را که در بالای آن لایه‌بندی شده‌اند، از جمله CIUS مربوط به XRechnung، اعمال می‌کند. بررسی می‌کند که آیا شناسه مالیات بر ارزش افزوده فروشنده در زمانی که مجموع‌ها آن را ایجاب می‌کنند وجود دارد، آیا مقادیر کمک هزینه و هزینه با مجموع سند مطابقت دارند، و آیا URN نمایه در XML با آنچه فایل ادعا می‌کند مطابقت دارد. Mustang اهمیتی نمی‌دهد که آیا PDF اطراف فونت‌های خود را تعبیه می‌کند یا خیر، زیرا این کار veraPDF است

هیچ‌کدام از این دو ابزار مجموعه کلان دیگری نیست. veraPDF یک کانتینر از نظر ساختاری بی‌نقص در اطراف یک XML بی‌معنی را عبور می‌دهد. Mustang یک XML بی‌نقص پیچیده شده در یک کانتینر با یک OutputIntent گمشده را عبور می‌دهد. هر کدام دقیقاً کلاسی از نقص را می‌گیرند که دیگری نسبت به آن نابینا است، که این دلیل اصلی این است که یک مهار اعتبارسنجی جدی هر دو را اجرا می‌کند و یک فایل را فقط زمانی به عنوان قابل ارسال تلقی می‌کند که هر دو موافق باشند

ماتریس اعتبارسنجی

برای اثبات اینکه کتابخانه فایل‌هایی را تولید می‌کند که از هر دو دروازه عبور می‌کنند، مهار یک ماتریس می‌سازد. شش نمایه فاکتور محدوده‌ای را که یک خط لوله اروپایی در عمل با آن روبرو می‌شود پوشش می‌دهد: Factur-X EN 16931، Factur-X BASIC، نوع Factur-X EXTENDED France B2B، XRechnung 3.0، ZUGFeRD 1.0 COMFORT و ZUGFeRD 2.0 BASIC. هر نمایه در برابر دو سطح زیر-انطباق PDF/A یعنی 3b و 3u ایجاد می‌شود، زیرا الزامات سطح B و سطح U در نقشه یابی یونیکد از هم دور می‌شوند و فایلی که یکی را عبور می‌کند می‌تواند در دیگری شکست بخورد. شش نمایه ضرب در دو سطح برابر است با دوازده فایل، که تک تک آنها به صورت بدون سرور (headless) توسط همان مسیر کدی که نمونه رابط کاربری گرافیکی ارسال می‌کند ساخته شده‌اند، بنابراین مصنوعات تحت آزمایش برای آزمایش به صورت دستی تنظیم نشده‌اند

تولیدکننده تمام دوازده مورد را می‌نویسد و یک اسکریپت هر یک را به هر دو اعتبارسنج می‌دهد. در اولین اجرای کامل veraPDF هر دوازده مورد را عبور داد. لوله‌کشی کانتینر در همه موارد صحیح بود: فایل‌های مرتبط ثبت شده، انطباق XMP اعلام شده، مقاصد خروجی در جای خود. Mustang هشت مورد را عبور داد. چهار فاکتور فایل‌های از نظر ساختاری معتبر PDF/A-3 حامل XML بودند که اعتبارسنج قوانین تجاری آنها را رد کرد، که دقیقاً همان شکافی است که رویکرد دو ابزاری برای آشکار کردن آن وجود دارد. اگر مهار فقط به veraPDF اعتماد کرده بود، این چهار مورد تمام‌شده به نظر می‌رسیدند

دو اصلاحی که شکاف را پر کرد

چهار شکست Mustang ناشی از دو علت مجزا بود، و اصلاح هر یک جزئیاتی است که ارزش دانستن را دارد قبل از اینکه خودتان این نمایه‌ها را تولید کنید

اولین مورد نمایه Factur-X EXTENDED France B2B بود. تولیدکننده اصلی یک برچسب داخلی را به عنوان سطح انطباق و یک URN داخلی را به عنوان دستورالعمل ارسال کرد، و Mustang فایل را با خطای invalid-conformance-value و پس از آن خطای unsupported-profile-type رد کرد. دلیل آن این است که فیلد XMP fx:ConformanceLevel یک شکاف متن آزاد برای نام‌گذاری نمایه خودتان نیست. Factur-X دقیقاً پنج مقدار استاندارد برای آن تعریف می‌کند: MINIMUM، BASIC WL، BASIC، EN 16931 و EXTENDED. تا آنجا که به اَبَرداده XMP مربوط می‌شود، فاکتور B2B ویژه فرانسه هنوز یک سند با نمایه EXTENDED است. کاراکتر فرانسوی فاکتور با اختراع ششمین مقدار انطباق بیان نمی‌شود. با کد کشور FR، و توسط شناسه دستورالعمل داخل XML بیان می‌شود، که باید پیشوند urn:cen.eu:en16931:2017#conformant# را حمل کند که نشان‌دهنده یک CIUS منطبق با EN 16931 است. عبور دادن مقدار استاندارد EXTENDED با FR به عنوان کد کشور و URN دستورالعمل صحیح فایل را منطبق کرد

در API کتابخانه که یک فراخوانی به AddFacturXAssociatedFileFromString است با انطباق، کشور و دستورالعمل همسو شده. آرگومان سطح انطباق رمز استاندارد را حمل می‌کند، آرگومان کد کشور FR را حمل می‌کند، و URN دستورالعمل در بایت‌های XML که از آنها عبور می‌کنید قرار دارد

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;

علت دوم نمایه ZUGFeRD 1.0 COMFORT بود، و هیچ ربطی به اَبَرداده نداشت. ZUGFeRD 1.0 در برابر :1p0 XSD تأیید می‌شود، که در مورد اصلیت (cardinality) سختگیرانه‌تر از آن چیزی است که خلاصه‌های متنی پیشنهاد می‌کنند. XSD نیازمند این است که جمع‌آوری تسویه حساب سرصفحه، ram:SpecifiedTradeSettlementMonetarySummation، شامل ram:ChargeTotalAmount و ram:AllowanceTotalAmount هر کدام دقیقاً یک بار باشد. XML تولید شده هر دو را حذف کرد، بنابراین Mustang گزارش داد که عناصر باید دقیقاً یک بار رخ دهند. هنگامی که طرحواره می‌گوید minOccurs یک است اینها اختیاری نیستند. انتشار هر دو در ترتیب دنباله XSD، بلافاصله پس از ram:LineTotalAmount، با مقدار 0.00 در زمانی که هیچ هزینه یا کمک هزینه‌ای وجود ندارد، طرحواره را برآورده کرد. یک صفر یک عنصر حاضر است؛ یک عنصر غایب نقض طرحواره است. با قرار گرفتن آن دو اصلاح، ماتریس در Mustang به دوازده از دوازده رسید در حالی که دوازده از دوازده را در veraPDF حفظ کرد

فیلدهای XRechnung که نامعتبر را به معتبر برمی‌گردانند

XRechnung سزاوار یادداشت خاص خود است زیرا CIUS آلمانی آن قوانین تجاری را اضافه می‌کند که در مجموعه پایه EN 16931 وجود ندارند، و آنها به روش‌هایی شکست می‌خورند که در نگاه اول به نظر می‌رسد هیچ مشکلی در سند وجود ندارد. دو مورد از آنها مربوط به آدرس‌های الکترونیکی است. BT-34 آدرس الکترونیکی فروشنده است و BT-49 آدرس الکترونیکی خریدار است، نقاط پایانی مسیریابی که پورتال بخش عمومی آلمان برای تحویل و تأیید فاکتور از آنها استفاده می‌کند. مدل پایه EN 16931 آنها را به عنوان اختیاری در نظر می‌گیرد. XRechnung اینطور نیست. هر یک را حذف کنید و فاکتور خوش‌شکل، از نظر طرحواره معتبر و رد شده است

سومی قانون BR-DE-6 است، که ایجاب می‌کند شماره تلفن تماس فروشنده حضور داشته باشد. این از آن دسته فیلدهایی است که یک توسعه‌دهنده آن را رها می‌کند زیرا به جای داده، شبیه به ارائه است، و عدم وجود آن باعث شکست اعتبارسنجی می‌شود که به جای اشاره به چیز واضحی که گم شده است، به گروه تماس فروشنده اشاره می‌کند. ارائه BT-34، BT-49 و شماره تلفن فروشنده چیزی است که یک فایل XRechnung را از نامعتبر به معتبر در Mustang منتقل می‌کند، و هیچ یک از آن چیزی را که veraPDF می‌بیند تغییر نمی‌دهد، زیرا هر سه در XML زندگی می‌کنند

سیم‌کشی خروجی کتابخانه به یک اعتبارسنج

نکته معماری در پس مهار به هر سیستم تجاری تعمیم می‌یابد. کتابخانه PDF یک کانتینر منطبق می‌نویسد و XML را تعبیه می‌کند. این کتابخانه تلاش نمی‌کند و نباید تلاش کند که مرجع قواعد تجاری EN 16931 باشد. ValidateFacturXInvoice در کتابخانه سازگاری کانتینر را بررسی می‌کند، که آرایه /AF کاتالوگ، درخت نام فایل‌های تعبیه شده، DocumentFileName XMP، نمایه، دستورالعمل و /AFRelationship همگی با هم توافق دارند، اما کدهای مالیاتی را اعتبارسنجی نمی‌کند یا مبالغ را تطبیق نمی‌دهد. تقسیم کار درست این است که سیستم تجاری XML را استخراج کند و آن را به یک اعتبارسنج اختصاصی فاکتور تحویل دهد، دقیقاً همانطور که مهار آن را به Mustang تحویل می‌دهد

خواندن مجدد فایل به شما می‌گوید چه چیزی واقعاً نوشته شده است. DetectFacturXInvoice گزارش می‌دهد که آیا فاکتور شناسایی شده است یا خیر، و GetFacturXInvoiceInfo فیلدهای اَبَرداده را با برچسب می‌خواند: برچسب 1 نام فایل تعبیه شده است، برچسب 2 DocumentFileName XMP است، برچسب 5 سطح انطباق است، برچسب 6 شناسه دستورالعمل است، و برچسب 7 /AFRelationship است. تأیید اینکه سطح انطباقی که بازخوانی می‌کنید رمز استاندارد است و برچسب داخلی نیست، ارزان‌ترین راه برای گرفتن اشتباه EXTENDED قبل از خروج فایل از ساخت شما است

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 بایت‌های خام XML را به عنوان یک AnsiString برمی‌گرداند که آماده نوشتن روی فایل یا جریان دادن در یک فرآیند اعتبارسنجی است. در مهار تست، آن هدف Mustang است که از طریق jar خط فرمان آن فراخوانی می‌شود، و veraPDF در همان عبور روی همان فایل اجرا می‌شود. سیم‌کشی کوچک است: یک ژنراتور کنسول، EInvoiceValidation.dpr، دوازده فایل را با استفاده از مدل مشترک فاکتور از نمونه می‌نویسد، و یک اسکریپت، run-validation.ps1، هر دو اعتبارسنج را روی پوشه خروجی اجرا می‌کند و یک جدول قبولی و ردی چاپ می‌کند. همین شکل دو مرحله‌ای، تولید با کتابخانه و تأیید با اعتبارسنج‌های خارجی، چیزی است که یک کار یکپارچه‌سازی پیوسته باید با هر تغییری در تولید فاکتور اجرا کند، زیرا تنها راه برای دانستن اینکه فایلی هر دو لایه را برآورده می‌کند پرسیدن از هر دو ابزار است

اگر خط لوله شما همچنین باید کانتینر را قبل از امضا کردن تأیید کند، بخش پیش‌پرواز (preflight) این کار در گذر از پیش‌پرواز PDF/A و PDF/UA در Delphi ما پوشش داده شده است، و جریان گسترده‌تر تأیید-سپس-امضا در میز کار انطباق و امضا توضیح داده شده است. هر دو روی همان مسیر نسلی ساخته شده‌اند که به عنوان بخشی از کتابخانه PDF Delphi برای Delphi و C++Builder، در کنار PDF/A، فایل مرتبط و APIهای اَبَرداده استفاده شده در اینجا عرضه می‌شود