Revision e3338e4a
Von Tamino Steinert vor etwa 1 Jahr hinzugefügt
SL/Controller/EmailJournal.pm | ||
---|---|---|
4 | 4 |
|
5 | 5 |
use parent qw(SL::Controller::Base); |
6 | 6 |
|
7 |
use SL::ZUGFeRD; |
|
8 |
use SL::Controller::ZUGFeRD; |
|
7 | 9 |
use SL::Controller::Helper::GetModels; |
8 | 10 |
use SL::DB::Employee; |
9 | 11 |
use SL::DB::EmailJournal; |
... | ... | |
380 | 382 |
); |
381 | 383 |
} |
382 | 384 |
|
385 |
sub action_zugferd_import_with_attachment { |
|
386 |
my ($self) = @_; |
|
387 |
|
|
388 |
my $email_journal_id = $::form->{email_journal_id}; |
|
389 |
my $attachment_id = $::form->{attachment_id}; |
|
390 |
|
|
391 |
die "no 'email_journal_id' was given" unless $email_journal_id; |
|
392 |
die "no 'attachment_id' was given" unless $attachment_id; |
|
393 |
|
|
394 |
my $attachment = SL::DB::EmailJournalAttachment->new(id => $attachment_id)->load(); |
|
395 |
|
|
396 |
my $content = $attachment->content; # scalar ref |
|
397 |
|
|
398 |
die t8("can only parse a pdf or xml file") unless $content =~ m/^%PDF|<\?xml/; |
|
399 |
|
|
400 |
my %res; |
|
401 |
if ( $content =~ m/^%PDF/ ) { |
|
402 |
%res = %{SL::ZUGFeRD->extract_from_pdf($content)}; |
|
403 |
} else { |
|
404 |
%res = %{SL::ZUGFeRD->extract_from_xml($content)}; |
|
405 |
} |
|
406 |
|
|
407 |
unless ($res{'result'} == SL::ZUGFeRD::RES_OK()) { |
|
408 |
die(t8("Could not extract Factur-X/ZUGFeRD data, data and error message:") . " $res{'message'}"); |
|
409 |
} |
|
410 |
|
|
411 |
my $form_defaults = SL::Controller::ZUGFeRD->build_ap_transaction_form_defaults(\%res); |
|
412 |
$form_defaults->{email_journal_id} = $email_journal_id; |
|
413 |
$form_defaults->{email_attachment_id} = $attachment_id; |
|
414 |
$form_defaults->{callback} = $::form->{back_to}; |
|
415 |
|
|
416 |
flash_later('info', |
|
417 |
t8("The ZUGFeRD/Factur-X invoice '#1' has been loaded.", $attachment->name)); |
|
418 |
$self->redirect_to( |
|
419 |
controller => 'ap.pl', |
|
420 |
action => 'load_zugferd', |
|
421 |
form_defaults => $form_defaults, |
|
422 |
); |
|
423 |
} |
|
424 |
|
|
383 | 425 |
sub action_update_attachment_preview { |
384 | 426 |
my ($self) = @_; |
385 | 427 |
$::auth->assert('email_journal'); |
... | ... | |
390 | 432 |
id => $attachment_id, |
391 | 433 |
)->load if $attachment_id; |
392 | 434 |
|
435 |
$self->js->hide('#zugferd_import_div'); |
|
436 |
if ($attachment && $attachment->content =~ m/^%PDF|<\?xml/) { |
|
437 |
my $content = $attachment->content; |
|
438 |
my %res; |
|
439 |
if ( $content =~ m/^%PDF/ ) { |
|
440 |
%res = %{SL::ZUGFeRD->extract_from_pdf($content)}; |
|
441 |
} else { |
|
442 |
%res = %{SL::ZUGFeRD->extract_from_xml($content)}; |
|
443 |
} |
|
444 |
if ($res{'result'} == SL::ZUGFeRD::RES_OK()) { |
|
445 |
$self->js->show('#zugferd_import_div'); |
|
446 |
} |
|
447 |
} |
|
448 |
|
|
393 | 449 |
$self->js |
394 | 450 |
->replaceWith('#attachment_preview', |
395 | 451 |
SL::Presenter::EmailJournal::attachment_preview( |
SL/Controller/ZUGFeRD.pm | ||
---|---|---|
127 | 127 |
my $file = $::form->{file}; |
128 | 128 |
my $file_name = $::form->{file_name}; |
129 | 129 |
|
130 |
my %res; # result data structure returned by SL::ZUGFeRD->extract_from_{pdf,xml}() |
|
131 |
my $parser; # SL::XMLInvoice object created by SL::ZUGFeRD->extract_from_{pdf,xml}() |
|
132 |
my $vendor; # SL::DB::Vendor object |
|
130 |
my %res; # result data structure returned by SL::ZUGFeRD->extract_from_{pdf,xml}() |
|
133 | 131 |
|
134 | 132 |
die t8("missing file for action import") unless $file; |
135 | 133 |
die t8("can only parse a pdf or xml file") unless $file =~ m/^%PDF|<\?xml/; |
... | ... | |
145 | 143 |
die(t8("Could not extract Factur-X/ZUGFeRD data, data and error message:") . " $res{'message'}"); |
146 | 144 |
} |
147 | 145 |
|
148 |
$parser = $res{'invoice_xml'}; |
|
146 |
my $form_defaults = $self->build_ap_transaction_form_defaults(\%res); |
|
147 |
|
|
148 |
# save the zugferd file to session file for reuse in ap.pl |
|
149 |
my $session_file = SL::SessionFile->new($file_name, mode => 'w'); |
|
150 |
$session_file->fh->print($file); |
|
151 |
$session_file->fh->close; |
|
152 |
$form_defaults->{zugferd_session_file} = $file_name; |
|
153 |
|
|
154 |
$form_defaults->{callback} = $self->url_for(action => 'upload_zugferd'); |
|
155 |
|
|
156 |
$self->redirect_to( |
|
157 |
controller => 'ap.pl', |
|
158 |
action => 'load_zugferd', |
|
159 |
form_defaults => $form_defaults, |
|
160 |
); |
|
161 |
} |
|
162 |
|
|
163 |
sub build_ap_transaction_form_defaults { |
|
164 |
my ($self, $data) = @_; |
|
165 |
|
|
166 |
my $parser = $data->{'invoice_xml'}; |
|
149 | 167 |
|
150 | 168 |
my %metadata = %{$parser->metadata}; |
151 | 169 |
my @items = @{$parser->items}; |
... | ... | |
158 | 176 |
die t8("Cannot process this invoice: neither VAT ID nor tax ID present."); |
159 | 177 |
} |
160 | 178 |
|
161 |
$vendor = find_vendor($metadata{'ustid'}, $metadata{'taxnumber'}); |
|
179 |
my $vendor = find_vendor($metadata{'ustid'}, $metadata{'taxnumber'});
|
|
162 | 180 |
|
163 | 181 |
die t8("Vendor with VAT ID (#1) and/or tax ID (#2) not found. Please check if the vendor " . |
164 | 182 |
"#3 exists and whether it has the correct tax ID/VAT ID." , |
... | ... | |
170 | 188 |
|
171 | 189 |
# Check IBAN specified on bill matches the one we've got in |
172 | 190 |
# the database for this vendor. |
173 |
if ($iban) { |
|
174 |
$intnotes .= "\nIBAN: "; |
|
175 |
$intnotes .= $iban ne $vendor->iban ? |
|
176 |
t8("Record IBAN #1 doesn't match vendor IBAN #2", $iban, $vendor->iban) |
|
177 |
: $iban |
|
178 |
} |
|
179 |
|
|
180 |
# save the zugferd file to session file for reuse in ap.pl |
|
181 |
my $session_file = SL::SessionFile->new($file_name, mode => 'w'); |
|
182 |
$session_file->fh->print($file); |
|
183 |
$session_file->fh->close; |
|
191 |
if ($iban) { |
|
192 |
$intnotes .= "\nIBAN: "; |
|
193 |
$intnotes .= $iban ne $vendor->iban ? |
|
194 |
t8("Record IBAN #1 doesn't match vendor IBAN #2", $iban, $vendor->iban) |
|
195 |
: $iban |
|
196 |
} |
|
184 | 197 |
|
185 | 198 |
# Use invoice creation date as due date if there's no due date |
186 | 199 |
$metadata{'duedate'} = $metadata{'transdate'} unless defined $metadata{'duedate'}; |
... | ... | |
254 | 267 |
} |
255 | 268 |
$item_form{rowcount} = $row; |
256 | 269 |
|
257 |
$self->redirect_to( |
|
258 |
controller => 'ap.pl', |
|
259 |
action => 'load_zugferd', |
|
260 |
form_defaults => { |
|
261 |
zugferd_session_file => $file_name, |
|
262 |
callback => $self->url_for(action => 'upload_zugferd'), |
|
263 |
vendor_id => $vendor->id, |
|
264 |
vendor => $vendor->name, |
|
265 |
invnumber => $invnumber, |
|
266 |
transdate => $metadata{'transdate'}, |
|
267 |
duedate => $metadata{'duedate'}, |
|
268 |
no_payment_bookings => 0, |
|
269 |
intnotes => $intnotes, |
|
270 |
taxincluded => 0, |
|
271 |
direct_debit => $metadata{'direct_debit'}, |
|
272 |
currency => $currency->name, |
|
273 |
AP_chart_id => $ap_chart_id, |
|
274 |
paid_1_suggestion => $::form->format_amount(\%::myconfig, $metadata{'total'}, 2), |
|
275 |
%item_form, |
|
276 |
}, |
|
277 |
); |
|
278 |
|
|
270 |
return { |
|
271 |
vendor_id => $vendor->id, |
|
272 |
vendor => $vendor->name, |
|
273 |
invnumber => $invnumber, |
|
274 |
transdate => $metadata{'transdate'}, |
|
275 |
duedate => $metadata{'duedate'}, |
|
276 |
no_payment_bookings => 0, |
|
277 |
intnotes => $intnotes, |
|
278 |
taxincluded => 0, |
|
279 |
direct_debit => $metadata{'direct_debit'}, |
|
280 |
currency => $currency->name, |
|
281 |
AP_chart_id => $ap_chart_id, |
|
282 |
paid_1_suggestion => $::form->format_amount(\%::myconfig, $metadata{'total'}, 2), |
|
283 |
%item_form, |
|
284 |
}, |
|
279 | 285 |
} |
280 | 286 |
|
281 | 287 |
sub check_auth { |
bin/mozilla/ap.pl | ||
---|---|---|
115 | 115 |
$::auth->assert('ap_transactions'); |
116 | 116 |
|
117 | 117 |
my $file_name = $::form->{form_defaults}->{zugferd_session_file}; |
118 |
flash('info', $::locale->text( |
|
119 |
"The ZUGFeRD/Factur-X invoice '#1' has been loaded.", $file_name)); |
|
118 |
if ($file_name) { |
|
119 |
flash('info', $::locale->text( |
|
120 |
"The ZUGFeRD/Factur-X invoice '#1' has been loaded.", $file_name)); |
|
121 |
} |
|
120 | 122 |
|
121 | 123 |
my $template_ap = SL::DB::Manager::RecordTemplate->get_first(where => [vendor_id => $::form->{form_defaults}->{vendor_id}]); |
122 | 124 |
if ($template_ap) { |
js/kivi.EmailJournal.js | ||
---|---|---|
56 | 56 |
$.post("controller.pl", data, kivi.eval_json_result); |
57 | 57 |
} |
58 | 58 |
|
59 |
ns.zugferd_import_with_attachment = function() { |
|
60 |
let data = $('#record_action_form').serializeArray(); |
|
61 |
data.push({ name: 'action', value: 'EmailJournal/zugferd_import_with_attachment' }); |
|
62 |
$.post("controller.pl", data, kivi.eval_json_result); |
|
63 |
} |
|
64 |
|
|
59 | 65 |
ns.toggle_obsolete = function(email_journal_id) { |
60 | 66 |
let data = $('#record_action_form').serializeArray(); |
61 | 67 |
data.push({ name: 'action', value: 'EmailJournal/toggle_obsolete' }); |
templates/design40_webpages/email_journal/show.html | ||
---|---|---|
172 | 172 |
) %] |
173 | 173 |
</div> |
174 | 174 |
[% END %] |
175 |
|
|
176 |
<div id="zugferd_import_div" style="display:none"> |
|
177 |
<!-- get shown if the attachment is valid zugferd --> |
|
178 |
[% L.button_tag('kivi.EmailJournal.zugferd_import_with_attachment();', |
|
179 |
LxERP.t8('Factur-X/ZUGFeRD import'), |
|
180 |
style="margin-top:5px" |
|
181 |
) |
|
182 |
%] |
|
183 |
</div> |
|
184 |
|
|
175 | 185 |
</div></div> <!-- action_div --> |
176 | 186 |
|
177 | 187 |
<div id="record_selection_div"> |
templates/webpages/email_journal/show.html | ||
---|---|---|
164 | 164 |
[% END %] |
165 | 165 |
</div> |
166 | 166 |
</div> |
167 |
|
|
168 |
<div id="zugferd_import_div" style="display:none"> |
|
169 |
<!-- get shown if the attachment is valid zugferd --> |
|
170 |
[% L.button_tag('kivi.EmailJournal.zugferd_import_with_attachment();', |
|
171 |
LxERP.t8('Factur-X/ZUGFeRD import'), |
|
172 |
style="margin-top:5px" |
|
173 |
) |
|
174 |
%] |
|
175 |
</div> |
|
176 |
|
|
167 | 177 |
</tr> <tr> |
168 | 178 |
<td> |
169 | 179 |
<div id="record_selection_div"> |
Auch abrufbar als: Unified diff
EmailJournal: Anhang als ZUGFeRD importieren