Revision 3818b392
Von Tamino Steinert vor 12 Monaten hinzugefügt
SL/Controller/ZUGFeRD.pm | ||
---|---|---|
12 | 12 |
use SL::SessionFile; |
13 | 13 |
|
14 | 14 |
use XML::LibXML; |
15 |
use List::Util qw(first); |
|
15 | 16 |
|
16 | 17 |
|
17 | 18 |
__PACKAGE__->run_before('check_auth'); |
... | ... | |
128 | 129 |
|
129 | 130 |
my %res; # result data structure returned by SL::ZUGFeRD->extract_from_{pdf,xml}() |
130 | 131 |
my $parser; # SL::XMLInvoice object created by SL::ZUGFeRD->extract_from_{pdf,xml}() |
131 |
my $dom; # DOM object for parsed XML data |
|
132 | 132 |
my $vendor; # SL::DB::Vendor object |
133 | 133 |
|
134 |
my $ibanmessage; # Message to display if vendor's database and invoice IBANs don't match up |
|
135 |
|
|
136 |
die t8("missing file for action import") unless $file; |
|
137 |
die t8("can only parse a pdf or xml file") unless $file =~ m/^%PDF|<\?xml/; |
|
134 |
die t8("missing file for action import") unless $file; |
|
135 |
die t8("can only parse a pdf or xml file") unless $file =~ m/^%PDF|<\?xml/; |
|
138 | 136 |
|
139 | 137 |
if ( $::form->{file} =~ m/^%PDF/ ) { |
140 | 138 |
%res = %{SL::ZUGFeRD->extract_from_pdf($file)}; |
... | ... | |
149 | 147 |
|
150 | 148 |
$parser = $res{'invoice_xml'}; |
151 | 149 |
|
152 |
# Shouldn't be neccessary with SL::XMLInvoice doing the heavy lifting, but |
|
153 |
# let's grab it, just in case. |
|
154 |
$dom = $parser->{dom}; |
|
155 |
|
|
156 | 150 |
my %metadata = %{$parser->metadata}; |
157 | 151 |
my @items = @{$parser->items}; |
158 | 152 |
|
153 |
my $notes = t8("ZUGFeRD Import. Type: #1", $metadata{'type'}); |
|
159 | 154 |
my $iban = $metadata{'iban'}; |
160 | 155 |
my $invnumber = $metadata{'invnumber'}; |
161 | 156 |
|
... | ... | |
175 | 170 |
|
176 | 171 |
# Check IBAN specified on bill matches the one we've got in |
177 | 172 |
# the database for this vendor. |
178 |
$ibanmessage = $iban ne $vendor->iban ? "Record IBAN $iban doesn't match vendor IBAN " . $vendor->iban : $iban if $iban; |
|
173 |
if ($iban) { |
|
174 |
$notes .= "\nIBAN: "; |
|
175 |
$notes .= $iban ne $vendor->iban ? |
|
176 |
t8("Record IBAN #1 doesn't match vendor IBAN #2", $iban, $vendor->iban) |
|
177 |
: $iban |
|
178 |
} |
|
179 | 179 |
|
180 | 180 |
# save the zugferd file to session file for reuse in ap.pl |
181 | 181 |
my $session_file = SL::SessionFile->new($file_name, mode => 'w'); |
... | ... | |
213 | 213 |
name => $metadata{'currency'}, |
214 | 214 |
); |
215 | 215 |
|
216 |
my $default_ap_amount_chart = SL::DB::Manager::Chart->find_by( |
|
217 |
id => $::instance_conf->get_expense_accno_id |
|
218 |
); |
|
219 |
# Fallback if there's no default AP amount chart configured |
|
220 |
$default_ap_amount_chart ||= SL::DB::Manager::Chart->find_by(charttype => 'A'); |
|
221 |
|
|
222 |
my $active_taxkey = $default_ap_amount_chart->taxkey_id; |
|
223 |
my $taxes = SL::DB::Manager::Tax->get_all( |
|
224 |
where => [ chart_categories => { |
|
225 |
like => '%' . $default_ap_amount_chart->category . '%' |
|
226 |
}], |
|
227 |
sort_by => 'taxkey, rate', |
|
228 |
); |
|
229 |
die t8( |
|
230 |
"No tax found for chart #1", $default_ap_amount_chart->displayable_name |
|
231 |
) unless scalar @{$taxes}; |
|
232 |
|
|
233 |
# parse items |
|
234 |
my $row = 0; |
|
235 |
my %item_form = (); |
|
236 |
foreach my $i (@items) { |
|
237 |
$row++; |
|
238 |
|
|
239 |
my %item = %{$i}; |
|
240 |
|
|
241 |
my $net_total = $::form->format_amount(\%::myconfig, $item{'subtotal'}, 2); |
|
242 |
|
|
243 |
my $tax_rate = $item{'tax_rate'}; |
|
244 |
$tax_rate /= 100 if $tax_rate > 1; # XML data is usually in percent |
|
245 |
|
|
246 |
my $tax = first { $tax_rate == $_->rate } @{ $taxes }; |
|
247 |
$tax //= first { $active_taxkey->tax_id == $_->id } @{ $taxes }; |
|
248 |
$tax //= $taxes->[0]; |
|
249 |
|
|
250 |
$item_form{"AP_amount_chart_id_${row}"} = $default_ap_amount_chart->id; |
|
251 |
$item_form{"previous_AP_amount_chart_id_${row}"} = $default_ap_amount_chart->id; |
|
252 |
$item_form{"amount_${row}"} = $net_total; |
|
253 |
$item_form{"taxchart_${row}"} = $tax->id . '--' . $tax->rate; |
|
254 |
} |
|
255 |
$item_form{rowcount} = $row; |
|
256 |
|
|
216 | 257 |
$self->redirect_to( |
217 |
controller => 'ap.pl', |
|
218 |
action => 'load_zugferd', |
|
219 |
'form_defaults.no_payment_bookings' => 0, |
|
220 |
'form_defaults.paid_1_suggestion' => $::form->format_amount(\%::myconfig, $metadata{'total'}, 2), |
|
221 |
'form_defaults.invnumber' => $invnumber, |
|
222 |
'form_defaults.AP_chart_id' => $ap_chart_id, |
|
223 |
'form_defaults.currency' => $currency->name, |
|
224 |
'form_defaults.duedate' => $metadata{'duedate'}, |
|
225 |
'form_defaults.transdate' => $metadata{'transdate'}, |
|
226 |
'form_defaults.notes' => "ZUGFeRD Import. Type: $metadata{'type'}\nIBAN: " . $ibanmessage, |
|
227 |
'form_defaults.taxincluded' => 0, |
|
228 |
'form_defaults.direct_debit' => $metadata{'direct_debit'}, |
|
229 |
'form_defaults.vendor' => $vendor->name, |
|
230 |
'form_defaults.vendor_id' => $vendor->id, |
|
231 |
'form_defaults.zugferd_session_file' => $file_name, |
|
258 |
controller => 'ap.pl', |
|
259 |
action => 'load_zugferd', |
|
260 |
no_payment_bookings => 0, |
|
261 |
paid_1_suggestion => $::form->format_amount(\%::myconfig, $metadata{'total'}, 2), |
|
262 |
invnumber => $invnumber, |
|
263 |
AP_chart_id => $ap_chart_id, |
|
264 |
currency => $currency->name, |
|
265 |
duedate => $metadata{'duedate'}, |
|
266 |
transdate => $metadata{'transdate'}, |
|
267 |
notes => $notes, |
|
268 |
taxincluded => 0, |
|
269 |
direct_debit => $metadata{'direct_debit'}, |
|
270 |
vendor => $vendor->name, |
|
271 |
vendor_id => $vendor->id, |
|
272 |
zugferd_session_file => $file_name, |
|
273 |
%item_form, |
|
232 | 274 |
); |
233 | 275 |
|
234 | 276 |
} |
Auch abrufbar als: Unified diff
ZUGFeRD: Verschiebe komplettes Parsen aus ap.pl nach S:C:ZUGFeRD