Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 6a12a968

Von Niclas Zimmermann vor fast 10 Jahren hinzugefügt

  • ID 6a12a968761127af91e9da8db7579be2836bcaaa
  • Vorgänger 28fee2e2
  • Nachfolger b09bc3de

Bankerweiterung - Zwischenstand, erster Entwurf

Erstellung von Tabelle bank_transactions

Import von Bankbewegungen (in Tabelle bank_transactions)

Menu-Eintrag war noch nicht commitet

Controller für die Bank-Transaktionen

Dialog hin- und her

Achtung: noch mit Debug-Statements!

Dies und das für Bank_transactions...

BankTransaction in RecordLinks

Kann verknüpfte Belege Speichern

Man kann Rechnungen mehr oder weniger schon als bezahlt markieren

Erweiterung für EK-Rechnungen (funktioniert noch nicht ganz)

EK-Rechnungen und erste Vorschläge für Rechnung bezahlen

Information von Rechnungen + Javascript statt Ajax

Style als Link lassen

Deckt verschiedene Spezialfälle ab

Datums- und Zahlenformatierungen (noch nicht fertig)

Datumsformat und Übersetzungen

Sub date wieder aus LxERP entfernt

Logik für automatisches Zuweisen

Bericht für BTs (noch nicht ganz fertig)

Formatierungen für Zeilen mit ReportGenerator

Löschen-Knopf und paar Sachen

Entwurf laden und mit Parametern aus form überschreiben

Aufruf mit Parametern als get für Kreditorenbuchung:

ap.pl?action=load_draft&id=ap-invoice-1385202327-644205-8150&invnumber=dsfdf&remove_draft=0&paid_1=123,45

Rechnung aus Bankbeleg erstellen

Bankkonten-Filter und id auf bank_account statt local...

Verknüpfte Belege mit id-Verknüpfung zu local_bank_account

CsvImport mit ID auf BankAccounts (noch nicht getestet)

Behebt Bugs bei Csv-Import von Bankbewegungen

Währungs-ID statt Währungsstring benutzen

Passt den Bankbewegungs-Import an die neuen Änderungen der Helfer an

Filter für create_invoice

Vergessene Templates

Filter für create invoice funktionier halb

Rest für den Filter von create Invoice

Auswahllistenbegrenzer bei Lieferantenfilter beachten

Mehr Daten bei 'create invoice' übernehmen

Wenn man eine Kreditorenbuchung aus einer Bankbewegung erstellt,
werden nun mehr Daten aus der Bankbewegung in die Vorlage über-
nommen.

Änderungen in drafts.pl (gehören zu letztem Commit)

Betrag richtig formatieren und Form submitten

Bei assign invoice werden jetzt Rechnungsbeträge richtig formatiert
und es werden Rechnungen gesucht, wenn man auf 'Enter' drückt.

Weiterleitung auf List und Rechnungsbezahlen repariert

Vorzeichen wechseln bei create invoice

Das Vorzeichen von der Bankbewegung muss geändert werden, wenn man
aus einer Bankbewegung eine Kreditorenbuchung erstellt.

Sortierung von Spalten bei Bankbewegungen

Geoffery's Änderungen bzgl. Vorschlagsuche

BankTransaction - create_invoice filtert für Kreditorenbuchungen

Im Bank-Dropdown Bankname zuerst anzeigen

Und die Breite vom Dropdown angepasst.

Bankauszug verbuchen Menüpunkt nicht unter Berichte

Banktransactions - Spalten in Tabellen umsortiert

Banktransactions Tooltip - bt-Info in Tooltip Fenster aufnehmen

Damit man innerhalb des Tooltip Fensters die wichtigsten Infos auf einen
Blick hat.

Sortierreihenfolge

Es wird jetzt zuerst nach Alphabet, dann gegen das Alphabet sortiert.

Banktransactions

Verbuchte Beträge werden jetzt in der BankTransaction gespeichert.

Sortierung auf DB-Ebene, falls möglich

Anzeige von verbuchten Beträgen der BankTransactions

Kleinerer Bug

Ein paar Debug-Statements entfernt

Verknüpfte Rechnungen im BankTransaction-Bericht anzeigen.

Kontenabgleich

Erste Schritte zum Kontenabgleich.

Kontenabgleich funktioniert schon ganz gut.

TODO: nochmal Funktionen checken
TODO: Filter hinzufügen

Kontenabgleich

Filter für BT und PR im Kontenabgleich.

TODO: Datumsfilter für beide gemeinsam umschreiben und Bilanzierung anzeigen.

Kontenabgleich übergreifender Datumsfilter

Das transdate wird jetzt auch übergreifend für Bankbewegungen und
verbuchte Zahlungen gesetzt.

TODO: Nach Änderung dieser Daten sollten die Tabellen neugeladen
und alle Teilfilter zurück auf 0 gesetzt werden.

Kontenabgleich - ein paar Sachen ausprobiert

Ist nur zum weitermachen (alle Änderungen nur Tests).

Kontenabgleich Kleiner Bug in Search

Kontenabgleich - Erste Übersicht

Kontenabgleich Anzeige von abgeglichenen Buchungen mit Bankbuchungen
funktioniert schonmal

Nächstes: Filter.

Kontenabgleich Filtern ist jetzt in der Übersicht möglich.

Next: Spalte reconciliation_link durch group oder so ersetzen.

Kontenabgleich In rec_group in reconciliation_links

In der Tabelle reconciliation_links werden jetzt keine ids mehr auf
reconciliation_links gespeichert. Stattdessen erkennt man an der
rec_group, welche Zeilen zusammengehören.

Kontenabgleich Berechnung von Summen

Jetzt werden Summen von Bankbewegungen und cleared payments angezeigt.

Next: Anhaken und abgleichen implementieren.

Kontenabgleich Checkboxen fügen Elemente zur Tabelle

Es gibt jetzt Checkboxen neben BT's und BB's. Wenn man sie anhakt,
wird die BT bzw. die BB in eine Tabelle zum abgleichen gesteckt.

TODO: Button zum abgleichen programmieren.

Kontenabgleich Man kann jetzt auch im Report abgleichen

Es fehlt noch: Abbruch-Action, falls beim Abgleichen etwas fehlerhaft ist.

Kontenabgleich Manager für ReconciliationLink

Wurde vergessen zu committen

Kontenabgleich Vorzeichenfehler bei AccTransactions behoben.

In der Anzeige muss das Vorzeichen von AccTransactions bei Buchungen
auf Bank geändert werden.

Kontenabgleich Code aufräumen und Sortierung nach Datum

Es wird jetzt immer nach Datum sortiert. Weiterhin wurde im Code
eine sub von actions nach helpers geschoben.

Kontenabgleich Abbruch nach Fehlern beim Abgleichen

Wenn beim Abgleichen Fehler auftreten, wird man jetzt auf die Über-
sichtsseite geleitet.

Kontenabgleich/BankTransactions Upgrade-Script für Tabellen anpassen

Einige Änderungen der Tabellen sind in den Scripten jetzt enthalten.

