PDF-FacturX

 view release on metacpan or  search on metacpan

t/12-embed-pdfa3.t  view on Meta::CPAN

use strict;
use warnings;
use utf8;
use Test::More;
use File::Temp qw(tempdir);
use File::Spec;

use PDF::FacturX::XML   qw(build_xml);
use PDF::FacturX::Embed qw(embed_xml_pdfa3);
use PDF::Builder;

# Skip si Ghostscript pas installé
my $gs_path = `which gs 2>/dev/null`;
chomp $gs_path;
plan skip_all => 'Ghostscript (gs) not installed' unless $gs_path && -x $gs_path;

plan tests => 9;

my $invoice = {
    number   => 'FA-2026-EMBED',
    date     => '2026-04-19',
    due_date => '2026-05-19',
    currency => 'EUR',
    seller   => { name => 'Acme SARL', siret => '12345678901234',
                  address_1 => '1 rue T', postcode => '75001', city => 'Paris', country => 'FR' },
    buyer    => { name => 'Client SAS', address_1 => '2 av B',
                  postcode => '69002', city => 'Lyon', country => 'FR' },
    lines    => [
        { name => 'Service', qty => 1, unit_price => 1000, vat_rate => 20, vat_cat => 'S' },
    ],
};

my $xml = build_xml($invoice, 'basic');

my $tmp     = tempdir(CLEANUP => 1);
my $pdf_in  = 't/data/source.pdf';
my $pdf_out = File::Spec->catfile($tmp, 'out.pdf');

ok(-r $pdf_in, "fixture PDF readable: $pdf_in") or BAIL_OUT("missing fixture");

my @warnings;
my ($ok, $msg) = embed_xml_pdfa3(
    pdf_in     => $pdf_in,
    xml        => $xml,
    pdf_out    => $pdf_out,
    profile    => 'basic',
    title      => 'Facture FA-2026-EMBED',
    author     => 'Acme SARL',
    on_warning => sub { push @warnings, $_[0] },
);
ok($ok, "embed_xml_pdfa3 OK: $msg") or diag("error: $msg");
ok(-s $pdf_out > 0, "PDF output non-empty");

# Inspection structurelle via PDF::Builder
my $pdf = PDF::Builder->open($pdf_out);
my $cat = $pdf->{catalog};

ok(ref $cat->{AF},             '/AF array present in Catalog');
ok(ref $cat->{OutputIntents},  '/OutputIntents present in Catalog');
ok(ref $cat->{Names},          '/Names present (EmbeddedFiles holder)');
ok(ref $cat->{Metadata},       '/Metadata stream present (XMP)');

# XMP Metadata stream content : doit contenir pdfaid + Factur-X
my $meta_obj = $cat->{Metadata}->realise;
my $xmp_bytes = $meta_obj->{' stream'};
like($xmp_bytes, qr{pdfaid:part>3</pdfaid:part}, 'XMP declares pdfaid:part 3');
like($xmp_bytes, qr{fx:ConformanceLevel>BASIC},   'XMP declares Factur-X profile BASIC');



( run in 0.494 second using v1.01-cache-2.11-cpan-71847e10f99 )