Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision b8dfb10a

Von Tamino Steinert vor 12 Monaten hinzugefügt

  • ID b8dfb10abe66741a74818a510a74eb84c974d094
  • Vorgänger a2a95b63
  • Nachfolger 48ef5a7c

BJ:ImportRecordEmails: Status vom auto. ZUGFeRD-Import in erw. Status

Unterschiede anzeigen:

SL/BackgroundJob/ImportRecordEmails.pm
use SL::DB::Manager::EmailImport;
use SL::Helper::EmailProcessing;
use SL::Presenter::Tag qw(link_tag);
use SL::Locale::String qw(t8);
use Params::Validate qw(:all);
use List::MoreUtils qw(any);
......
# , $email_journal->id
# );
my $email_journal_id = $email_journal->id;
$result .= "Error while processing email journal $email_journal_id attachments with $function_name: $@";
$result .= t8("Error while processing email journal ('#1') attachments with '#2': ", $email_journal_id, $function_name) . $@ . ".";
};
}
if ($created_records && $config->{processed_imap_flag}) {
......
my $result = "";
$result .= "Deleted email import(s): "
$result .= t8("Deleted email import(s): ")
. join(', ', @deleted_email_import_ids) . "."
if scalar @deleted_email_import_ids;
$result .= "Could not find email import(s): "
$result .= t8("Could not find email import(s): ")
. join(', ', @not_found_email_import_ids) . " for deletion."
if scalar @not_found_email_import_ids;
SL/Controller/EmailJournal.pm
my $record_type = $::form->{"record_type"};
die "ZUGFeRD-Import only implemented for ap transaction templates" unless $record_type == 'ap_transaction';
my $attachment_id = $::form->{attachment_id};
my $attachment_id = $::form->{attachment_id};
my $form_defaults;
if ($attachment_id) {
SL/Controller/ZUGFeRD.pm
unless ( defined $ap_chart_id ) {
# If no default account is configured, just use the first AP account found.
my $ap_chart = SL::DB::Manager::Chart->get_all(
my ($ap_chart) = @{SL::DB::Manager::Chart->get_all(
where => [ link => 'AP' ],
sort_by => [ 'accno' ],
);
$ap_chart_id = ${$ap_chart}[0]->id;
)};
$ap_chart_id = $ap_chart->id;
}
my $currency = SL::DB::Manager::Currency->find_by(
SL/DB/Helper/ZUGFeRD.pm
# Try to fill in AP account to book against
my $ap_chart_id = $::instance_conf->get_ap_chart_id;
my $ap_chart = SL::DB::Manager::Chart->find_by(id => $ap_chart_id);
unless ( defined $ap_chart ) {
my $ap_chart;
unless ( defined $ap_chart_id ) {
# If no default account is configured, just use the first AP account found.
my $ap_charts = SL::DB::Manager::Chart->get_all(
($ap_chart) = @{SL::DB::Manager::Chart->get_all(
where => [ link => 'AP' ],
sort_by => [ 'accno' ],
);
$ap_chart = ${$ap_charts}[0];
)};
} else {
$ap_chart = SL::DB::Manager::Chart->find_by(id => $ap_chart_id);
}
my $currency = SL::DB::Manager::Currency->find_by(
......
my %template_params;
my $template_ap = SL::DB::Manager::RecordTemplate->get_first(where => [vendor_id => $vendor->id]);
if ($template_ap) {
$template_params{globalproject_id} = $template_ap->globalproject_id;
$template_params{globalproject_id} = $template_ap->project_id;
$template_params{payment_id} = $template_ap->payment_id;
$template_params{department_id} = $template_ap->department_id;
$template_params{ordnumber} = $template_ap->ordnumber;
......
taxzone_id => $vendor->taxzone_id,
currency_id => $currency->id,
direct_debit => $metadata{'direct_debit'},
invnumber => $invnumber,
transdate => $metadata{transdate} || $today->to_kivitendo,
duedate => $metadata{duedate} || $today->to_kivitendo,
taxincluded => 0,
intnotes => $intnotes,
invnumber => $invnumber,
transdate => $metadata{transdate} || $today->to_kivitendo,
duedate => $metadata{duedate} || $today->to_kivitendo,
taxincluded => 0,
intnotes => $intnotes,
transactions => [],
%template_params,
);
......
$self->assign_attributes(%params);
# parse items
my $template_item;
if ($template_ap && scalar @{$template_ap->items}) {
my $template_item = $template_ap->items->[0];
}
foreach my $i (@items) {
my %item = %{$i};
my $net_total = $item{'subtotal'};
# set default values for items
my ($tax, $chart, $project_id);
if ($template_ap) {
my $template_item = $template_ap->items->[0];
$tax = SL::DB::Tax->new(id => $template_item->tax_id)->load();
$chart = SL::DB::Chart->new(id => $template_item->chart_id)->load();
$project_id = $template_item->project_id;
my %line_params;
$line_params{amount} = $net_total;
if ($template_item) {
$line_params{tax_id} = $template_item->tax->id;
$line_params{chart} = $template_item->chart;
$line_params{project_id} = $template_item->project_id;
} else {
my $tax_rate = $item{'tax_rate'};
$tax_rate /= 100 if $tax_rate > 1; # XML data is usually in percent
$tax = first { $tax_rate == $_->rate } @{ $taxes };
$tax //= first { $active_taxkey->tax_id == $_->id } @{ $taxes };
$tax //= $taxes->[0];
$chart = $default_ap_amount_chart;
my $tax_rate = $item{'tax_rate'};
$tax_rate /= 100 if $tax_rate > 1; # XML data is usually in percent
my $tax = first { $tax_rate == $_->rate } @{ $taxes };
$tax //= first { $active_taxkey->tax_id == $_->id } @{ $taxes };
$tax //= $taxes->[0];
$line_params{tax_id} = $tax->id;
$line_params{chart} = $default_ap_amount_chart;
}
my %line_params = (
amount => $net_total,
tax_id => $tax->id,
chart => $chart,
);
$self->add_ap_amount_row(%line_params);
}
$self->recalculate_amounts();
SL/Helper/EmailProcessing.pm
use XML::LibXML;
use SL::ZUGFeRD;
use SL::Locale::String qw(t8);
use SL::DB::PurchaseInvoice;
sub process_attachments {
my ($self, $function_name, $email_journal, %params) = @_;
unless ($self->can("process_attachments_$function_name")) {
my $full_function_name = "process_attachments_$function_name";
unless ($self->can($full_function_name)) {
croak "Function not implemented for: $function_name";
}
$function_name = "process_attachments_$function_name";
my $processed_count = 0;
my @processed_files;
my @errors;
foreach my $attachment (@{$email_journal->attachments_sorted}) {
my $processed = $self->$function_name($email_journal, $attachment, %params);
$processed_count += $processed;
my $attachment_name = $attachment->name;
my $error = $self->$full_function_name($email_journal, $attachment, %params);
if ($error) {
push @errors, "$attachment_name: $error.";
} else {
push @processed_files, $attachment_name;
}
}
return $processed_count;
my $extended_status = t8("Processed attachments with function '#1':", $function_name);
if (scalar @processed_files) {
$extended_status .= "\n" . t8("Processed successfully: ")
. join(', ', @processed_files);
}
if (scalar @errors) {
$extended_status .= "\n" . t8("Errors while processing: ")
. "\n" . join("\n", @errors);
}
unless (scalar @processed_files || scalar @errors) {
$extended_status .= "\n" . t8("No attachments.");
}
$email_journal->extended_status(
join "\n", $email_journal->extended_status, $extended_status
);
$email_journal->save;
return scalar @processed_files;
}
sub can_function {
......
my ($self, $email_journal, $attachment, %params) = @_;
my $content = $attachment->content; # scalar ref
my $name = $attachment->name;
return 0 unless $content =~ m/^%PDF|<\?xml/;
return t8("Not a PDF or XML file") unless $content =~ m/^%PDF|<\?xml/;
my %res;
if ( $content =~ m/^%PDF/ ) {
......
}
unless ($res{'result'} == SL::ZUGFeRD::RES_OK()) {
my $error = $res{'message'};
$email_journal->extended_status(
join "\n", $email_journal->extended_status,
"Error processing ZUGFeRD attachment $name: $error"
)->save;
return 0;
# my $error = $res{'message'}; # technical error
my $error = t8('No vaild Factur-X/ZUGFeRD file');
return $error;
}
my $purchase_invoice;
......
1;
} or do {
my $error = $@;
$email_journal->update_attributes(
extended_status =>
join "\n", $email_journal->extended_status,
"Error processing ZUGFeRD attachment $name: $error"
);
return 0;
return $error;
};
$self->_add_attachment_to_record($email_journal, $attachment, $purchase_invoice);
return 1;
return 0;
}
sub _add_attachment_to_record {
locale/de/all
'Could not create new project #1' => 'Neues Projekt #1 kann nicht angelegt werden',
'Could not extract Factur-X/ZUGFeRD data, data and error message:' => 'Konnte keine Factur-X-/ZUGFeRD-Daten extrahieren, folgende Fehlermeldung und das PDF:',
'Could not find an entry for this part in the pricegroup.' => 'Konnte keinen Eintrag für diesen Artikel in der Preisgruppe finden.',
'Could not find email import(s): ' => 'Konnte folgende E-Mailimport(e) nicht finden: ',
'Could not load class #1 (#2): "#3"' => 'Konnte Klasse #1 (#2) nicht laden: "#3"',
'Could not load class #1, #2' => 'Konnte Klasse #1 nicht laden: "#2"',
'Could not load employee' => 'Konnte Benutzer nicht laden',
......
'Delete text block' => 'Textblock löschen',
'Delete transaction' => 'Buchung löschen',
'Deleted' => 'Gelöscht',
'Deleted email import(s): ' => 'Gelöschte E-Mailimport(e): ',
'Deleting this type of record has been disabled in the configuration.' => 'Das Löschen von dieser Belegart ist in der Konfiguration deaktiviert.',
'Delivered' => 'Geliefert',
'Delivered amount' => 'Gelieferter Betrag',
......
'Error when saving: #1' => 'Fehler beim Speichern: #1',
'Error while applying year-end bookings!' => 'Fehler beim Durchführen der Abschlußbuchungen!',
'Error while creating project with project number of new order number, project number #1 already exists!' => 'Fehler beim Erstellen eines Projekts mit der Projektnummer der neuen Auftragsnummer, Projektnummer #1 existiert bereits!',
'Error while processing email journal (\'#1\') attachments with \'#2\': ' => 'Fehler beim Verarbeiten der E-Mail-Journals (\'#1\') Anhänge mit \'#2\': ',
'Error while saving shop order #1. DB Error #2. Generic exception #3.' => 'Fehler beim Speichern der Shop-Bestellung #1. DB Fehler #2. Genereller Fehler #3.',
'Error with default taxzone' => 'Ungültige Standardsteuerzone',
'Error!' => 'Fehler!',
......
'Errors during printing:' => 'Druckfehler:',
'Errors in GL transaction:' => 'Fehler in Dialogbuchung:',
'Errors while deleting record:' => 'Fehler beim Speichern des Belegs:',
'Errors while processing: ' => 'Fehler bei Verarbeitung: ',
'Errors: #1' => 'Fehler: #1',
'Ertrag' => 'Ertrag',
'Ertrag prozentual' => 'Ertrag prozentual',
......
'No articles have been added yet.' => 'Es wurden noch keine Artikel hinzugefügt.',
'No assembly has been selected yet.' => 'Es wurde noch kein Erzeugnis ausgewahlt.',
'No attachment' => 'Kein Anhang',
'No attachments.' => 'Keine Anhänge',
'No background job has been created yet.' => 'Es wurden noch keine Hintergrund-Jobs angelegt.',
'No bank account chosen!' => 'Kein Bankkonto ausgewählt!',
'No bank account configured for bank code/BIC #1, account number/IBAN #2.' => 'Kein Bankkonto für BLZ/BIC #1, Kontonummer/IBAN #2 konfiguriert.',
......
'No transactions yet.' => 'Bisher keine Buchungen.',
'No transfers were executed in this export.' => 'In diesem SEPA-Export wurden keine Überweisungen ausgeführt.',
'No users have been created yet.' => 'Es wurden noch keine Benutzer angelegt.',
'No vaild Factur-X/ZUGFeRD file' => 'Keine valide Factur-X/ZUGFeRD Datei',
'No valid invoice(s) found' => 'Keine gültige(n) Rechnung(en) gefunden.',
'No valid number entered for pricegroup "#1".' => 'Für Preisgruppe "#1" wurde keine gültige Nummer eingegeben.',
'No vendor available' => 'Kein Lieferant verfügbar',
......
'Normalize Customer / Vendor names' => 'Normalisierung Kunden- / Lieferantennamen',
'Normalize part description and part notes' => 'Normalisierung Artikelbeschreibung und Artikellangtext (Bemerkung)',
'Not Discountable' => 'Nicht rabattierfähig',
'Not a PDF or XML file' => 'Keine PDF oder XML Datei',
'Not delivered' => 'Nicht geliefert',
'Not delivered amount' => 'nicht gelieferte Menge',
'Not done yet' => 'Noch nicht fertig',
......
'Private E-mail' => 'Private E-Mail',
'Private Phone' => 'Privates Tel.',
'Problem' => 'Problem',
'Processed attachments with function \'#1\':' => 'Anhänge verarbeitet mit Funktion \'#1\':',
'Processed successfully: ' => 'Erfolgreich verarbeitet: ',
'Produce' => 'Fertigen',
'Produce Assembly' => 'Erzeugnis fertigen',
'Produce Assembly Configuration' => 'Konfiguration für Erzeugnis fertigen',
locale/en/all
'Could not create new project #1' => '',
'Could not extract Factur-X/ZUGFeRD data, data and error message:' => '',
'Could not find an entry for this part in the pricegroup.' => '',
'Could not find email import(s): ' => '',
'Could not load class #1 (#2): "#3"' => '',
'Could not load class #1, #2' => '',
'Could not load employee' => '',
......
'Delete text block' => '',
'Delete transaction' => '',
'Deleted' => '',
'Deleted email import(s): ' => '',
'Deleting this type of record has been disabled in the configuration.' => '',
'Delivered' => '',
'Delivered amount' => '',
......
'Error when saving: #1' => '',
'Error while applying year-end bookings!' => '',
'Error while creating project with project number of new order number, project number #1 already exists!' => '',
'Error while processing email journal (\'#1\') attachments with \'#2\': ' => '',
'Error while saving shop order #1. DB Error #2. Generic exception #3.' => '',
'Error with default taxzone' => '',
'Error!' => '',
......
'Errors during printing:' => '',
'Errors in GL transaction:' => '',
'Errors while deleting record:' => '',
'Errors while processing: ' => '',
'Errors: #1' => '',
'Ertrag' => '',
'Ertrag prozentual' => '',
......
'No articles have been added yet.' => '',
'No assembly has been selected yet.' => '',
'No attachment' => '',
'No attachments.' => '',
'No background job has been created yet.' => '',
'No bank account chosen!' => '',
'No bank account configured for bank code/BIC #1, account number/IBAN #2.' => '',
......
'No transactions yet.' => '',
'No transfers were executed in this export.' => '',
'No users have been created yet.' => '',
'No vaild Factur-X/ZUGFeRD file' => '',
'No valid invoice(s) found' => '',
'No valid number entered for pricegroup "#1".' => '',
'No vendor available' => '',
......
'Normalize Customer / Vendor names' => '',
'Normalize part description and part notes' => '',
'Not Discountable' => '',
'Not a PDF or XML file' => '',
'Not delivered' => '',
'Not delivered amount' => '',
'Not done yet' => '',
......
'Private E-mail' => '',
'Private Phone' => '',
'Problem' => '',
'Processed attachments with function \'#1\':' => '',
'Processed successfully: ' => '',
'Produce' => '',
'Produce Assembly' => '',
'Produce Assembly Configuration' => '',

Auch abrufbar als: Unified diff