Kontenabgleich Farbliche Hinterlegung und Entfernung von Debug-Code

Nicht zugewiesene BankTransactions und Buchungen auf Bankkonten
werden im Kontenabgleich jetzt rot hinterlegt.

Weiterhin wurden noch Debug-Statements entfernt.

TODO: Erweiterung auf andere css Klassen (nicht nur kivitendo, sondern
auch mobile/alte lx-office-styles etc...)

Kontenabgleich Behebt Bug

Unter gewissen Umständen wurden nach der Filterung noch alte Daten
beibehalten. Jetzt wird alles erneuert.

Kontenabgleich Filter für cleared

Man kann jetzt in der Übersicht auch nach cleared und uncleared filtern.

Kontenabgleich Erste Schritte für Automatischen Abgleich

Bisher werden Vorschläge nur dargestellt.

TODO: Button 'Abgleichen' für Vorschläge programmieren.

Kontenabgleich Vorschläge können jetzt abgeglichen werden

Vorschläge können jetzt auch automatisch abgeglichen werden, wenn
man sie anhakt und danach auf abgleichen klickt.

Kontenabgleich Anzeige von Reference

Es gibt jetzt einen Link im Kontenabgleich auf ar/ap/gl.

Kontenabgleich Kunden-/Lieferantennamen

Kunden- und Lieferantennamen werden jetzt für AccTransactions an-
gezeigt. Im Falle einer Dialogbuchung erscheint ihre Beschreibung.

Kontenabgleich Untersortierung nach Betrag

Bisher wurde nur nach Datum sortiert. Innerhalb eines Datums wird
jetzt zusätzlich nach Betrag sortiert.

Kontenabgleich/BankTransactions Entfernung Debug-Statements

Kontenabgleich BankTransactions als verbucht markieren

BankTransactions werden jetzt als verbucht markiert, wenn sie abge-
glichen sind. Ansonsten wurde noch ein kleiner Syntax-Fehler behoben.

Kontenabgleich Bilanz über alle Buchungen berechnen

Die Bilanz wird jetzt unabhängig vom Filter sowohl für cleared als
auch uncleared berechnet. Weiterhin wurde noch ein Vorzeichenfehler
in der Bilanz für Bankbewegungen behoben und der Code etwas verschoben.

Kontenabgleich Verlinkungen aufheben

Man kann jetzt auch Verlinkungen nach dem Abgleichen aufheben.

Kontenabgleich Code-Formatierung und kleine Verbesserung in der Anzeige

Formatierung von Code wurde geändert, sowie einige kleine Besserungen
in der Anzeige (zum Beispiel sind Beträge jetzt rechts orientiert
in der Tabellenzeile).

Kontenabgleich Tabellenhöhe mit relativer Größe

Die Tabellenhöhe hängt jetzt relativ von der Größe des Bildschirms
ab anstatt von einer festen Pixel-Anzahl.

Kontenabgleich Ok message für Flash eingebaut

Kontenabgleich gehört noch zum Flash-message-Commit

Kontenabgleich Zusammenführen verschiedener Abgleichmöglichkeiten

Bisher wurden verschiedene Methoden implementiert, den Kontenabgleich
zu machen. In diesem Commit werden zwei verschiedene Möglichkeiten
unter einen Hut gebracht. Es ist auf der erstellten Seite auch ohne
weiteres Möglich weitere Möglichkeiten hinzuzufügen.

Kontenabgleich Anzeige von Overview umbauen

Die Anzeige von Overview wurde verändert, so dass man jetzt noch
schneller abgleichen kann.

TODO: Anzeige von Proposals der Anzeige von Overview angleichen.

Kontenabgleich Behebt Syntaxfehler

Kontenabgleich Umgang mit Stornos ändern

Der Umgang mit Stornos wurde geändert. Statt Stornos nicht anzuzeigen,
gibt es jetzt einen Filter dafür. Der Saldo von BBs und BTs errechnet
sich jetzt nur noch aus den gefilterten Objekten.

Weiterhin gibt es jetzt eine onchange-Action auf den Datumsfeldern
im Filter und der Filter-Button wird nicht mehr angezeigt.

Kontenabgleich Anpassung der proposals an neue Ansicht

Automatische Vorschläge werden jetzt auch in der neuen Darstellung
angezeigt.

Kontenabgleich Mastercheckbox wieder da und Spaltenreihenfolge vertauscht

Die Checkbox, bei der man alle Vorschläge an-/abhaken kann, wird
jetzt wieder angezeigt. Weiterhin wird jetzt auch der Betrag und
das Belegdatum weiter vorne angezeigt.

Kontenabgleich Saldo in der richtigen Spalte

Der Saldo wird jetzt in der richtigen Spalte angezeigt.

Kontenabgleich Buchungen außerhalb des Filters ausgrauen

Bisher kam es vor, dass Buchungen, die in einen Zeitraum außerhalb
des Filters fallen (weil ihre Gegenbuchung in den gefilterten Zeitraum
fällt), trotzdem angezeigt wurden, aber nicht in der
Summe mitgerechnet wurden. Solche Buchungen werden jetzt nur noch
in grauer Schrift angezeigt.

Kontenabgleich Abgeglichene Buchungen besser Filtern

Es kam bisher vor, dass abgeglichene Buchungen, bei denen eine Buchung
nach dem gefilterten Zeitraum un eine Buchung vor dem gefilterten
Zeitraum lag, angezeigt wurden. Dabei war es bisher nicht erforderlich,
dass eine Buchung im gefilterten Zeitraum lag. Jetzt muss mindestens
eine Buchung im gefilterten Zeitraum liegen, damit die abgeglichenen
Buchungen auch angezeigt werden.

Kontenabgleich Absolute Bilanz anzeigen

Jetzt wird auch immer die Summe von BB's und BT's von Beginn der
Buchungen bis zum "Todate" angezeigt (inklusive Stornos).

Banktransactions nach Datum filtern

Man kann jetzt Bankbewegungen nach Datum filtern. Weiterhin funktioniert
jetzt auch der Callback, nachdem man eine Debitorenbuchung erstellt.

Banktransactions: Datumsfilter nach Sortierung beibehalten

Bisher ging der Datumsfilter nach der Sortierung verloren, jetzt
wird er beibehalten.

Kontenabgleich Mehr Vorschläge machen

Bisher wurden nur Vorschläge gemacht, wenn Rechnungen via Bankbewegungen
bezahlt wurden. Jetzt werden auch Vorschläge gemacht, wenn Beträge
deckungsgleich sind und Kontoverbindung von Kunde/Lieferant und
Bankbeleg übereinstimmen.

Kontenabgleich Reconciliate-Button taucht nicht auf

Behebt einen Bug, bei dem der Abgleichen-Knopf nicht auftaucht,
obwohl er das sollte. Das Problem lag daran, dass die beiden Zahlen
6.286,18 und -6.286,18 aufaddiert in Perl nicht Null ergaben.

Kontenabgleich Fügt mehr Proposals hinzu

Auf diese Weise werden noch mehr Übereinstimmungen gefunden.

Banktransactions Teilzahlungen funktionieren jetzt besser

