X-Git-Url: http://wagnertech.de/gitweb/gitweb.cgi/mfinanz.git/blobdiff_plain/53593baa211863fbf66540cf1bcc36c8fb37257f..d8be5cc409de5b3bc34439599b1481201a5a1c2e:/SL/LiquidityProjection.pm diff --git a/SL/LiquidityProjection.pm b/SL/LiquidityProjection.pm index 5954e0056..0fd489d91 100644 --- a/SL/LiquidityProjection.pm +++ b/SL/LiquidityProjection.pm @@ -40,11 +40,12 @@ sub new { # Monat ihre Saldierungsperiode haben, außer Wartungsverträgen, die # für den jeweiligen Monat bereits abgerechnet wurden. # -# Diese Werte sollen zusätzlich optional nach Verkäufer(in) und nach -# Buchungsgruppe aufgeschlüsselt werden. +# Diese Werte sollen zusätzlich optional nach Verkäufer(in), +# Buchungsgruppe und Warengruppe aufgeschlüsselt werden. # # Diese Lösung geht deshalb immer über die Positionen der Belege -# (wegen der Buchungsgruppe) und berechnet die Summen daraus manuell. +# (wegen der Buchungsgruppen & Warengruppen) und berechnet die Summen +# daraus manuell. # # Alle Aufträge, deren Lieferdatum leer ist, oder deren Lieferdatum # vor dem aktuellen Monat liegt, werden in einer Kategorie 'alt' @@ -70,12 +71,14 @@ sub new { # Monat vorgemerkt. # # 4. Es werden für alle offenen Kundenaufträge die Positionen -# ausgelesen und mit Verkäufer(in), Buchungsgruppe verknüpft. Aus -# Menge, Einzelpreis und Zeilenrabatt wird die Zeilensumme berechnet. +# ausgelesen und mit Verkäufer(in), Buchungsgruppe, Warengruppe +# verknüpft. Aus Menge, Einzelpreis und Zeilenrabatt wird die +# Zeilensumme berechnet. # # 5. Mit den Informationen aus 3. und 4. werden Datenstrukturen # initialisiert, die für die Gesamtsummen, für alle Verkäufer(innen), -# für alle Buchungsgruppen, für alle Monate Werte enthalten. +# für alle Buchungsgruppen, für alle Warengruppen, für alle Monate +# Werte enthalten. # # 6. Es wird über alle Einträge aus 4. iteriert. Die Zeilensummen # werden in den entsprechenden Datenstrukturen aus 5. addiert. @@ -94,7 +97,8 @@ sub new { # den Aufträgen nie vorgekommen ist (sprich Rechnung enthält # Positionen, die im Auftrag nicht enthalten sind, und die komplett # andere Buchungsgruppen verwenden), so wird schlicht die allererste -# in 4. gefundene Buchungsgruppe damit belastet. +# in 4. gefundene Buchungsgruppe damit belastet. Analog passiert dies +# auch für Warengruppen. sub create { my ($self) = @_; @@ -127,8 +131,9 @@ SQL # 2. Auslesen aktiver Wartungsvertragskonfigurationen $query = < 'o') + AND ( (oi.recurring_billing_mode = 'always') + OR ( (oi.recurring_billing_mode = 'once') + AND (oi.recurring_billing_invoice_id IS NULL))) SQL # 3. Iterieren über Saldierungsintervalle, vormerken @@ -153,6 +162,15 @@ SQL my $billing_len = $SL::DB::PeriodicInvoicesConfig::PERIOD_LENGTHS{ $ref->{periodicity} } || 1; if (($date ge $self->{min_date}) && (!$periodic_invoices{ $ref->{config_id} } || !$periodic_invoices{ $ref->{config_id} }->{$date})) { + if ($ref->{recurring_billing_mode} eq 'once') { + push @scentries, { buchungsgruppe => $ref->{buchungsgruppe}, + salesman => $ref->{salesman}, + linetotal => $ref->{linetotal}, + date => $date, + }; + last; + } + my $order_value_periodicity = $ref->{order_value_periodicity} eq 'p' ? $ref->{periodicity} : $ref->{order_value_periodicity}; my $order_value_len = $SL::DB::PeriodicInvoicesConfig::ORDER_VALUE_PERIOD_LENGTHS{$order_value_periodicity} || 1; @@ -160,6 +178,7 @@ SQL salesman => $ref->{salesman}, linetotal => $ref->{linetotal} * $billing_len / $order_value_len, date => $date, + parts_group => $ref->{parts_group}, }; } @@ -172,15 +191,16 @@ SQL $query = < 'o')) SQL @@ -190,6 +210,7 @@ SQL my @entries = selectall_hashref_query($::form, $dbh, $query); my @salesmen = uniq map { $_->{salesman} } (@entries, @scentries); my @buchungsgruppen = uniq map { $_->{buchungsgruppe} } (@entries, @scentries); + my @parts_groups = uniq map { $_->{parts_group} } (@entries, @scentries); my @now = localtime; my @dates = map { $self->_date_for($now[5] + 1900, $now[4] + $_) } (0..$self->{params}->{months} + 1); my %dates_by_ordnumber = map { $_->{ordnumber} => $self->_date_for($_) } @entries; @@ -202,9 +223,11 @@ SQL support => { map { $_ => 0 } @dates }, salesman => { map { $_ => { map { $_ => 0 } @dates } } @salesmen }, buchungsgruppe => { map { $_ => { map { $_ => 0 } @dates } } @buchungsgruppen }, + parts_group => { map { $_ => { map { $_ => 0 } @dates } } @parts_groups }, sorted => { month => [ sort { ($date_sorter{$a} || $a) cmp ($date_sorter{$b} || $b) } @dates ], salesman => [ sort { $a cmp $b } @salesmen ], buchungsgruppe => [ sort { $a cmp $b } @buchungsgruppen ], + parts_group => [ sort { $a cmp $b } @parts_groups ], type => [ qw(order partial support) ], }, }; @@ -217,6 +240,7 @@ SQL $projection->{order}->{$date} += $ref->{linetotal}; $projection->{salesman}->{ $ref->{salesman} }->{$date} += $ref->{linetotal}; $projection->{buchungsgruppe}->{ $ref->{buchungsgruppe} }->{$date} += $ref->{linetotal}; + $projection->{parts_group}->{ $ref->{parts_group} }->{$date} += $ref->{linetotal}; } # 7. Aufsummieren der Wartungsvertragspositionen @@ -227,6 +251,7 @@ SQL $projection->{support}->{$date} += $ref->{linetotal}; $projection->{salesman}->{ $ref->{salesman} }->{$date} += $ref->{linetotal}; $projection->{buchungsgruppe}->{ $ref->{buchungsgruppe} }->{$date} += $ref->{linetotal}; + $projection->{parts_group}->{ $ref->{parts_group} }->{$date} += $ref->{linetotal}; } if (%dates_by_ordnumber) { @@ -235,11 +260,13 @@ SQL $query = <{ordnumber} } || die; my $salesman = $salesman_by_ordnumber{ $ref->{ordnumber} } || die; my $buchungsgruppe = $projection->{buchungsgruppe}->{ $ref->{buchungsgruppe} } ? $ref->{buchungsgruppe} : $buchungsgruppen[0]; + my $parts_group = $projection->{parts_group}->{ $ref->{parts_group} } ? $ref->{parts_group} : $parts_groups[0]; $projection->{partial}->{$date} -= $ref->{linetotal}; $projection->{total}->{$date} -= $ref->{linetotal}; $projection->{salesman}->{$salesman}->{$date} -= $ref->{linetotal}; $projection->{buchungsgruppe}->{$buchungsgruppe}->{$date} -= $ref->{linetotal}; + $projection->{parts_group}->{$parts_group}->{$date} -= $ref->{linetotal}; } } @@ -300,4 +329,52 @@ sub _date_for { : $date; } +sub orders_for_time_period { + my ($class, %params) = @_; + + my $dbh = SL::DB::Order->new->db->dbh; + + my @recurring_orders; + + # 1. Alle aktiven Konfigurationen für wiederkehrende Rechnungen auslesen. + + my $configs = SL::DB::Manager::PeriodicInvoicesConfig->get_all(where => [ active => 1 ]); + + my %calc_params; + $calc_params{start_date} = $params{after}->clone if $params{after}; + $calc_params{end_date} = $params{before}->clone->add(days => -1) if $params{before}; + $calc_params{end_date} //= $calc_params{start_date}->clone->add(years => 1); + + foreach my $config (@{ $configs }) { + my @dates = $config->calculate_invoice_dates(%calc_params); + next unless @dates; + + my $order = SL::DB::Order->new(id => $config->oe_id)->load(with_objects => [ qw(customer employee) ]); + $order->{is_recurring} = 1; + + push @recurring_orders, $order; + } + + my @where = ( + record_type => 'sales_order', + or => [ closed => undef, closed => 0, ], + ); + push @where, (reqdate => { ge => $params{after}->clone }) if $params{after}; + push @where, (reqdate => { lt => $params{before}->clone }) if $params{before}; + push @where, '!id' => [ map { $_->id } @recurring_orders ] if @recurring_orders; + + # 1. Auslesen aller offenen Aufträge, deren Lieferdatum im + # gewünschten Bereich liegt + my $regular_orders = SL::DB::Manager::Order->get_all( + where => \@where, + with_objects => [ qw(customer employee) ], + ); + + return sort { + ($a->transdate <=> $b->transdate) + || ($a->reqdate <=> $b->reqdate) + || (lc($a->customer->name) cmp lc($b->customer->name)) + } (@recurring_orders, @{ $regular_orders }); +} + 1;