Lieferwertbericht um Filter nach Warengruppen erweitert
[kivitendo-erp.git] / SL / Controller / DeliveryValueReport.pm
index 20e0286..ae2032f 100644 (file)
@@ -11,13 +11,13 @@ use SL::Controller::Helper::ReportGenerator;
 use SL::Locale::String;
 use SL::Helper::ShippedQty;
 use SL::AM;
-use SL::DBUtils ();
+use SL::DBUtils qw(selectall_as_map);
+use List::MoreUtils qw(uniq);
 use Carp;
 use Data::Dumper;
 
 use Rose::Object::MakeMethods::Generic (
-  scalar => [ qw(db_args flat_filter) ],
-  'scalar --get_set_init' => [ qw(models vc all_employees all_businesses) ],
+  'scalar --get_set_init' => [ qw(models vc all_employees all_businesses all_partsgroups) ],
 );
 
 __PACKAGE__->run_before(sub { $::auth->assert('delivery_value_report'); });
@@ -38,6 +38,8 @@ my %sort_columns = (
   netto_shipped_qty       => t8('Net Value in delivery orders'),
   delivered_qty           => t8('transferred in / out'),
   netto_delivered_qty     => t8('Net value transferred in / out'),
+  do_closed_qty           => t8('Qty in closed delivery orders'),
+  netto_do_closed_qty     => t8('Net value in closed delivery orders'),
 );
 
 
@@ -68,7 +70,7 @@ sub prepare_report {
 
   my @columns     = qw(reqdate customer vendor ordnumber partnumber description unit qty netto_qty
                        not_shipped_qty netto_not_shipped_qty shipped_qty netto_shipped_qty delivered_qty
-                       netto_delivered_qty);
+                       netto_delivered_qty do_closed_qty netto_do_closed_qty);
 
 
   my @sortable    = qw(reqdate customer vendor ordnumber partnumber description);
@@ -82,26 +84,18 @@ sub prepare_report {
                            obj_link => sub { $self->link_to($_[0]->part)                                      } },
     partnumber        => {      sub => sub { $_[0]->part->partnumber                                          },
                            obj_link => sub { $self->link_to($_[0]->part)                                      } },