Bisher haben Teilzahlungen zwar funktioniert, jedoch tauchten die
Bankbewegungen, mit denen sie erstellt wurden immer wieder in der
Liste auf. Es lag daran, dass invoice_amount in der Tabelle
bank_transactions falsch gesetzt wurde.

Banktransactions 40 statt 5 Bankbewegungen pro Seite anzeigen

Kontenabgleich Entfernen von Tests

Entfernt alten Code, der die ersten Tests enthielt.

Kontenabgleich Umbenennung von Controller

Der Controller SL/Controller/Reconciliation_3.pm wird umbenannt in
SL/Controller/Reconciliation.pm

Kontenabgleich Umbenennung von Ordner whole_reconciliation

Der Order whole_reconciliation wurde in reconciliation umbenannt.

Banktransactions Minuspunkte für transdate vergeben

Wenn eine Rechnung nicht 30 Tage vor der Bankbewegung liegt, so
wird jetzt ein Minuspunkt für die Vorschläge vergeben.

Kontenabgleich/Banktransaction Rechte hinzufügen

Bank CSV Import - Purpose zusammengefügt

Icons bei Reconciliation

Kontenabgleich Icons in Vorschlägen übernehmen

Icons werden jetzt auch bei Vorschlägen benutzt. Weiterhin wurde
unsinniges Attribut bei Icons im Overview entfernt.

Kontenabgleich bei Import Standard-Währung setzen

Beim Import wird jetzt die Standard-Währung eingetragen, wenn keine
andere Währung vorhanden ist. Weiterhin ist die Währung jetzt auch ein
Pflichtfeld durch ein NOT NULL-Constraint.

Kontenabgleich Spalte in Summenzeile ergänzen

Aufgrund der neu hinzugekommenen Icons musste noch eine Spalte in
der Zeile eingefügt werden, wo die Summen angezeigt werden.

Banktransaction Betrag im Filter parsen

Beim Suchen von Rechnungen im "Rechnung hinzufügen"-Modus wurde der
Betrag im Filter nicht geparst. Man musste bisher also immer einen
Punkt statt einem Komma eingeben.

Kontenabgleich CSS verbessern

Bisher konnte man nicht bis an den unteren Bildschirmrand scrollen.
Dieser Commit versucht dies zu beheben. Allerdings ist es unklar,
ob das Problem durch den Commit behoben ist.

Banktransactions Automatisches bezahlen von Vorschlägen

Banktransactions Speichern von Vorschlägen

Automatische Vorschläge, die kivitendo schon macht, können jetzt
auch benutzt werden, um vorgeschlagene Rechnungen direkt zu speichern.

Banktransactions Bugfix

Bisher wurden der "Rechnung speichern"-Button und der "Save proposals"-
Button nur getogglet. Das hat dazu geführt, dass wenn man zweimal
auf den Reiter "Proposals" drückt, der Rechnung speichern-Butten
angezeigt wurde, obwohl der Save proposals-Button angezeigt werden
musste. Jetzt werden die Buttons versteckt und angezeigt, was den
Fehler behebt.

Banktransactions - kein von und bis wenn leer

Die Wörter "von" und "bis" nur anzeigen, wenn auch ein von- oder
bis-Datum gesetzt ist.

Bankbewegungen - in Tooltip Tagesdelta anzeigen

Anzahl der Tage zwischen (vorgeschlagenem) Rechnungsdatum und
Bankeingangsdatum wird in Klammern hinter dem Bankdatum angezeigt.

Banktransactions - bei Proposals trotz sub-cent Matchen

Übereinstimmung muß nicht genau sein, sondern kleiner 1 Cent.
Wegen Rundungsproblematik.

String-Vergleich bei Banktransactions - mind. 3 Zeichen

Mindestlänge für Wortvergleich.

testing - agreement modifying tests

Banktransactions Belegdatum bei Rechnung zuweisen

Wenn man auf Rechnung zuweisen klickt, wird jetzt sowohl von dem
Bankbeleg als auch von den Rechnungen das Belegdatum angezeigt.
Weiterhin wurde ein Filter für das Datum hinzugefügt.

Kontenabgleich/Banktransactions

Reiter 'Set cleared entfernen' im Kontenabgleich.

Bei Vorgeschlagenen Rechnungen anzeigen, ob EK oder VK.

Deutsche Übersetzungen

VERSION angepasst

MT940 Importer der aqbanking-cli über CSV-Import aufruft

Noch alles hartkodiert
Kein Dublettencheck

MT940 Importer der aqbanking-cli über CSV-Import aufruft

Noch alles hartkodiert
Kein Dublettencheck

Bank - in Bankkontodropdowns Kontoname berücksichtigen

Bankerweiterung - Offener Betrag bei Rechnungsfilter

wenn man aus Bankbuchungen eine Rechnung zuweisen möchte.

RB - corrected all after rebase

RB - GLTransaction.pm nach Rebase gefixed

Unterschiede anzeigen:

