epic-s6ts
[kivitendo-erp.git] / SL / DO.pm
index e97b0fd..ebc6051 100644 (file)
--- a/SL/DO.pm
+++ b/SL/DO.pm
@@ -36,12 +36,13 @@ package DO;
 
 use Carp;
 use List::Util qw(max);
-use YAML;
+use Text::ParseWords;
 
 use SL::AM;
 use SL::Common;
 use SL::CVar;
 use SL::DB::DeliveryOrder;
+use SL::DB::DeliveryOrder::TypeData qw(:types is_valid_type);
 use SL::DB::Status;
 use SL::DBUtils;
 use SL::Helper::ShippedQty;
@@ -51,6 +52,7 @@ use SL::IC;
 use SL::TransNumber;
 use SL::DB;
 use SL::Util qw(trim);
+use SL::YAML;
 
 use strict;
 
@@ -78,6 +80,7 @@ sub transactions {
          dord.transaction_description, dord.itime::DATE AS insertdate,
          pr.projectnumber AS globalprojectnumber,
          dep.description AS department,
+         dord.order_type,
          e.name AS employee,
          sm.name AS salesman
        FROM delivery_orders dord
@@ -89,7 +92,10 @@ sub transactions {
        LEFT JOIN department dep ON (dord.department_id = dep.id)
 |;
 
-  push @where, ($form->{type} eq 'sales_delivery_order' ? '' : 'NOT ') . qq|COALESCE(dord.is_sales, FALSE)|;
+  if ($form->{type} && is_valid_type($form->{type})) {
+    push @where, 'dord.order_type = ?';
+    push @values, $form->{type};
+  }
 
   if ($form->{department_id}) {
     push @where,  qq|dord.department_id = ?|;
@@ -128,7 +134,8 @@ sub transactions {
     push @where, "dord.$item = ?";
     push @values, conv_i($form->{$item});
   }
-  if (!$main::auth->assert('sales_all_edit', 1)) {
+  if ( !(    ($vc eq 'customer' && ($main::auth->assert('sales_all_edit',    1) || $main::auth->assert('sales_delivery_order_view',    1)))
+          || ($vc eq 'vendor'   && ($main::auth->assert('purchase_all_edit', 1) || $main::auth->assert('purchase_delivery_order_view', 1))) ) ) {
     push @where, qq|dord.employee_id = (select id from employee where login= ?)|;
     push @values, $::myconfig{login};
   }
@@ -211,6 +218,17 @@ SQL
     push @values, like($form->{parts_description});
   }
 
+  if ($form->{all}) {
+    my @tokens = parse_line('\s+', 0, $form->{all});
+    # ordnumber quonumber customer.name vendor.name transaction_description
+    push @where, <<SQL for @tokens;
+      (   (dord.donumber                ILIKE ?)
+       OR (ct.name                      ILIKE ?)
+       OR (dord.transaction_description ILIKE ?))
+SQL
+    push @values, (like($_))x3 for @tokens;
+  }
+
   if (@where) {
     $query .= " WHERE " . join(" AND ", map { "($_)" } @where);
   }
@@ -316,8 +334,8 @@ sub _save {
     $query = qq|SELECT nextval('id')|;
     ($form->{id}) = selectrow_query($form, $dbh, $query);
 
-    $query = qq|INSERT INTO delivery_orders (id, donumber, employee_id, currency_id, taxzone_id) VALUES (?, '', ?, (SELECT currency_id FROM defaults LIMIT 1), ?)|;
-    do_query($form, $dbh, $query, $form->{id}, conv_i($form->{employee_id}), $form->{taxzone_id});
+    $query = qq|INSERT INTO delivery_orders (id, donumber, employee_id, currency_id, taxzone_id, order_type) VALUES (?, '', ?, (SELECT currency_id FROM defaults LIMIT 1), ?, ?)|;
+    do_query($form, $dbh, $query, $form->{id}, conv_i($form->{employee_id}), $form->{taxzone_id}, SALES_DELIVERY_ORDER_TYPE);
   }
 
   my $project_id;
@@ -438,7 +456,7 @@ SQL
                   conv_i($sinfo->{bin_id}));
         $h_item_stock_id->finish();
         # write back the id to the form (important if only transfer was clicked (id fk for invoice)
-        $form->{"stock_${in_out}_$i"} = YAML::Dump($stock_info);
+        $form->{"stock_${in_out}_$i"} = SL::YAML::Dump($stock_info);
       }
       @values = ($form->{"delivery_order_items_id_$i"}, $sinfo->{qty}, $sinfo->{unit}, conv_i($sinfo->{warehouse_id}),
                  conv_i($sinfo->{bin_id}), $sinfo->{chargenumber}, conv_date($sinfo->{bestbefore}),
@@ -499,25 +517,25 @@ SQL
   $query =
     qq|UPDATE delivery_orders SET
          donumber = ?, ordnumber = ?, cusordnumber = ?, transdate = ?, vendor_id = ?,
-         customer_id = ?, reqdate = ?,
+         customer_id = ?, reqdate = ?, tax_point = ?,
          shippingpoint = ?, shipvia = ?, notes = ?, intnotes = ?, closed = ?,
-         delivered = ?, department_id = ?, language_id = ?, shipto_id = ?,
+         delivered = ?, department_id = ?, language_id = ?, shipto_id = ?, billing_address_id = ?,
          globalproject_id = ?, employee_id = ?, salesman_id = ?, cp_id = ?, transaction_description = ?,
-         is_sales = ?, taxzone_id = ?, taxincluded = ?, payment_id = ?, currency_id = (SELECT id FROM currencies WHERE name = ?),
+         order_type = ?, taxzone_id = ?, taxincluded = ?, payment_id = ?, currency_id = (SELECT id FROM currencies WHERE name = ?),
          delivery_term_id = ?
        WHERE id = ?|;
 
   @values = ($form->{donumber}, $form->{ordnumber},
              $form->{cusordnumber}, conv_date($form->{transdate}),
              conv_i($form->{vendor_id}), conv_i($form->{customer_id}),
-             conv_date($form->{reqdate}), $form->{shippingpoint}, $form->{shipvia},
+             conv_date($form->{reqdate}), conv_date($form->{tax_point}), $form->{shippingpoint}, $form->{shipvia},
              $restricter->process($form->{notes}), $form->{intnotes},
              $form->{closed} ? 't' : 'f', $form->{delivered} ? "t" : "f",
-             conv_i($form->{department_id}), conv_i($form->{language_id}), conv_i($form->{shipto_id}),
+             conv_i($form->{department_id}), conv_i($form->{language_id}), conv_i($form->{shipto_id}), conv_i($form->{billing_address_id}),
              conv_i($form->{globalproject_id}), conv_i($form->{employee_id}),
              conv_i($form->{salesman_id}), conv_i($form->{cp_id}),
              $form->{transaction_description},
-             $form->{type} =~ /^sales/ ? 't' : 'f',
+             $form->{type} =~ /^sales/ ? SALES_DELIVERY_ORDER_TYPE : PURCHASE_DELIVERY_ORDER_TYPE,
              conv_i($form->{taxzone_id}), $form->{taxincluded} ? 't' : 'f', conv_i($form->{payment_id}), $form->{currency},
              conv_i($form->{delivery_term_id}),
              conv_i($form->{id}));
@@ -545,10 +563,10 @@ SQL
                             'to_id'      => $form->{id},
     );
   delete $form->{convert_from_oe_ids};
-
-  $self->mark_orders_if_delivered('do_id' => $form->{id},
-                                  'type'  => $form->{type} eq 'sales_delivery_order' ? 'sales' : 'purchase',
-                                  'dbh'   => $dbh,);
+  unless ($::instance_conf->get_shipped_qty_require_stock_out) {
+    $self->mark_orders_if_delivered('do_id' => $form->{id},
+                                    'type'  => $form->{type} eq 'sales_delivery_order' ? 'sales' : 'purchase');
+  }
 
   $form->{saved_donumber} = $form->{donumber};
   $form->{saved_ordnumber} = $form->{ordnumber};
@@ -637,6 +655,38 @@ sub delete {
   return $rc;
 }
 
+sub delete_transfers {
+  $main::lxdebug->enter_sub();
+
+  my ($self)   = @_;
+
+  my $myconfig = \%main::myconfig;
+  my $form     = $main::form;
+
+  my $rc = SL::DB::Order->new->db->with_transaction(sub {
+
+    my $do = SL::DB::DeliveryOrder->new(id => $form->{id})->load;
+    die "No valid delivery order found" unless ref $do eq 'SL::DB::DeliveryOrder';
+
+    my $dt = DateTime->today->subtract(days => $::instance_conf->get_undo_transfer_interval);
+    croak "Wrong call. Please check undoing interval" unless $do->itime > $dt;
+
+    foreach my $doi (@{ $do->orderitems }) {
+      foreach my $dois (@{ $doi->delivery_order_stock_entries}) {
+        $dois->inventory->delete;
+        $dois->delete;
+      }
+    }
+    $do->update_attributes(delivered => 0);
+
+    1;
+  });
+
+  $main::lxdebug->leave_sub();
+
+  return $rc;
+}
+
 sub retrieve {
   $main::lxdebug->enter_sub();
 
@@ -681,13 +731,13 @@ sub retrieve {
   # so if any of these infos is important (or even different) for any item,
   # it will be killed out and then has to be fetched from the item scope query further down
   $query =
-    qq|SELECT dord.cp_id, dord.donumber, dord.ordnumber, dord.transdate, dord.reqdate,
+    qq|SELECT dord.cp_id, dord.donumber, dord.ordnumber, dord.transdate, dord.reqdate, dord.tax_point,
          dord.shippingpoint, dord.shipvia, dord.notes, dord.intnotes,
          e.name AS employee, dord.employee_id, dord.salesman_id,
          dord.${vc}_id, cv.name AS ${vc},
          dord.closed, dord.reqdate, dord.department_id, dord.cusordnumber,
          d.description AS department, dord.language_id,
-         dord.shipto_id,
+         dord.shipto_id, dord.billing_address_id,
          dord.itime, dord.mtime,
          dord.globalproject_id, dord.delivered, dord.transaction_description,
          dord.taxzone_id, dord.taxincluded, dord.payment_id, (SELECT cu.name FROM currencies cu WHERE cu.id=dord.currency_id) AS currency,
@@ -821,7 +871,7 @@ sub retrieve {
         push @{ $requests }, $ref;
       }
 
-      $doi->{"stock_${in_out}"} = YAML::Dump($requests);
+      $doi->{"stock_${in_out}"} = SL::YAML::Dump($requests);
     }
 
     $sth->finish();
@@ -1011,16 +1061,16 @@ sub order_details {
       push @{ $form->{TEMPLATE_ARRAYS}{si_unit}[$si_position-1] },          $si->{unit};
     }
 
-    if ($form->{"assembly_$i"}) {
+    if ($form->{"part_type_$i"} eq 'assembly') {
       $sameitem = "";
 
       # get parts and push them onto the stack
       my $sortorder = "";
       if ($form->{groupitems}) {
         $sortorder =
-          qq|ORDER BY pg.partsgroup, a.oid|;
+          qq|ORDER BY pg.partsgroup, a.position|;
       } else {
-        $sortorder = qq|ORDER BY a.oid|;
+        $sortorder = qq|ORDER BY a.position|;
       }
 
       do_statement($form, $h_pg, $q_pg, conv_i($form->{"id_$i"}));
@@ -1073,21 +1123,6 @@ sub order_details {
   $main::lxdebug->leave_sub();
 }
 
-sub project_description {
-  $main::lxdebug->enter_sub();
-
-  my ($self, $dbh, $id) = @_;
-
-  my $form     =  $main::form;
-
-  my $query = qq|SELECT description FROM project WHERE id = ?|;
-  my ($value) = selectrow_query($form, $dbh, $query, $id);
-
-  $main::lxdebug->leave_sub();
-
-  return $value;
-}
-
 sub unpack_stock_information {
   $main::lxdebug->enter_sub();
 
@@ -1098,7 +1133,7 @@ sub unpack_stock_information {
 
   my $unpacked;
 
-  eval { $unpacked = $params{packed} ? YAML::Load($params{packed}) : []; };
+  eval { $unpacked = $params{packed} ? SL::YAML::Load($params{packed}) : []; };
 
   $unpacked = [] if (!$unpacked || ('ARRAY' ne ref $unpacked));
 
@@ -1234,167 +1269,12 @@ sub transfer_in_out {
 
   WH->transfer(@transfers);
 
-  $main::lxdebug->leave_sub();
-}
-
-
-sub get_shipped_qty {
-  $main::lxdebug->enter_sub();
-
-  # Drei Fälle:
-  # $params{oe_id} : Alle Lieferscheine zu diesem Auftrag durchsuchen und pro Auftragsposition die Mengen zurückgeben
-  #                  Wird zur Darstellung der gelieferten Mengen im Auftrag benötigt
-  # $params{do_id} : Alle Aufträge zu diesem Lieferschein durchsuchen und pro Lieferscheinposition die Mengen zurückgeben
-  #                  Wird für LaTeX benötigt um im Lieferschein pro Position die Mengen auszugeben
-  # $params{delivered}: Alle Aufträge zum Lieferschein $params{do_id} prüfen ob sie vollständiger ausgeliefert sind
-  #                  Wird für das Setzen des 'delivered' Flag in der Datenbank beim "save" des Lieferscheins benötigt
-
-  my $self     = shift;
-  my %params   = @_;
-
-  # Eigentlich unkritisch: wenn keine der Parameter gesetzt ist kommt ein leerer Hash zurück
-  croak ("Need at least one parameter oe_id or do_id") unless $params{oe_id} || $params{do_id};
-
-  my $myconfig = \%main::myconfig;
-  my $form     = $main::form;
-  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
-  my %ship = ();
-
-  my @oe_ids;
-
-  if ($params{oe_id} ) {
-    push @oe_ids,  $params{oe_id};
-  } elsif ($params{do_id}) {
-    my @links  = RecordLinks->get_links(  'dbh'        => $dbh,
-                                          'from_table' => 'oe',
-                                          'to_table'   => 'delivery_orders',
-                                          'to_id'      => $params{do_id});
-
-    @oe_ids  = map { $_->{from_id} } @links;
+  if ($::instance_conf->get_shipped_qty_require_stock_out) {
+    $self->mark_orders_if_delivered('do_id' => $form->{id},
+                                    'type'  => $form->{type} eq 'sales_delivery_order' ? 'sales' : 'purchase');
   }
 
-  if (scalar (@oe_ids) > 0 ) {
-    my $all_units = AM->retrieve_all_units();
-    my $placeholders = join(', ', ('?') x scalar @oe_ids);
-    my $query = qq|SELECT oi.id, oi.position, oi.parts_id, oi.qty, oi.unit, oi.trans_id,
-                        p.unit AS partunit FROM orderitems oi
-                        LEFT JOIN parts p ON (oi.parts_id = p.id)
-                        WHERE trans_id IN (${placeholders})
-                        ORDER BY position ASC|;
-
-    my $orderitems = selectall_hashref_query($form, $dbh, $query, @oe_ids);
-    foreach my $oe_entry (@{ $orderitems }) {
-      $oe_entry->{qty} *= AM->convert_unit($oe_entry->{unit}, $oe_entry->{partunit}, $all_units);
-      $oe_entry->{qty_notdelivered} = $oe_entry->{qty};
-
-      # Bei oe Modus auf jeden Fall einen Record anlegen
-      if ( $params{oe_id} ) {
-        $ship{$oe_entry->{position}} = {
-             'qty_ordered'      => $oe_entry->{qty} ,
-             'qty_notdelivered' => $oe_entry->{qty}
-        };
-      }
-    }
-
-    my @dolinks  = RecordLinks->get_links('dbh'       => $dbh,
-                                       'from_table' => 'oe',
-                                       'to_table'   => 'delivery_orders',
-                                       'from_id'    => \@oe_ids);
-
-    my @do_ids = map { $_->{to_id} }  @dolinks ;
-    if (scalar (@do_ids) == 0) {
-      $main::lxdebug->leave_sub();
-      return %ship;
-    }
-
-    my %oeitems_by_id       = map { $_->{id} => $_ } @{ $orderitems };
-
-
-    $placeholders = join(', ', ('?') x scalar @do_ids);
-    $query  = qq|SELECT doi.parts_id, doi.id, doi.qty, doi.unit, doi.position,
-               doi.delivery_order_id, COALESCE(rlitem.from_id,0) as from_id,
-               p.unit AS partunit
-               FROM delivery_order_items doi
-               LEFT JOIN parts p ON (doi.parts_id = p.id)
-               LEFT JOIN record_links rlitem
-               ON (rlitem.to_id = doi.id AND rlitem.to_table='delivery_order_items')
-               WHERE doi.delivery_order_id IN (${placeholders})|;
-
-    my $deliveryorderitems = selectall_hashref_query($form, $dbh, $query, @do_ids);
-
-    # erst mal qty der links bearbeiten
-    foreach my $do_entry (@{ $deliveryorderitems }) {
-      $do_entry->{qty} *= AM->convert_unit($do_entry->{unit}, $do_entry->{partunit}, $all_units);
-      if ($do_entry->{from_id} > 0 ) {
-        # record link zwischen items vorhanden, kann auch von anderem Auftrag sein
-        my $oe_entry = $oeitems_by_id{$do_entry->{from_id}};
-        if ( $oe_entry ) {
-          $oe_entry->{qty_notdelivered} -= $do_entry->{qty};
-          # derzeit nur ein link pro do_item
-          $do_entry->{oe_entry} = $oe_entry;
-        }
-      } else {
-        $main::lxdebug->message(LXDebug->DEBUG2(),"no entry for=".$do_entry->{id}." part=".$do_entry->{parts_id});
-      }
-    }
-    # nun den rest ohne links bearbeiten
-    foreach my $do_entry (@{ $deliveryorderitems }) {
-      next if $do_entry->{from_id} > 0;
-      next if $do_entry->{qty} == 0;
-
-      foreach my $oe_entry (@{ $orderitems }) {
-        next if $oe_entry->{qty_notdelivered} == 0;
-        if ( $do_entry->{parts_id} == $oe_entry->{parts_id} ) {
-          # zu viele geliefert auf andere position ?
-          if ( $oe_entry->{qty_notdelivered} < 0 ) {
-            $do_entry->{qty} += - $oe_entry->{qty_notdelivered};
-            $oe_entry->{qty_notdelivered} = 0;
-          } else {
-            if ( $do_entry->{qty} < $oe_entry->{qty_notdelivered} ) {
-              $oe_entry->{qty_notdelivered} -= $do_entry->{qty};
-              $do_entry->{qty} = 0;
-            } else {
-              $do_entry->{qty} -= $oe_entry->{qty_notdelivered};
-              $oe_entry->{qty_notdelivered} = 0;
-            }
-            # derzeit nur ein link pro do_item
-            $do_entry->{oe_entry} = $oe_entry if !$do_entry->{oe_entry};
-          }
-        }
-        last if $do_entry->{qty} <= 0;
-      }
-    }
-    if ( $params{oe_id} ) {
-      $ship{$_->{position}}->{qty_notdelivered} = $_->{qty_notdelivered} for @{ $orderitems };
-    }
-    elsif ($params{do_id} && $params{delivered}) {
-      foreach my $oe_entry (@{ $orderitems }) {
-        if ( !$ship{$oe_entry->{trans_id}} ) {
-            $ship{$oe_entry->{trans_id}} = { 'delivered' => 1 };
-        }
-        $ship{$oe_entry->{trans_id}}->{delivered} = 0 if $oe_entry->{qty_notdelivered} > 0;
-      }
-    }
-    elsif ($params{do_id}) {
-      foreach my $do_entry (@{ $deliveryorderitems }) {
-        next if $params{do_id} != $do_entry->{delivery_order_id};
-        my $position = $do_entry->{position};
-        if ( $position > 0 && $do_entry->{oe_entry}) {
-          if ( !$ship{$position} ) {
-            $ship{$position} = {
-              'qty_ordered'      => $do_entry->{oe_entry}->{qty} ,
-              'qty_notdelivered' => $do_entry->{oe_entry}->{qty_notdelivered}
-            };
-          } else {
-            $ship{$position}->{qty_ordered}      += $do_entry->{oe_entry}->{qty};
-            $ship{$position}->{qty_notdelivered} += $do_entry->{oe_entry}->{qty_notdelivered};
-          }
-        }
-      }
-    }
-  }
   $main::lxdebug->leave_sub();
-  return %ship;
 }
 
 sub is_marked_as_delivered {