File Coverage

blib/lib/PDF/FacturX.pm
Criterion Covered Total %
statement 18 39 46.1
branch 0 12 0.0
condition 0 2 0.0
subroutine 6 7 85.7
pod 1 1 100.0
total 25 61 40.9


line stmt bran cond sub pod time code
1             package PDF::FacturX;
2 2     2   446293 use strict;
  2         4  
  2         82  
3 2     2   11 use warnings;
  2         4  
  2         157  
4 2     2   573 use utf8;
  2         330  
  2         14  
5 2     2   80 use Exporter 'import';
  2         5  
  2         115  
6              
7 2     2   1274 use PDF::FacturX::XML qw(build_xml validate_xml);
  2         9  
  2         205  
8 2     2   1396 use PDF::FacturX::Embed qw(embed_xml_pdfa3);
  2         12  
  2         1089  
9              
10             our $VERSION = '0.01';
11              
12             our @EXPORT_OK = qw(generate);
13              
14             ###############################################################################
15             # generate(%opts) — façade end-to-end :
16             # 1. Validate the invoice hash (fast, in-Perl, French error messages)
17             # 2. Build the Factur-X CrossIndustryInvoice XML for the requested profile
18             # 3. Validate the XML against the bundled official XSD (unless validate=>0)
19             # 4. Embed the XML into a PDF/A-3 envelope with proper XMP, AF, OutputIntent
20             #
21             # Returns (1, $info) on success or (0, $error) on failure. Never dies on
22             # expected error paths — die-on-error stays inside the lower-level modules
23             # only when called directly.
24             ###############################################################################
25             sub generate {
26 0     0 1   my (%opt) = @_;
27              
28 0           my $invoice = $opt{invoice};
29 0 0         return (0, 'invoice requis') unless ref $invoice eq 'HASH';
30              
31 0   0       my $profile = $opt{profile} || 'basic';
32 0 0         my $do_validate = exists $opt{validate} ? $opt{validate} : 1;
33              
34             # 1+2. Build XML (validation maison happens inside build_xml)
35 0           my $xml = eval { build_xml($invoice, $profile) };
  0            
36 0 0         if ($@) {
37 0           my $err = $@;
38 0           chomp $err;
39 0           return (0, "build_xml KO : $err");
40             }
41              
42             # 3. XSD validation (optional)
43 0 0         if ($do_validate) {
44 0           my ($xsd_ok, $xsd_msg) = validate_xml($xml, $profile);
45 0 0         return (0, "XSD validation KO : $xsd_msg") unless $xsd_ok;
46             }
47              
48             # 4. Embed into PDF/A-3
49 0           my ($ok, $msg) = eval {
50             embed_xml_pdfa3(
51             pdf_in => $opt{pdf_in},
52             pdf_out => $opt{pdf_out},
53             xml => $xml,
54             profile => $profile,
55             title => $opt{title},
56             author => $opt{author},
57             creator => $opt{creator},
58             tmp_dir => $opt{tmp_dir},
59             gs => $opt{gs},
60             icc_path => $opt{icc_path},
61             on_warning => $opt{on_warning},
62 0           );
63             };
64 0 0         if ($@) {
65 0           my $err = $@;
66 0           chomp $err;
67 0           return (0, "embed KO : $err");
68             }
69 0           return ($ok, $msg);
70             }
71              
72             1;
73              
74             __END__