SL/Auth.pm
["general_ledger", $locale->text("Transactions, AR transactions, AP transactions")],
["datev_export", $locale->text("DATEV Export")],
["cash", $locale->text("Receipt, payment, reconciliation")],
["bank_transaction", $locale->text("Bank transactions")],
["--reports", $locale->text('Reports')],
["report", $locale->text('All reports')],
["advance_turnover_tax_return", $locale->text('Advance turnover tax return')],
SL/Controller/BankTransaction.pm
package SL::Controller::BankTransaction;
# idee- möglichkeit bankdaten zu übernehmen in stammdaten
# erst Kontenabgleich, um alle gl-Einträge wegzuhaben
use strict;
use parent qw(SL::Controller::Base);
use SL::Controller::Helper::GetModels;
use SL::Controller::Helper::ReportGenerator;
use SL::ReportGenerator;
use SL::DB::BankTransaction;
use SL::Helper::Flash;
use SL::Locale::String;
use SL::SEPA;
use SL::DB::Invoice;
use SL::DB::PurchaseInvoice;
use SL::DB::RecordLink;
use SL::JSON;
use SL::DB::Chart;
use SL::DB::AccTransaction;
use SL::DB::Tax;
use SL::DB::Draft;
use SL::DB::BankAccount;
use Rose::Object::MakeMethods::Generic
(
'scalar --get_set_init' => [ qw(models) ],
);
__PACKAGE__->run_before('check_auth');
#
# actions
#
sub action_search {
my ($self) = @_;
my $bank_accounts = SL::DB::Manager::BankAccount->get_all();
$self->render('bank_transactions/search',
label_sub => sub { t8('#1 - Account number #2, bank code #3, #4', $_[0]->name, $_[0]->account_number, $_[0]->bank_code, $_[0]->bank, )},
BANK_ACCOUNTS => $bank_accounts);
}
sub action_list_all {
my ($self) = @_;
my $transactions = $self->models->get;
$self->make_filter_summary;
$self->prepare_report;
$self->report_generator_list_objects(report => $self->{report}, objects => $transactions);
}
sub action_list {
my ($self) = @_;
if (!$::form->{filter}{bank_account}) {
flash('error', t8('No bank account chosen!'));
$self->action_search;
return;
}
my $sort_by = $::form->{sort_by} || 'transdate';
$sort_by = 'transdate' if $sort_by eq 'proposal';
$sort_by .= $::form->{sort_dir} ? ' DESC' : ' ASC';
my $fromdate = $::locale->parse_date_to_object(\%::myconfig, $::form->{filter}->{fromdate});
my $todate = $::locale->parse_date_to_object(\%::myconfig, $::form->{filter}->{todate});
$todate->add( days => 1 ) if $todate;
my @where = ();
push @where, (transdate => { ge => $fromdate }) if ($fromdate);
push @where, (transdate => { lt => $todate }) if ($todate);
my $bank_transactions = SL::DB::Manager::BankTransaction->get_all(where => [ amount => {ne => \'invoice_amount'},
local_bank_account_id => $::form->{filter}{bank_account},
@where ],
with_objects => [ 'local_bank_account', 'currency' ],
sort_by => $sort_by, limit => 10000);
my $all_open_ar_invoices = SL::DB::Manager::Invoice->get_all(where => [amount => { gt => \'paid' }], with_objects => 'customer');
my $all_open_ap_invoices = SL::DB::Manager::PurchaseInvoice->get_all(where => [amount => { gt => \'paid' }], with_objects => 'vendor');
my @all_open_invoices;
push @all_open_invoices, @{ $all_open_ar_invoices };
push @all_open_invoices, @{ $all_open_ap_invoices };
foreach my $bt (@{ $bank_transactions }) {
next unless $bt->{remote_name}; # bank has no name, usually fees, use create invoice to assign
foreach my $open_invoice (@all_open_invoices){
$open_invoice->{agreement} = 0;
#compare banking arrangements
my ($bank_code, $account_number);
$bank_code = $open_invoice->customer->bank_code if $open_invoice->is_sales;
$account_number = $open_invoice->customer->account_number if $open_invoice->is_sales;
$bank_code = $open_invoice->vendor->bank_code if ! $open_invoice->is_sales;
$account_number = $open_invoice->vendor->account_number if ! $open_invoice->is_sales;
($bank_code eq $bt->remote_bank_code
&& $account_number eq $bt->remote_account_number) ? ($open_invoice->{agreement} += 2) : ();
my $datediff = $bt->transdate->{utc_rd_days} - $open_invoice->transdate->{utc_rd_days};
$open_invoice->{datediff} = $datediff;
#compare amount
# (abs($open_invoice->amount) == abs($bt->amount)) ? ($open_invoice->{agreement} += 2) : ();
# do we need double abs here?
(abs(abs($open_invoice->amount) - abs($bt->amount)) < 0.01) ? ($open_invoice->{agreement} += 4) : ();
#search invoice number in purpose
my $invnumber = $open_invoice->invnumber;
# possible improvement: match has to have more than 1 character?
$bt->purpose =~ /\b$invnumber\b/i ? ($open_invoice->{agreement} += 2) : ();
#check sign
if ( $open_invoice->is_sales && $bt->amount < 0 ) {
$open_invoice->{agreement} -= 1;
};
if ( ! $open_invoice->is_sales && $bt->amount > 0 ) {
$open_invoice->{agreement} -= 1;
};
#search customer/vendor number in purpose
my $cvnumber;
$cvnumber = $open_invoice->customer->customernumber if $open_invoice->is_sales;
$cvnumber = $open_invoice->vendor->vendornumber if ! $open_invoice->is_sales;
$bt->purpose =~ /\b$cvnumber\b/i ? ($open_invoice->{agreement}++) : ();
#compare customer/vendor name and account holder
my $cvname;
$cvname = $open_invoice->customer->name if $open_invoice->is_sales;
$cvname = $open_invoice->vendor->name if ! $open_invoice->is_sales;
$bt->remote_name =~ /\b$cvname\b/i ? ($open_invoice->{agreement}++) : ();
#Compare transdate of bank_transaction with transdate of invoice
#Check if words in remote_name appear in cvname
$open_invoice->{agreement} += &check_string($bt->remote_name,$cvname);
$open_invoice->{agreement} -= 1 if $datediff < -5; # dies hebelt eventuell Vorkasse aus
$open_invoice->{agreement} += 1 if $datediff < 30; # dies hebelt eventuell Vorkasse aus
# only if we already have a good agreement, let date further change value of agreement.
# this is so that if there are several open invoices which are all equal (rent jan, rent feb...) the one with the best date match is chose over the others
# another way around this is to just pre-filter by periods instead of matching everything
if ( $open_invoice->{agreement} > 5 ) {
if ( $datediff == 0 ) {
$open_invoice->{agreement} += 3;
} elsif ( $datediff > 0 and $datediff <= 14 ) {
$open_invoice->{agreement} += 2;
} elsif ( $datediff >14 and $datediff < 35) {
$open_invoice->{agreement} += 1;
} elsif ( $datediff >34 and $datediff < 120) {
$open_invoice->{agreement} += 1;
} elsif ( $datediff < 0 ) {
$open_invoice->{agreement} -= 1;
} else {
# e.g. datediff > 120
};
};
#if ($open_invoice->transdate->{utc_rd_days} == $bt->transdate->{utc_rd_days}) {
#$open_invoice->{agreement} += 4;
#print FH "found matching date for invoice " . $open_invoice->invnumber . " ( " . $bt->transdate->{utc_rd_days} . " . \n";
#} elsif (($open_invoice->transdate->{utc_rd_days} + 30) < $bt->transdate->{utc_rd_days}) {
#$open_invoice->{agreement} -= 1;
#} else {
#$open_invoice->{agreement} -= 2;
#print FH "found nomatch date -2 for invoice " . $open_invoice->invnumber . " ( " . $bt->transdate->{utc_rd_days} . " . \n";
#};
#print FH "agreement after date_agreement: " . $open_invoice->{agreement} . "\n";
}
# finished going through all open_invoices
# go through each bt
# for each open_invoice try to match it to each open_invoice and store agreement in $open_invoice->{agreement} (which gets overwritten each time for each bt)
# calculate
#
$bt->{proposals} = [];
my $agreement = 11;
# wird nie ausgeführt, bzw. nur ganz am Ende
# oder einmal am Anfang?
# es werden maximal 7 vorschläge gemacht?
# 7 mal wird geprüft, ob etwas passt
while (scalar @{ $bt->{proposals} } < 1 && $agreement-- > 0) {
$bt->{proposals} = [ grep { $_->{agreement} > $agreement } @all_open_invoices ];
#Kann wahrscheinlich weg:
# map { $_->{style} = "green" } @{ $bt->{proposals} } if $agreement >= 5;
# map { $_->{style} = "orange" } @{ $bt->{proposals} } if $agreement < 5 and $agreement >= 3;
# map { $_->{style} = "red" } @{ $bt->{proposals} } if $agreement < 3;
$bt->{agreement} = $agreement; # agreement value at cutoff, will correspond to several results if threshold is 7 and several are already above 7
}
} # finished one bt
# finished all bt
# separate filter for proposals (second tab, agreement >= 5 and exactly one match)
# to qualify as a proposal there has to be
# * agreement >= 5
# * there must be only one exact match
# * depending on whether sales or purchase the amount has to have the correct sign (so Gutschriften don't work?)
my @proposals = grep { $_->{agreement} >= 5
and 1 == scalar @{ $_->{proposals} }
and (@{ $_->{proposals} }[0]->is_sales ? abs(@{ $_->{proposals} }[0]->amount - $_->amount) < 0.01 : abs(@{ $_->{proposals} }[0]->amount + $_->amount) < 0.01) } @{ $bank_transactions };
#Sort bank transactions by quality of proposal
$bank_transactions = [ sort { $a->{agreement} <=> $b->{agreement} } @{ $bank_transactions } ] if $::form->{sort_by} eq 'proposal' and $::form->{sort_dir} == 1;
$bank_transactions = [ sort { $b->{agreement} <=> $a->{agreement} } @{ $bank_transactions } ] if $::form->{sort_by} eq 'proposal' and $::form->{sort_dir} == 0;
$self->render('bank_transactions/list',
title => t8('List of bank transactions'),
BANK_TRANSACTIONS => $bank_transactions,
PROPOSALS => \@proposals,
bank_account => SL::DB::Manager::BankAccount->find_by(id => $::form->{filter}{bank_account}) );
}
sub check_string {
my $bankstring = shift;
my $namestring = shift;
return 0 unless $bankstring and $namestring;
my @bankwords = grep(/^\w+$/, split(/\b/,$bankstring));
my $match = 0;
foreach my $bankword ( @bankwords ) {
# only try to match strings with more than 2 characters
next unless length($bankword)>2;
if ( $namestring =~ /\b$bankword\b/i ) {
$match++;
};
};
return $match;
};
sub action_assign_invoice {
my ($self) = @_;
$self->{transaction} = SL::DB::Manager::BankTransaction->find_by(id => $::form->{bt_id});
$self->render('bank_transactions/assign_invoice', { layout => 0 },
title => t8('Assign invoice'),);
}
sub action_create_invoice {
my ($self) = @_;
my %myconfig = %main::myconfig;
$self->{transaction} = SL::DB::Manager::BankTransaction->find_by(id => $::form->{bt_id});
my $vendor_of_transaction = SL::DB::Manager::Vendor->find_by(account_number => $self->{transaction}->{remote_account_number});
my $drafts = SL::DB::Manager::Draft->get_all(where => [ module => 'ap'] , with_objects => 'employee');
my @filtered_drafts;
foreach my $draft ( @{ $drafts } ) {
my $draft_as_object = YAML::Load($draft->form);
my $vendor = SL::DB::Manager::Vendor->find_by(id => $draft_as_object->{vendor_id});
$draft->{vendor} = $vendor->name;
$draft->{vendor_id} = $vendor->id;
push @filtered_drafts, $draft;
}
#Filter drafts
@filtered_drafts = grep { $_->{vendor_id} == $vendor_of_transaction->id } @filtered_drafts if $vendor_of_transaction;
my $all_vendors = SL::DB::Manager::Vendor->get_all();
$self->render('bank_transactions/create_invoice', { layout => 0 },
title => t8('Create invoice'),
DRAFTS => \@filtered_drafts,
vendor_id => $vendor_of_transaction ? $vendor_of_transaction->id : undef,
vendor_name => $vendor_of_transaction ? $vendor_of_transaction->name : undef,
ALL_VENDORS => $all_vendors,
limit => $myconfig{vclimit},
callback => $self->url_for(action => 'list',
'filter.bank_account' => $::form->{filter}->{bank_account},
'filter.todate' => $::form->{filter}->{todate},
'filter.fromdate' => $::form->{filter}->{fromdate}),
);
}
sub action_filter_drafts {
my ($self) = @_;
$self->{transaction} = SL::DB::Manager::BankTransaction->find_by(id => $::form->{bt_id});
my $vendor_of_transaction = SL::DB::Manager::Vendor->find_by(account_number => $self->{transaction}->{remote_account_number});
my $drafts = SL::DB::Manager::Draft->get_all(with_objects => 'employee');
my @filtered_drafts;
foreach my $draft ( @{ $drafts } ) {
my $draft_as_object = YAML::Load($draft->form);
my $vendor = SL::DB::Manager::Vendor->find_by(id => $draft_as_object->{vendor_id});
$draft->{vendor} = $vendor->name;
$draft->{vendor_id} = $vendor->id;
push @filtered_drafts, $draft;
}
my $vendor_name = $::form->{vendor};
my $vendor_id = $::form->{vendor_id};
#Filter drafts
@filtered_drafts = grep { $_->{vendor_id} == $vendor_id } @filtered_drafts if $vendor_id;
@filtered_drafts = grep { $_->{vendor} =~ /$vendor_name/i } @filtered_drafts if $vendor_name;
my $output = $self->render(
'bank_transactions/filter_drafts',
{ output => 0 },
DRAFTS => \@filtered_drafts,
);
my %result = ( count => 0, html => $output );
$self->render(\to_json(\%result), { type => 'json', process => 0 });
}
sub action_ajax_add_list {
my ($self) = @_;
my @where_sale = (amount => { ne => \'paid' });
my @where_purchase = (amount => { ne => \'paid' });
if ($::form->{invnumber}) {
push @where_sale, (invnumber => { ilike => '%' . $::form->{invnumber} . '%'});
push @where_purchase, (invnumber => { ilike => '%' . $::form->{invnumber} . '%'});
}
if ($::form->{amount}) {
push @where_sale, (amount => $::form->parse_amount(\%::myconfig, $::form->{amount}));
push @where_purchase, (amount => $::form->parse_amount(\%::myconfig, $::form->{amount}));
}
if ($::form->{vcnumber}) {
push @where_sale, ('customer.customernumber' => { ilike => '%' . $::form->{vcnumber} . '%'});
push @where_purchase, ('vendor.vendornumber' => { ilike => '%' . $::form->{vcnumber} . '%'});
}
if ($::form->{vcname}) {
push @where_sale, ('customer.name' => { ilike => '%' . $::form->{vcname} . '%'});
push @where_purchase, ('vendor.name' => { ilike => '%' . $::form->{vcname} . '%'});
}
if ($::form->{transdatefrom}) {
my $fromdate = $::locale->parse_date_to_object(\%::myconfig, $::form->{transdatefrom});
push @where_sale, ('transdate' => { ge => $fromdate});
push @where_purchase, ('transdate' => { ge => $fromdate});
}
if ($::form->{transdateto}) {
my $todate = $::locale->parse_date_to_object(\%::myconfig, $::form->{transdateto});
$todate->add(days => 1);
push @where_sale, ('transdate' => { lt => $todate});
push @where_purchase, ('transdate' => { lt => $todate});
}
my $all_open_ar_invoices = SL::DB::Manager::Invoice->get_all(where => \@where_sale, with_objects => 'customer');
my $all_open_ap_invoices = SL::DB::Manager::PurchaseInvoice->get_all(where => \@where_purchase, with_objects => 'vendor');
my @all_open_invoices;
push @all_open_invoices, @{ $all_open_ar_invoices };
push @all_open_invoices, @{ $all_open_ap_invoices };
@all_open_invoices = sort { $a->id <=> $b->id } @all_open_invoices;
#my $all_open_invoices = SL::DB::Manager::Invoice->get_all(where => \@where);
my $output = $self->render(
'bank_transactions/add_list',
{ output => 0 },
INVOICES => \@all_open_invoices,
);
my %result = ( count => 0, html => $output );
$self->render(\to_json(\%result), { type => 'json', process => 0 });
}
sub action_ajax_accept_invoices {
my ($self) = @_;
my @selected_invoices;
foreach my $invoice_id (@{ $::form->{invoice_id} || [] }) {
my $invoice_object = SL::DB::Manager::Invoice->find_by(id => $invoice_id);
$invoice_object ||= SL::DB::Manager::PurchaseInvoice->find_by(id => $invoice_id);
push @selected_invoices, $invoice_object;
}
$self->render('bank_transactions/invoices', { layout => 0 },
INVOICES => \@selected_invoices,
bt_id => $::form->{bt_id} );
}
sub action_save_invoices {
my ($self) = @_;
my $invoice_hash = delete $::form->{invoice_ids};
while ( my ($bt_id, $invoice_ids) = each(%$invoice_hash) ) {
my $bank_transaction = SL::DB::Manager::BankTransaction->find_by(id => $bt_id);
my $sign = $bank_transaction->amount < 0 ? -1 : 1;
my $amount_of_transaction = $sign * $bank_transaction->amount;
my @invoices;
foreach my $invoice_id (@{ $invoice_ids }) {
push @invoices, (SL::DB::Manager::Invoice->find_by(id => $invoice_id) || SL::DB::Manager::PurchaseInvoice->find_by(id => $invoice_id));
}
@invoices = sort { return 1 if ($a->is_sales and $a->amount > 0);
return 1 if (!$a->is_sales and $a->amount < 0);
return -1; } @invoices if $bank_transaction->amount > 0;
@invoices = sort { return -1 if ($a->is_sales and $a->amount > 0);
return -1 if (!$a->is_sales and $a->amount < 0);
return 1; } @invoices if $bank_transaction->amount < 0;
foreach my $invoice (@invoices) {
if ($amount_of_transaction == 0) {
flash('warning', $::locale->text('There are invoices which could not be payed by bank transaction #1 (Account number: #2, bank code: #3)!',
$bank_transaction->purpose,
$bank_transaction->remote_account_number,
$bank_transaction->remote_bank_code));
last;
}
#pay invoice or go to the next bank transaction if the amount is not sufficiently high
if ($invoice->amount <= $amount_of_transaction) {
$invoice->pay_invoice(chart_id => $bank_transaction->local_bank_account->chart_id, trans_id => $invoice->id, amount => $invoice->amount, transdate => $bank_transaction->transdate);
if ($invoice->is_sales) {
$amount_of_transaction -= $sign * $invoice->amount;
$bank_transaction->invoice_amount($bank_transaction->invoice_amount + $invoice->amount);
} else {
$amount_of_transaction += $sign * $invoice->amount if (!$invoice->is_sales);
$bank_transaction->invoice_amount($bank_transaction->invoice_amount - $invoice->amount);
}
} else {
$invoice->pay_invoice(chart_id => $bank_transaction->local_bank_account->chart_id, trans_id => $invoice->id, amount => $amount_of_transaction, transdate => $bank_transaction->transdate);
$bank_transaction->invoice_amount($bank_transaction->amount) if $invoice->is_sales;
$bank_transaction->invoice_amount($bank_transaction->amount) if !$invoice->is_sales;
$amount_of_transaction = 0;
}
#Record a link from the bank transaction to the invoice
my @props = (
from_table => 'bank_transactions',
from_id => $bt_id,
to_table => $invoice->is_sales ? 'ar' : 'ap',
to_id => $invoice->id,
);
my $existing = SL::DB::Manager::RecordLink->get_all(where => \@props, limit => 1)->[0];
SL::DB::RecordLink->new(@props)->save if !$existing;
}
$bank_transaction->save;
}
$self->action_list();
}
sub action_save_proposals {
my ($self) = @_;
foreach my $bt_id (@{ $::form->{proposal_ids} }) {
#mark bt as booked
my $bt = SL::DB::Manager::BankTransaction->find_by(id => $bt_id);
$bt->invoice_amount($bt->amount);
$bt->save;
#pay invoice
my $arap = SL::DB::Manager::Invoice->find_by(id => $::form->{"proposed_invoice_$bt_id"});
$arap = SL::DB::Manager::PurchaseInvoice->find_by(id => $::form->{"proposed_invoice_$bt_id"}) if not defined $arap;
$arap->pay_invoice(chart_id => $bt->local_bank_account->chart_id,
trans_id => $arap->id,
amount => $arap->amount,
transdate => $bt->transdate);
$arap->save;
#create record link
my @props = (
from_table => 'bank_transactions',
from_id => $bt_id,
to_table => $arap->is_sales ? 'ar' : 'ap',
to_id => $arap->id,
);
my $existing = SL::DB::Manager::RecordLink->get_all(where => \@props, limit => 1)->[0];
SL::DB::RecordLink->new(@props)->save if !$existing;
}
flash('ok', t8('#1 proposal(s) saved.', scalar @{ $::form->{proposal_ids} }));
$self->action_list();
}
#
# filters
#
sub check_auth {
$::auth->assert('bank_transaction');
}
#
# helpers
#
sub make_filter_summary {
my ($self) = @_;
my $filter = $::form->{filter} || {};
my @filter_strings;
my @filters = (
[ $filter->{"transdate:date::ge"}, $::locale->text('Transdate') . " " . $::locale->text('From Date') ],
[ $filter->{"transdate:date::le"}, $::locale->text('Transdate') . " " . $::locale->text('To Date') ],
[ $filter->{"valutadate:date::ge"}, $::locale->text('Valutadate') . " " . $::locale->text('From Date') ],
[ $filter->{"valutadate:date::le"}, $::locale->text('Valutadate') . " " . $::locale->text('To Date') ],
[ $filter->{"amount:number"}, $::locale->text('Amount') ],
[ $filter->{"bank_account_id:integer"}, $::locale->text('Local bank account') ],
);
for (@filters) {
push @filter_strings, "$_->[1]: $_->[0]" if $_->[0];
}
$self->{filter_summary} = join ', ', @filter_strings;
}
sub prepare_report {
my ($self) = @_;
my $callback = $self->models->get_callback;
my $report = SL::ReportGenerator->new(\%::myconfig, $::form);
$self->{report} = $report;
my @columns = qw(transdate valudate remote_name remote_account_number remote_bank_code amount invoice_amount invoices currency purpose local_account_number local_bank_code id);
my @sortable = qw(transdate valudate remote_name remote_account_number remote_bank_code amount purpose local_account_number local_bank_code);
my %column_defs = (
transdate => { sub => sub { $_[0]->transdate_as_date } },
valutadate => { sub => sub { $_[0]->valutadate_as_date } },
remote_name => { },
remote_account_number => { },
remote_bank_code => { },
amount => { sub => sub { $_[0]->amount_as_number },
align => 'right' },
invoice_amount => { sub => sub { $_[0]->invoice_amount_as_number },
align => 'right' },
invoices => { sub => sub { $_[0]->linked_invoices } },
currency => { sub => sub { $_[0]->currency->name } },
purpose => { },
local_account_number => { sub => sub { $_[0]->local_bank_account->account_number } },
local_bank_code => { sub => sub { $_[0]->local_bank_account->bank_code } },
id => {},
);
map { $column_defs{$_}->{text} ||= $::locale->text( $self->models->get_sort_spec->{$_}->{title} ) } keys %column_defs;
$report->set_options(
std_column_visibility => 1,
controller_class => 'BankTransaction',
output_format => 'HTML',
top_info_text => $::locale->text('Bank transactions'),
title => $::locale->text('Bank transactions'),
allow_pdf_export => 1,
allow_csv_export => 1,
);
$report->set_columns(%column_defs);
$report->set_column_order(@columns);
$report->set_export_options(qw(list filter));
$report->set_options_from_form;
$self->models->disable_pagination if $report->{options}{output_format} =~ /^(pdf|csv)$/i;
$self->models->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable);
my $bank_accounts = SL::DB::Manager::BankAccount->get_all();
my $label_sub = sub { t8('#1 - Account number #2, bank code #3, #4', $_[0]->name, $_[0]->account_number, $_[0]->bank_code, $_[0]->bank )};
$report->set_options(
raw_top_info_text => $self->render('bank_transactions/report_top', { output => 0 }, BANK_ACCOUNTS => $bank_accounts, label_sub => $label_sub),
raw_bottom_info_text => $self->render('bank_transactions/report_bottom', { output => 0 }),
);
}
sub init_models {
my ($self) = @_;
SL::Controller::Helper::GetModels->new(
controller => $self,
sorted => {
_default => {
by => 'transdate',
dir => 1,
},
transdate => t8('Transdate'),
remote_name => t8('Remote name'),
amount => t8('Amount'),
invoice_amount => t8('Assigned'),
invoices => t8('Linked invoices'),
valutadate => t8('Valutadate'),
remote_account_number => t8('Remote account number'),
remote_bank_code => t8('Remote bank code'),
currency => t8('Currency'),
purpose => t8('Purpose'),
local_account_number => t8('Local account number'),
local_bank_code => t8('Local bank code'),
},
with_objects => [ 'local_bank_account', 'currency' ],
);
}
1;
SL/Controller/CsvImport.pm
use SL::Controller::CsvImport::Project;
use SL::Controller::CsvImport::Order;
use SL::JSON;
use SL::Controller::CsvImport::BankTransaction;
use SL::BackgroundJob::CsvImport;
use SL::System::TaskServer;
......
: $self->type eq 'inventories' ? $::locale->text('CSV import: inventories')
: $self->type eq 'projects' ? $::locale->text('CSV import: projects')
: $self->type eq 'orders' ? $::locale->text('CSV import: orders')
: $self->type eq 'bank_transactions' ? $::locale->text('CSV import: bank transactions')
: $self->type eq 'mt940' ? $::locale->text('CSV import: MT940')
: die;
if ($self->{type} eq 'customers_vendors' or $self->{type} eq 'orders' ) {
......
$self->profile_from_form;
if ($::form->{file}) {
if ( $::form->{file} && $::form->{FILENAME} =~ /\.940$/ ) {
my $mt940_file = SL::SessionFile->new($::form->{FILENAME}, mode => '>');
$mt940_file->fh->print($::form->{file});
$mt940_file->fh->close;
my $aqbin = '/usr/bin/aqbanking-cli';
my $cmd = "$aqbin --cfgdir=\"users\" import --importer=\"swift\" --profile=\"SWIFT-MT940\" -f " . $mt940_file->file_name . " | $aqbin --cfgdir=\"users\" listtrans --exporter=\"csv\" --profile=\"AqMoney2\" ";
my $converted_mt940;
open(MT, "$cmd |");
$converted_mt940 .= '"transaction_id";"local_bank_code";"local_account_number";"remote_bank_code";"remote_account_number";"transdate";"valutadate";"amount";"currency";"remote_name";"remote_name_1";"purpose";"purpose1";"purpose2";"purpose3";"purpose4";"purpose5";"purpose6";"purpose7";"purpose8";"purpose9";"purpose10";"purpose11"' . "\n";
my $headerline = <MT>; # discard original header line
while (<MT>) {
$converted_mt940 .= $_;
};
my $file = SL::SessionFile->new($self->csv_file_name, mode => '>');
$file->fh->print($::form->{file});
$file->fh->print($converted_mt940);
$file->fh->close;
} elsif ($::form->{file}) {
my $file = SL::SessionFile->new($self->csv_file_name, mode => '>');
$file->fh->print($::form->{file});
$file->fh->close;
}
my $file = SL::SessionFile->new($self->csv_file_name, mode => '<', encoding => $self->profile->get('charset'));
......
: $self->{type} eq 'inventories' ? SL::Controller::CsvImport::Inventory->new(@args)
: $self->{type} eq 'projects' ? SL::Controller::CsvImport::Project->new(@args)
: $self->{type} eq 'orders' ? SL::Controller::CsvImport::Order->new(@args)
: $self->{type} eq 'bank_transactions' ? SL::Controller::CsvImport::BankTransaction->new(@args)
: $self->{type} eq 'mt940' ? SL::Controller::CsvImport::BankTransaction->new(@args)
: die "Program logic error";
}
SL/Controller/CsvImport/BankTransaction.pm
package SL::Controller::CsvImport::BankTransaction;
use strict;
use SL::Helper::Csv;
use SL::Controller::CsvImport::Helper::Consistency;
use SL::DB::BankTransaction;
use Data::Dumper;
use parent qw(SL::Controller::CsvImport::Base);
use Rose::Object::MakeMethods::Generic
(
'scalar --get_set_init' => [ qw(table bank_accounts_by) ],
);
sub init_class {
my ($self) = @_;
$self->class('SL::DB::BankTransaction');
}
sub init_bank_accounts_by {
my ($self) = @_;
return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $self->all_bank_accounts } } ) } qw(id account_number) };
}
sub check_objects {
my ($self) = @_;
$self->controller->track_progress(phase => 'building data', progress => 0);
my $i;
my $num_data = scalar @{ $self->controller->data };
foreach my $entry (@{ $self->controller->data }) {
$self->controller->track_progress(progress => $i/$num_data * 100) if $i % 100 == 0;
$self->check_bank_account($entry);
$self->check_currency($entry, take_default => 1);
$self->join_purposes($entry);
#TODO: adde checks für die Variablen
} continue {
$i++;
}
$self->add_cvar_raw_data_columns;
}
sub setup_displayable_columns {
my ($self) = @_;
$self->SUPER::setup_displayable_columns;
$self->add_displayable_columns({ name => 'transaction_id', description => $::locale->text('Transaction ID') },
{ name => 'local_bank_code', description => $::locale->text('Own bank code') },
{ name => 'local_account_number', description => $::locale->text('Own bank account number') },
{ name => 'local_bank_account_id', description => $::locale->text('ID of own bank account') },
{ name => 'remote_bank_code', description => $::locale->text('Bank code of the goal/source') },
{ name => 'remote_account_number', description => $::locale->text('Account number of the goal/source') },
{ name => 'transdate', description => $::locale->text('Date of transaction') },
{ name => 'valutadate', description => $::locale->text('Valuta') },
{ name => 'amount', description => $::locale->text('Amount') },
{ name => 'currency', description => $::locale->text('Currency') },
{ name => 'currency_id', description => $::locale->text('Currency (database ID)') },
{ name => 'remote_name', description => $::locale->text('Name of the goal/source') },
{ name => 'remote_name_1', description => $::locale->text('Name of the goal/source') },
{ name => 'purpose', description => $::locale->text('Purpose') },
);
}
sub check_bank_account {
my ($self, $entry) = @_;
my $object = $entry->{object};
# Check whether or not local_bank_account ID is valid.
if ($object->local_bank_account_id && !$self->bank_accounts_by->{id}->{ $object->local_bank_account_id }) {
push @{ $entry->{errors} }, $::locale->text('Error: Invalid local bank account');
return 0;
}
# Check whether or not local_bank_account ID, local_account_number and local_bank_code are consistent.
if ($object->local_bank_account_id && $entry->{raw_data}->{local_account_number}) {
my $bank_account = $self->bank_accounts_by->{id}->{ $object->local_bank_account_id };
if ($bank_account->account_number ne $entry->{raw_data}->{local_account_number}) {
push @{ $entry->{errors} }, $::locale->text('Error: Invalid local bank account');
return 0;
}
if ($entry->{raw_data}->{local_bank_code} && $entry->{raw_data}->{local_bank_code} ne $bank_account->bank_code) {
push @{ $entry->{errors} }, $::locale->text('Error: Invalid local bank account');
return 0;
}
}
# Map account information to ID if given.
if (!$object->local_bank_account_id && $entry->{raw_data}->{local_account_number}) {
my $bank_account = $self->bank_accounts_by->{account_number}->{ $entry->{raw_data}->{local_account_number} };
if (!$bank_account) {
push @{ $entry->{errors} }, $::locale->text('Error: Invalid local bank account');
return 0;
}
if ($entry->{raw_data}->{local_bank_code} && $entry->{raw_data}->{local_bank_code} ne $bank_account->bank_code) {
push @{ $entry->{errors} }, $::locale->text('Error: Invalid local bank account');
return 0;
}
$object->local_bank_account_id($bank_account->id);
}
return $object->local_bank_account_id ? 1 : 0;
}
sub join_purposes {
my ($self, $entry) = @_;
my $object = $entry->{object};
my $purpose = join('', $entry->{raw_data}->{purpose},
$entry->{raw_data}->{purpose1},
$entry->{raw_data}->{purpose2},
$entry->{raw_data}->{purpose3},
$entry->{raw_data}->{purpose4},
$entry->{raw_data}->{purpose5},
$entry->{raw_data}->{purpose6},
$entry->{raw_data}->{purpose7},
$entry->{raw_data}->{purpose8},
$entry->{raw_data}->{purpose9},
$entry->{raw_data}->{purpose10},
$entry->{raw_data}->{purpose11} );
$object->purpose($purpose);
}
1;
SL/Controller/CsvImport/Base.pm
use List::MoreUtils qw(pairwise any);
use SL::Helper::Csv;
use SL::DB::BankAccount;
use SL::DB::Customer;
use SL::DB::Language;
use SL::DB::PaymentTerm;
......
use Rose::Object::MakeMethods::Generic
(
scalar => [ qw(controller file csv test_run save_with_cascade) ],
'scalar --get_set_init' => [ qw(profile displayable_columns existing_objects class manager_class cvar_columns all_cvar_configs all_languages payment_terms_by delivery_terms_by all_vc vc_by clone_methods) ],
'scalar --get_set_init' => [ qw(profile displayable_columns existing_objects class manager_class cvar_columns all_cvar_configs all_languages payment_terms_by delivery_terms_by all_bank_accounts all_vc vc_by clone_methods) ],
);
sub run {
......
return SL::DB::Manager::Language->get_all;
}
sub init_all_bank_accounts {
my ($self) = @_;
return SL::DB::Manager::BankAccount->get_all;
}
sub init_payment_terms_by {
my ($self) = @_;
SL/Controller/Helper/GetModels/Sorted.pm
use Carp;
use List::MoreUtils qw(uniq);
use Data::Dumper;
use Rose::Object::MakeMethods::Generic (
scalar => [ qw(by dir specs form_data) ],
'scalar --get_set_init' => [ qw(form_params) ],
SL/Controller/Project.pm
use SL::Helper::Flash;
use SL::Locale::String;
use Data::Dumper;
use Rose::Object::MakeMethods::Generic
(
scalar => [ qw(project linked_records) ],
......
my %params;
$params{CUSTOM_VARIABLES} = CVar->get_configs(module => 'Projects');
($params{CUSTOM_VARIABLES_FILTER_CODE}, $params{CUSTOM_VARIABLES_INCLUSION_CODE})
= CVar->render_search_options(variables => $params{CUSTOM_VARIABLES},
include_prefix => 'l_',
SL/Controller/Reconciliation.pm
package SL::Controller::Reconciliation;
use strict;
use parent qw(SL::Controller::Base);
use SL::Locale::String;
use SL::JSON;
use SL::Controller::Helper::ParseFilter;
use SL::Helper::Flash;
use SL::DB::BankTransaction;
use SL::DB::BankAccount;
use SL::DB::AccTransaction;
use SL::DB::ReconciliationLink;
use Rose::Object::MakeMethods::Generic (
'scalar --get_set_init' => [ qw(cleared BANK_ACCOUNTS) ],
);
__PACKAGE__->run_before('check_auth');
__PACKAGE__->run_before('_bank_account');
#
# actions
#
sub action_search {
my ($self) = @_;
$self->render('reconciliation/search',
label_sub => sub { t8('#1 - Account number #2, bank code #3, #4',
$_[0]->name,
$_[0]->bank,
$_[0]->account_number,
$_[0]->bank_code) });
}
sub action_reconciliation {
my ($self) = @_;
$self->_get_linked_transactions;
$self->_get_balances;
$self->render('reconciliation/form',
title => t8('Reconciliation'),
label_sub => sub { t8('#1 - Account number #2, bank code #3, #4',
$_[0]->name,
$_[0]->bank,
$_[0]->account_number,
$_[0]->bank_code) });
}
sub action_load_overview {
my ($self) = @_;
$self->_get_proposals;
$self->_get_linked_transactions;
$self->_get_balances;
... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.

Auch abrufbar als: Unified diff