Revision 5b44ba35
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 |
} |
bin/mozilla/ap.pl | ||
---|---|---|
114 | 114 |
sub load_zugferd { |
115 | 115 |
$::auth->assert('ap_transactions'); |
116 | 116 |
|
117 |
my $data; # buffer for holding file contents |
|
118 |
|
|
119 |
my $form_defaults = $::form->{form_defaults}; |
|
120 |
my $file = SL::SessionFile->new($form_defaults->{zugferd_session_file}, mode => '<'); |
|
121 |
my $file_name = $file->file_name; |
|
122 |
|
|
123 |
$::form->{$_} = $form_defaults->{$_} for keys %{ $form_defaults // {} }; |
|
117 |
my $file_name = $::form->{zugferd_session_file}; |
|
124 | 118 |
|
125 | 119 |
# Defaults |
126 |
$::form->{title} = "Add"; |
|
127 |
$::form->{paidaccounts} = 1; |
|
128 |
|
|
129 |
$file->open('<'); |
|
130 |
if ( ! defined($file->fh->read($data, -s $file->fh)) ) { |
|
131 |
SL::Helper::Flash::flash_later('error', |
|
132 |
t8('Could not open ZUGFeRD file for reading: #1', $!)); |
|
133 |
} else { |
|
134 |
|
|
135 |
my %res; # result data structure returned by SL::ZUGFeRD->extract_from_{pdf,xml}() |
|
136 |
my $parser; # SL::XMLInvoice object created by SL::ZUGFeRD->extract_from_{pdf,xml}() |
|
137 |
my $template_ap; # SL::DB::RecordTemplate object |
|
138 |
my $vendor; # SL::DB::Vendor object |
|
139 |
my %metadata; # structured data extracted from XML payload |
|
140 |
my @items; # list of invoice items |
|
141 |
my $default_ap_amount_chart; |
|
142 |
|
|
143 |
if ( $data =~ m/^%PDF/ ) { |
|
144 |
%res = %{SL::ZUGFeRD->extract_from_pdf($data)}; |
|
145 |
} else { |
|
146 |
%res = %{SL::ZUGFeRD->extract_from_xml($data)}; |
|
147 |
} |
|
148 |
|
|
149 |
|
|
150 |
$parser = $res{'invoice_xml'}; |
|
151 |
%metadata = %{$parser->metadata}; |
|
152 |
@items = @{$parser->items}; |
|
153 |
|
|
154 |
$default_ap_amount_chart = SL::DB::Manager::Chart->find_by(id => $::instance_conf->get_expense_accno_id); |
|
155 |
|
|
156 |
# Fallback if there's no default AP amount chart configured |
|
157 |
unless ( $default_ap_amount_chart ) { |
|
158 |
$default_ap_amount_chart = SL::DB::Manager::Chart->find_by(charttype => 'A'); |
|
159 |
} |
|
160 |
|
|
161 |
my $row = 0; |
|
162 |
foreach my $i (@items) { |
|
163 |
$row++; |
|
164 |
|
|
165 |
my %item = %{$i}; |
|
120 |
$::form->{title} ||= "Add"; |
|
121 |
$::form->{paidaccounts} = 1 if undef $::form->{paidaccounts}; |
|
166 | 122 |
|
167 |
my $net_total = $::form->format_amount(\%::myconfig, $item{'subtotal'}, 2); |
|
168 |
my $desc = $item{'description'}; |
|
169 |
my $tax_rate = $item{'tax_rate'} / 100; # XML data is usually in percent |
|
170 |
|
|
171 |
my $active_taxkey = $default_ap_amount_chart->taxkey_id; |
|
172 |
my $taxes = SL::DB::Manager::Tax->get_all( |
|
173 |
where => [ chart_categories => { like => '%' . $default_ap_amount_chart->category . '%' }], |
|
174 |
sort_by => 'taxkey, rate', |
|
175 |
); |
|
176 |
|
|
177 |
my $tax = first { $tax_rate == $_->rate } @{ $taxes }; |
|
178 |
$tax //= first { $active_taxkey->tax_id == $_->id } @{ $taxes }; |
|
179 |
$tax //= $taxes->[0]; |
|
180 |
|
|
181 |
# If we really can't find any tax definition (a simple rounding error may |
|
182 |
# be sufficient for that to happen), grab the first tax fitting the default |
|
183 |
# AP amount chart, just like the AP form would do it for manual entry. |
|
184 |
if ( scalar @{$taxes} == 0 ) { |
|
185 |
$taxes = SL::DB::Manager::Tax->get_all( |
|
186 |
where => [ chart_categories => { like => '%' . $default_ap_amount_chart->category . '%' } ], |
|
187 |
); |
|
188 |
} |
|
189 |
|
|
190 |
if (!$tax) { |
|
191 |
$row--; |
|
192 |
next; |
|
193 |
} |
|
194 |
|
|
195 |
$::form->{"AP_amount_chart_id_${row}"} = $default_ap_amount_chart->id; |
|
196 |
$::form->{"previous_AP_amount_chart_id_${row}"} = $default_ap_amount_chart->id; |
|
197 |
$::form->{"amount_${row}"} = $net_total; |
|
198 |
$::form->{"taxchart_${row}"} = $tax->id . '--' . $tax->rate; |
|
199 |
} |
|
200 |
|
|
201 |
flash('info', $::locale->text("The ZUGFeRD/Factur-X invoice '#1' has been loaded.", $file_name)); |
|
202 |
|
|
203 |
$::form->{form_validity_token} = SL::DB::ValidityToken->create(scope => SL::DB::ValidityToken::SCOPE_PURCHASE_INVOICE_POST())->token; |
|
204 |
$::form->{rowcount} = $row; |
|
205 |
|
|
206 |
update( |
|
207 |
keep_rows_without_amount => 1, |
|
208 |
dont_add_new_row => 1, |
|
209 |
); |
|
210 |
} |
|
123 |
$::form->{form_validity_token} = SL::DB::ValidityToken->create(scope => SL::DB::ValidityToken::SCOPE_PURCHASE_INVOICE_POST())->token; |
|
124 |
flash('info', $::locale->text( |
|
125 |
"The ZUGFeRD/Factur-X invoice '#1' has been loaded.", $file_name)); |
|
126 |
update( |
|
127 |
keep_rows_without_amount => 1, |
|
128 |
dont_add_new_row => 1, |
|
129 |
); |
|
211 | 130 |
} |
212 | 131 |
|
213 | 132 |
sub load_record_template { |
locale/de/all | ||
---|---|---|
848 | 848 |
'Could not load this vendor' => 'Konnte diesen Lieferanten nicht laden', |
849 | 849 |
'Could not open ZUGFeRD file for reading: #1' => 'Die ZUGFeRD Datei konnte nicht zum Lesen geöffnet werden: #1', |
850 | 850 |
'Could not parse PDF embedded attachment #1: #2' => 'Konnte PDF-Anhang #1 nicht verarbeiten: #2', |
851 |
'Could not parse XML Invoice: unknown root node name (#1) (supported: (#2))' => 'Konnte XML-Rechnung nicht verabeiten: unbekanntes Wurzelelement (unterstützt: #2)',
|
|
851 |
'Could not parse XML Invoice: unknown XML invoice type\nsupported: #1' => 'Konnte XML Rechnung nicht parsen: unbekannter XML Rechnungstyp\nunterstützt: #1',
|
|
852 | 852 |
'Could not print dunning.' => 'Die Mahnungen konnten nicht gedruckt werden.', |
853 | 853 |
'Could not reconcile chosen elements!' => 'Die gewählten Elemente konnten nicht ausgeglichen werden!', |
854 | 854 |
'Could not spawn ghostscript.' => 'Die Anwendung "ghostscript" konnte nicht gestartet werden.', |
... | ... | |
1716 | 1716 |
'Factur-X/ZUGFeRD invoice' => 'Factur-X-/ZUGFeRD-Rechnung', |
1717 | 1717 |
'Factur-X/ZUGFeRD notes for each invoice' => 'Factur-X-/ZUGFeRD-Notizen für jede Rechnung', |
1718 | 1718 |
'Factur-X/ZUGFeRD settings' => 'Factur-X-/ZUGFeRD-Einstellungen', |
1719 |
'Faktur-X/ZUGFeRD/XRechnung import #1, #2' => 'Faktur-X/ZUGFeRD/XRechnung-Import #1, #2', |
|
1720 | 1719 |
'Fax' => 'Fax', |
1721 | 1720 |
'Features' => 'Features', |
1722 | 1721 |
'Feb' => 'Feb', |
... | ... | |
2453 | 2452 |
'No Order items fetched' => 'Keine Auftragspositionen gefunden', |
2454 | 2453 |
'No Shopdescription' => 'Keine Shop-Artikelbeschreibung', |
2455 | 2454 |
'No Shopimages' => 'Keine Shop-Bilder', |
2455 |
'No VAT Info for this Factur-X/ZUGFeRD invoice, please ask your vendor to add this for his Factur-X/ZUGFeRD data.' => 'Keine USt-Info für diese Factur-X/ZUGFeRD Rechnung, bitte fragen Sie Ihren Lieferanten, diese für seine Factur-X/ZUGFeRD Daten hinzuzufügen.', |
|
2456 | 2456 |
'No Vendor' => 'Kein Lieferant', |
2457 | 2457 |
'No Vendor was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Händler gefunden', |
2458 | 2458 |
'No account selected. Please select an account.' => 'Kein Konto ausgewählt. Bitte Konto auswählen.', |
... | ... | |
2536 | 2536 |
'No such job #1 in the database.' => 'Hintergrund-Job #1 existiert nicht mehr.', |
2537 | 2537 |
'No summary account' => 'Kein Sammelkonto', |
2538 | 2538 |
'No superuser credentials were entered.' => 'Es wurden keine Super-Benutzer-Anmeldedaten eingegeben.', |
2539 |
'No tax found for chart #1' => 'Keine Steuer für Konto #1 gefunden', |
|
2539 | 2540 |
'No template has been selected yet.' => 'Es wurde noch keine Vorlage ausgewählt.', |
2540 | 2541 |
'No text blocks have been created for this position.' => 'Für diese Position wurden noch keine Textblöcke angelegt.', |
2541 | 2542 |
'No text has been entered yet.' => 'Es wurde noch kein Text eingegeben.', |
... | ... | |
2847 | 2848 |
'Pictures for search parts' => 'Bilder für Warensuche', |
2848 | 2849 |
'Please Check the bank information for each customer:' => 'Bitte überprüfen Sie die Bankinformationen der Kunden:', |
2849 | 2850 |
'Please Check the bank information for each vendor:' => 'Bitte überprüfen Sie die Kontoinformationen der Lieferanten:', |
2851 |
'Please add a valid VAT-ID for this vendor: #1' => 'Bitte fügen Sie eine gültige USt-ID für diesen Lieferanten hinzu: #1', |
|
2850 | 2852 |
'Please ask your administrator to create warehouses and bins.' => 'Bitten Sie Ihren Administrator, dass er Lager und Lagerplätze anlegt.', |
2851 | 2853 |
'Please change the partnumber of the following parts and run the update again:' => 'Bitte ändern Sie daher die Artikelnummer folgender Artikel:', |
2852 | 2854 |
'Please choose a part.' => 'Bitte wählen Sie einen Artikel aus.', |
... | ... | |
3165 | 3167 |
'Reconcile' => 'Abgleichen', |
3166 | 3168 |
'Reconciliation' => 'Kontenabgleich', |
3167 | 3169 |
'Reconciliation with bank' => 'Kontenabgleich mit Bank', |
3170 |
'Record IBAN #1 doesn\'t match vendor IBAN #2' => 'Beleg IBAN #1 stimmt nicht mit Lieferanten IBAN #2 überein', |
|
3168 | 3171 |
'Record Type' => 'Belegtyp', |
3169 | 3172 |
'Record Vendor Invoice' => 'Einkaufsrechnung erfassen', |
3170 | 3173 |
'Record in' => 'Buchen auf', |
... | ... | |
3911 | 3914 |
'The WebDAV feature has been used.' => 'Das WebDAV-Feature wurde benutzt.', |
3912 | 3915 |
'The XMP metadata does not declare the Factur-X/ZUGFeRD data.' => 'Die XMP-Metadaten enthalten keine Factur-X-/ZUGFeRD-Deklaration.', |
3913 | 3916 |
'The ZUGFeRD invoice data cannot be generated because the data validation failed.' => 'Die ZUGFeRD-Rechnungsdaten können nicht erzeugt werden, da die Validierung fehlschlug.', |
3917 |
'The ZUGFeRD/Factur-X invoice \'#1\' has been loaded.' => 'Die ZUGFeRD/Factur-X Rechnung \'#1\' wurde geladen.', |
|
3914 | 3918 |
'The abbreviation is missing.' => 'Abkürzung fehlt', |
3915 | 3919 |
'The access rights a user has within a client instance is still governed by his group membership.' => 'Welche Zugriffsrechte ein Benutzer innerhalb eines Mandanten hat, wird weiterhin über Gruppenmitgliedschaften geregelt.', |
3916 | 3920 |
'The access rights have been saved.' => 'Die Zugriffsrechte wurden gespeichert.', |
... | ... | |
4860 | 4864 |
'Your import is being processed.' => 'Ihr Import wird verarbeitet', |
4861 | 4865 |
'Your target quantity will be added to the stocked quantity.' => 'Ihre gezählte Zielmenge wird zum Lagerbestand hinzugezählt.', |
4862 | 4866 |
'ZIPcode' => 'PLZ', |
4867 |
'ZUGFeRD Import. Type: #1' => 'ZUGFeRD Import. Typ: #1', |
|
4863 | 4868 |
'Zeitraum' => 'Zeitraum', |
4864 | 4869 |
'Zero amount posting!' => 'Buchung ohne Wert', |
4865 | 4870 |
'Zip' => 'PLZ', |
locale/en/all | ||
---|---|---|
673 | 673 |
'Cannot post transaction with a debit and credit entry for the same account!' => '', |
674 | 674 |
'Cannot post transaction!' => '', |
675 | 675 |
'Cannot process payment for a closed period!' => '', |
676 |
'Cannot process this invoice: neither VAT ID nor tax ID present.' => '', |
|
676 | 677 |
'Cannot remove files!' => '', |
677 | 678 |
'Cannot revert a versioned copy.' => '', |
678 | 679 |
'Cannot safely book imported bank transactions due to lax posting settings for payments' => '', |
... | ... | |
846 | 847 |
'Could not load this draft' => '', |
847 | 848 |
'Could not load this vendor' => '', |
848 | 849 |
'Could not open ZUGFeRD file for reading: #1' => '', |
850 |
'Could not parse PDF embedded attachment #1: #2' => '', |
|
851 |
'Could not parse XML Invoice: unknown XML invoice type\nsupported: #1' => '', |
|
849 | 852 |
'Could not print dunning.' => '', |
850 | 853 |
'Could not reconcile chosen elements!' => '', |
851 | 854 |
'Could not spawn ghostscript.' => '', |
... | ... | |
2436 | 2439 |
'Next run at' => '', |
2437 | 2440 |
'No' => '', |
2438 | 2441 |
'No 1:n or n:1 relation' => '', |
2439 |
'No AP Record Template for this vendor found, please add one' => '', |
|
2440 | 2442 |
'No AP Record Template for vendor #1 found, please add one' => '', |
2441 | 2443 |
'No AP template was found.' => '', |
2442 | 2444 |
'No Billing and ship to address, for Order Number #1 with ID Billing #2 and ID Shipping #3' => '', |
... | ... | |
2533 | 2535 |
'No such job #1 in the database.' => '', |
2534 | 2536 |
'No summary account' => '', |
2535 | 2537 |
'No superuser credentials were entered.' => '', |
2538 |
'No tax found for chart #1' => '', |
|
2536 | 2539 |
'No template has been selected yet.' => '', |
2537 | 2540 |
'No text blocks have been created for this position.' => '', |
2538 | 2541 |
'No text has been entered yet.' => '', |
... | ... | |
2738 | 2741 |
'Paid' => '', |
2739 | 2742 |
'Paid amount' => '', |
2740 | 2743 |
'Parameter module must be given.' => '', |
2744 |
'Parsing the XML data failed: #1' => '', |
|
2741 | 2745 |
'Parsing the XMP metadata failed.' => '', |
2742 | 2746 |
'Part' => '', |
2743 | 2747 |
'Part "#1" has chargenumber or best before date set. So it cannot be transfered automatically.' => '', |
... | ... | |
3162 | 3166 |
'Reconcile' => '', |
3163 | 3167 |
'Reconciliation' => '', |
3164 | 3168 |
'Reconciliation with bank' => '', |
3169 |
'Record IBAN #1 doesn\'t match vendor IBAN #2' => '', |
|
3165 | 3170 |
'Record Type' => '', |
3166 | 3171 |
'Record Vendor Invoice' => '', |
3167 | 3172 |
'Record in' => '', |
... | ... | |
3880 | 3885 |
'The AR transaction #1 has been deleted.' => '', |
3881 | 3886 |
'The Bins in Inventory were only a information text field.' => '', |
3882 | 3887 |
'The Bins in master data were only a information text field.' => '', |
3883 |
'The Factur-X/ZUGFeRD XML invoice was not found.' => '', |
|
3884 | 3888 |
'The Factur-X/ZUGFeRD notes have been saved.' => '', |
3885 | 3889 |
'The Factur-X/ZUGFeRD version used is not supported.' => '', |
3886 | 3890 |
'The GL transaction #1 has been deleted.' => '', |
... | ... | |
3908 | 3912 |
'The WebDAV feature has been used.' => '', |
3909 | 3913 |
'The XMP metadata does not declare the Factur-X/ZUGFeRD data.' => '', |
3910 | 3914 |
'The ZUGFeRD invoice data cannot be generated because the data validation failed.' => '', |
3915 |
'The ZUGFeRD/Factur-X invoice \'#1\' has been loaded.' => '', |
|
3911 | 3916 |
'The abbreviation is missing.' => '', |
3912 | 3917 |
'The access rights a user has within a client instance is still governed by his group membership.' => '', |
3913 | 3918 |
'The access rights have been saved.' => '', |
... | ... | |
4690 | 4695 |
'Vendor saved' => '', |
4691 | 4696 |
'Vendor saved!' => '', |
4692 | 4697 |
'Vendor type' => '', |
4698 |
'Vendor with VAT ID (#1) and/or tax ID (#2) not found. Please check if the vendor #3 exists and whether it has the correct tax ID/VAT ID.' => '', |
|
4693 | 4699 |
'Vendors' => '', |
4694 | 4700 |
'Vendors: VAT ID / taxnumber unique' => '', |
4695 | 4701 |
'Verrechnungseinheit' => '', |
... | ... | |
4856 | 4862 |
'Your import is being processed.' => '', |
4857 | 4863 |
'Your target quantity will be added to the stocked quantity.' => '', |
4858 | 4864 |
'ZIPcode' => '', |
4865 |
'ZUGFeRD Import. Type: #1' => '', |
|
4859 | 4866 |
'Zeitraum' => '', |
4860 | 4867 |
'Zero amount posting!' => '', |
4861 | 4868 |
'Zip' => '', |
... | ... | |
4904 | 4911 |
'by' => '', |
4905 | 4912 |
'can not allocate #1 units of #2, missing #3 units' => '', |
4906 | 4913 |
'can not allocate enough resources for production' => '', |
4907 |
'can only parse a pdf file' => '',
|
|
4914 |
'can only parse a pdf or xml file' => '',
|
|
4908 | 4915 |
'cash' => '', |
4909 | 4916 |
'chargenumber #1' => '', |
4910 | 4917 |
'chart_of_accounts' => '', |
Auch abrufbar als: Unified diff
ZUGFeRD: Verschiebe komplettes Parsen aus ap.pl nach S:C:ZUGFeRD