-    qty               => {      sub => sub { $_[0]->qty_as_number .
-                                             ($rp_csv_mod ? '' : ' ' .  $_[0]->unit)                           } },
-    netto_qty         => {      sub => sub { $::form->format_amount(\%::myconfig,
-                                              ($_[0]->qty * $_[0]->sellprice * (1 - $_[0]->discount) /
-                                                                         ($_[0]->price_factor || 1), 2))       },},
-    unit              => {      sub => sub {  $_[0]->unit                                                      },
-                            visible => $rp_csv_mod                                                             },
-    shipped_qty       => {      sub => sub { $::form->format_amount(\%::myconfig, $_[0]{shipped_qty}, 2) .
-                                             ($rp_csv_mod ? '' : ' ' .  $_[0]->unit)                           } },
-    netto_shipped_qty => {      sub => sub { $::form->format_amount(\%::myconfig, $_[0]{netto_shipped_qty}, 2) },},
-    not_shipped_qty   => {      sub => sub { $::form->format_amount(\%::myconfig, $_[0]->qty - $_[0]{shipped_qty}
-                                               - $_[0]{delivered_qty} - $_[0]{do_closed_qty}, 2) .
-                                             ($rp_csv_mod ? '' : ' ' .  $_[0]->unit)                           } },
-    delivered_qty     => {      sub => sub { $::form->format_amount(\%::myconfig, $_[0]{delivered_qty}, 2) .
-                                             ($rp_csv_mod ? '' : ' ' .  $_[0]->unit)                           } },
-    netto_delivered_qty => {    sub => sub { $::form->format_amount(\%::myconfig, $_[0]{netto_delivered_qty}, 2) },},
-    netto_not_shipped_qty => {  sub => sub { $::form->format_amount(\%::myconfig,(($_[0]->qty -
-                                             $_[0]{shipped_qty} - $_[0]{delivered_qty} - $_[0]{do_closed_qty})
-                                             * ($_[0]->sellprice * (1 - $_[0]->discount) /
-                                                                             ($_[0]->price_factor || 1)), 2))  },},
+    qty               => {      sub => sub { _format_qty($_[0], 'qty', $rp_csv_mod)                           } },
+    netto_qty         => {      sub => sub { _format_val($_[0], 'qty')                                        },},
+    unit              => {      sub => sub {  $_[0]->unit                                                     },
+                            visible => $rp_csv_mod                                                              },
+    shipped_qty       => {      sub => sub { _format_qty($_[0], 'shipped_qty', $rp_csv_mod)                   } },
+    netto_shipped_qty => {      sub => sub { _format_val($_[0], 'shipped_qty')                                },},
+    not_shipped_qty   => {      sub => sub { _format_qty($_[0], 'not_shipped_qty', $rp_csv_mod)               } },
+    netto_not_shipped_qty => {  sub => sub { _format_val($_[0], 'not_shipped_qty')                            },},
+    delivered_qty     => {      sub => sub { _format_qty($_[0], 'delivered_qty', $rp_csv_mod)                 } },
+    netto_delivered_qty => {    sub => sub { _format_val($_[0], 'delivered_qty')                              },},
+    do_closed_qty     => {      sub => sub { _format_qty($_[0], 'do_closed_qty', $rp_csv_mod)                 },},
+    netto_do_closed_qty => {    sub => sub { _format_val($_[0], 'do_closed_qty')                              },},
     ordnumber         => {      sub => sub { $_[0]->order->ordnumber                                           },
                            obj_link => sub { $self->link_to($_[0]->order)                                      } },
     vendor            => {      sub => sub { $_[0]->order->vendor->name                                        },
@@ -147,13 +141,14 @@ sub prepare_report {
 sub make_filter_summary {
   my ($self) = @_;
   my $vc     = $self->vc;
-  my ($business, $employee);
+  my ($business, $employee, $partsgroup);
 
   my $filter = $::form->{filter} || {};
   my @filter_strings;
 
-  $business = SL::DB::Business->new(id => $filter->{order}{customer}{"business_id"})->load->description if $filter->{order}{customer}{"business_id"};
-  $employee = SL::DB::Employee->new(id => $filter->{order}{employee_id})->load->name if $filter->{order}{employee_id};
+  $business   = SL::DB::Business->new(id => $filter->{order}{customer}{"business_id"})->load->description if $filter->{order}{customer}{"business_id"};
+  $employee   = SL::DB::Employee->new(id => $filter->{order}{employee_id})->load->name                    if $filter->{order}{employee_id};
+  $partsgroup = SL::DB::PartsGroup->new(id => $filter->{part}{partsgroup_id})->load->partsgroup           if $filter->{part}{partsgroup_id};
 
   my @filters = (
     [ $filter->{order}{"ordnumber:substr::ilike"},                    $::locale->text('Number')                                             ],
@@ -169,6 +164,7 @@ sub make_filter_summary {
     [ $filter->{order}{customer}{"customernumber:substr::ilike"},     $::locale->text('Customer Number')                                    ],
     [ $business,                                                      $::locale->text('Customer type')                                      ],
     [ $employee,                                                      $::locale->text('Employee')                                           ],
+    [ $partsgroup,                                                    $::locale->text('Partsgroup')                                         ],
   );
 
   # flags for with_object 'part'
@@ -223,6 +219,9 @@ sub init_all_employees {
 sub init_all_businesses {
   return SL::DB::Manager::Business->get_all_sorted;
 }
+sub init_all_partsgroups {
+  return SL::DB::Manager::PartsGroup->get_all_sorted;
+}
 
 
 sub link_to {
@@ -236,7 +235,11 @@ sub link_to {
     my $vc     = $object->is_sales ? 'customer' : 'vendor';
     my $id     = $object->id;
 
-    return "oe.pl?action=$action&type=$type&vc=$vc&id=$id";
+    if ($::instance_conf->get_feature_experimental_order) {
+      return "controller.pl?action=Order/$action&type=$type&id=$id";
+    } else {
+      return "oe.pl?action=$action&type=$type&vc=$vc&id=$id";
+    }
   }
   if ($object->isa('SL::DB::Part')) {
     my $id     = $object->id;
@@ -248,6 +251,18 @@ sub link_to {
   }
 }
 
+sub _format_qty {
+  my ($item, $col, $csv_mod) = @_;
+
+  $::form->format_amount(\%::myconfig, $item->{$col}, 2) .  ($csv_mod ? '' : ' ' .  $item->unit)
+}
+
+sub _format_val {
+  my ($item, $col) = @_;
+
+  $::form->format_amount(\%::myconfig, $item->{$col} * $item->sellprice * (1 - $item->discount) / ($item->price_factor || 1), 2)
+}
+
 
 sub calc_qtys_price {
   my ($self, $orderitems) = @_;
@@ -261,17 +276,31 @@ sub calc_qtys_price {
 
   $_->{delivered_qty} = delete $_->{shipped_qty} for @$orderitems;
 
-  SL::Helper::ShippedQty
-    ->new(require_stock_out => 0)
+  my $helper = SL::Helper::ShippedQty
+    ->new(require_stock_out => 0, keep_matches => 1)
     ->calculate($orderitems)
     ->write_to_objects;
 
   for my $item (@$orderitems) {
     $item->{not_shipped_qty} = $item->qty - $item->{shipped_qty};
+    $item->{do_closed_qty}   = 0;
 
     my $price_factor = $item->price_factor || 1;
-    $item->{netto_shipped_qty}   = $item->{shipped_qty}   * $item->sellprice * (1 - $item->discount) / $price_factor;
-    $item->{netto_delivered_qty} = $item->{delivered_qty} * $item->sellprice * (1 - $item->discount) / $price_factor;
+  }
+
+  if (my @all_doi_ids = uniq map { $_->[1] } @{ $helper->matches }) {
+    my %oi_by_id = map { $_->id => $_ } @$orderitems;
+    my $query    = sprintf <<'', join ', ', ("?")x@all_doi_ids;
+      SELECT DISTINCT doi.id, closed FROM delivery_orders
+      LEFT JOIN delivery_order_items doi ON (doi.delivery_order_id = delivery_orders.id)
+      WHERE doi.id IN (%s)
+
+    my %doi_is_closed = selectall_as_map($::form, SL::DB->client->dbh, $query, (id => 'closed'), @all_doi_ids);
+
+    for my $match (@{ $helper->matches }) {
+      next unless $doi_is_closed{$match->[1]};
+      $oi_by_id{$match->[0]}->{do_closed_qty} += $match->[2];
+    }
   }
 }