Merge branch 'master' of ssh://git-jbueren@lx-office.linet-services.de/~/lx-office-erp
[kivitendo-erp.git] / SL / OE.pm
index 9adbee2..b9aba5c 100644 (file)
--- a/SL/OE.pm
+++ b/SL/OE.pm
@@ -37,9 +37,12 @@ package OE;
 use List::Util qw(max first);
 use SL::AM;
 use SL::Common;
+use SL::CVar;
 use SL::DBUtils;
 use SL::IC;
 
+use strict;
+
 sub transactions {
   $main::lxdebug->enter_sub();
 
@@ -72,7 +75,8 @@ sub transactions {
     qq|  o.marge_total, o.marge_percent, | .
     qq|  ex.$rate AS exchangerate, | .
     qq|  pr.projectnumber AS globalprojectnumber, | .
-    qq|  e.name AS employee, s.name AS salesman | .
+    qq|  e.name AS employee, s.name AS salesman, | .
+    qq|  ct.${vc}number AS vcnumber, ct.country, ct.ustid  | .
     qq|FROM oe o | .
     qq|JOIN $vc ct ON (o.${vc}_id = ct.id) | .
     qq|LEFT JOIN employee e ON (o.employee_id = e.id) | .
@@ -95,7 +99,18 @@ sub transactions {
       qq|AND ((globalproject_id = ?) OR EXISTS | .
       qq|  (SELECT * FROM orderitems oi | .
       qq|   WHERE oi.project_id = ? AND oi.trans_id = o.id))|;
-    push(@values, $form->{"project_id"}, $form->{"project_id"});
+    push(@values, conv_i($form->{"project_id"}), conv_i($form->{"project_id"}));
+  }
+
+  if ($form->{"projectnumber"}) {
+    $query .= <<SQL;
+      AND (pr.projectnumber ILIKE ?) OR EXISTS (
+        SELECT * FROM orderitems oi
+        LEFT JOIN project proi ON proi.id = oi.project_id
+        WHERE proi.projectnumber ILIKE ? AND oi.trans_id = o.id
+      )
+SQL
+    push @values, "%" . $form->{"projectnumber"} . "%", "%" . $form->{"projectnumber"} . "%" ;
   }
 
   if ($form->{"${vc}_id"}) {
@@ -107,6 +122,10 @@ sub transactions {
     push(@values, '%' . $form->{$vc} . '%');
   }
 
+  if (!$main::auth->assert('sales_all_edit', 1)) {
+    $query .= " AND o.employee_id = (select id from employee where login= ?)";
+    push @values, $form->{login};
+  }
   if ($form->{employee_id}) {
     $query .= " AND o.employee_id = ?";
     push @values, conv_i($form->{employee_id});
@@ -184,7 +203,7 @@ sub transactions {
 
   my %id = ();
   $form->{OE} = [];
-  while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+  while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
     $ref->{exchangerate} = 1 unless $ref->{exchangerate};
     push @{ $form->{OE} }, $ref if $ref->{id} != $id{ $ref->{id} };
     $id{ $ref->{id} } = $ref->{id};
@@ -248,6 +267,9 @@ sub save {
   my $all_units = AM->retrieve_units($myconfig, $form);
   $form->{all_units} = $all_units;
 
+  my $ic_cvar_configs = CVar->get_configs(module => 'IC',
+                                          dbh    => $dbh);
+
   $form->{employee_id} = (split /--/, $form->{employee})[1] if !$form->{employee_id};
   unless ($form->{employee_id}) {
     $form->get_employee($dbh);
@@ -256,6 +278,11 @@ sub save {
   my $ml = ($form->{type} eq 'sales_order') ? 1 : -1;
 
   if ($form->{id}) {
+    $query = qq|DELETE FROM custom_variables
+                WHERE (config_id IN (SELECT id FROM custom_variable_configs WHERE module = 'IC'))
+                  AND (sub_module = 'orderitems')
+                  AND (trans_id IN (SELECT id FROM orderitems WHERE trans_id = ?))|;
+    do_query($form, $dbh, $query, $form->{id});
 
     $query = qq|DELETE FROM orderitems WHERE trans_id = ?|;
     do_query($form, $dbh, $query, $form->{id});
@@ -279,6 +306,8 @@ sub save {
   my $project_id;
   my $reqdate;
   my $taxrate;
+  my $taxbase;
+  my $taxdiff;
   my $taxamount = 0;
   my $fxsellprice;
   my %taxbase;
@@ -308,8 +337,9 @@ sub save {
       my $baseqty = $form->{"qty_$i"} * $basefactor;
 
       $form->{"marge_percent_$i"} = $form->parse_amount($myconfig, $form->{"marge_percent_$i"}) * 1;
-      $form->{"marge_total_$i"} = $form->parse_amount($myconfig, $form->{"marge_total_$i"}) * 1;
-      $form->{"lastcost_$i"} = $form->{"lastcost_$i"} * 1;
+      $form->{"marge_absolut_$i"} = $form->parse_amount($myconfig, $form->{"marge_absolut_$i"}) * 1;
+      
+      $form->{"lastcost_$i"} = $form->parse_amount($myconfig, $form->{"lastcost_$i"});
 
       # set values to 0 if nothing entered
       $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
@@ -350,7 +380,7 @@ sub save {
 
       if ($form->round_amount($taxrate, 7) == 0) {
         if ($form->{taxincluded}) {
-          foreach $item (@taxaccounts) {
+          foreach my $item (@taxaccounts) {
             $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2);
             $taxaccounts{$item} += $taxamount;
             $taxdiff            += $taxamount;
@@ -358,13 +388,13 @@ sub save {
           }
           $taxaccounts{ $taxaccounts[0] } += $taxdiff;
         } else {
-          foreach $item (@taxaccounts) {
+          foreach my $item (@taxaccounts) {
             $taxaccounts{$item} += $linetotal * $form->{"${item}_rate"};
             $taxbase{$item}     += $taxbase;
           }
         }
       } else {
-        foreach $item (@taxaccounts) {
+        foreach my $item (@taxaccounts) {
           $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate;
           $taxbase{$item} += $taxbase;
         }
@@ -379,24 +409,19 @@ sub save {
       $pricegroup_id *= 1;
 
       # save detail record in orderitems table
+      my $orderitems_id = $form->{"orderitems_id_$i"};
+      ($orderitems_id)  = selectfirst_array_query($form, $dbh, qq|SELECT nextval('orderitemsid')|) if (!$orderitems_id);
+
       @values = ();
-      $query = qq|INSERT INTO orderitems (|;
-      if ($form->{"orderitems_id_$i"}) {
-        $query .= "id, ";
-      }
-      $query .= qq|trans_id, parts_id, description, longdescription, qty, base_qty, | .
-                qq|sellprice, discount, unit, reqdate, project_id, serialnumber, ship, | .
-                qq|pricegroup_id, ordnumber, transdate, cusordnumber, subtotal, | .
-                qq|marge_percent, marge_total, lastcost, price_factor_id, price_factor, marge_price_factor) | .
-                qq|VALUES (|;
-      if($form->{"orderitems_id_$i"}) {
-        $query .= qq|?,|;
-        push(@values, $form->{"orderitems_id_$i"});
-      }
-      $query .= qq|?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
-                   (SELECT factor FROM price_factors WHERE id = ?), ?)|;
+      $query = qq|INSERT INTO orderitems (
+                    id, trans_id, parts_id, description, longdescription, qty, base_qty,
+                    sellprice, discount, unit, reqdate, project_id, serialnumber, ship,
+                    pricegroup_id, ordnumber, transdate, cusordnumber, subtotal,
+                    marge_percent, marge_total, lastcost, price_factor_id, price_factor, marge_price_factor)
+                  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
+                          (SELECT factor FROM price_factors WHERE id = ?), ?)|;
       push(@values,
-           conv_i($form->{id}), conv_i($form->{"id_$i"}),
+           conv_i($orderitems_id), conv_i($form->{id}), conv_i($form->{"id_$i"}),
            $form->{"description_$i"}, $form->{"longdescription_$i"},
            $form->{"qty_$i"}, $baseqty,
            $fxsellprice, $form->{"discount_$i"},
@@ -404,7 +429,7 @@ sub save {
            $form->{"serialnumber_$i"}, $form->{"ship_$i"}, conv_i($pricegroup_id),
            $form->{"ordnumber_$i"}, conv_date($form->{"transdate_$i"}),
            $form->{"cusordnumber_$i"}, $form->{"subtotal_$i"} ? 't' : 'f',
-           $form->{"marge_percent_$i"}, $form->{"marge_total_$i"},
+           $form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
            $form->{"lastcost_$i"},
            conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
            conv_i($form->{"marge_price_factor_$i"}));
@@ -412,6 +437,15 @@ sub save {
 
       $form->{"sellprice_$i"} = $fxsellprice;
       $form->{"discount_$i"} *= 100;
+
+      CVar->save_custom_variables(module       => 'IC',
+                                  sub_module   => 'orderitems',
+                                  trans_id     => $orderitems_id,
+                                  configs      => $ic_cvar_configs,
+                                  variables    => $form,
+                                  name_prefix  => 'ic_',
+                                  name_postfix => "_$i",
+                                  dbh          => $dbh);
     }
   }
 
@@ -580,7 +614,7 @@ sub delete {
   my $query = qq|SELECT s.spoolfile FROM status s | .
               qq|WHERE s.trans_id = ?|;
   my @values = (conv_i($form->{id}));
-  $sth = $dbh->prepare($query);
+  my $sth = $dbh->prepare($query);
   $sth->execute(@values) || $self->dberror($query);
 
   my $spoolfile;
@@ -633,10 +667,13 @@ sub retrieve {
   my ($self, $myconfig, $form) = @_;
 
   # connect to database
-  my $dbh = $form->dbconnect_noauto($myconfig);
+  my $dbh = $form->get_standard_dbh;
 
   my ($query, $query_add, @values, @ids, $sth);
 
+  my $ic_cvar_configs = CVar->get_configs(module => 'IC',
+                                          dbh    => $dbh);
+
   # translate the ids (given by id_# and trans_id_#) into one array of ids, so we can join them later
   map {
     push @ids, $form->{"trans_id_$_"}
@@ -653,7 +690,9 @@ sub retrieve {
     undef @ids;
   }
 
-  my $query_add = '';
+  # and remember for the rest of the function
+  my $is_collective_order = scalar @ids;
+
   if (!$form->{id}) {
     my $wday         = (localtime(time))[6];
     my $next_workday = $wday == 5 ? 3 : $wday == 6 ? 2 : 1;
@@ -708,14 +747,14 @@ sub retrieve {
     @values = $form->{id} ? ($form->{id}) : @ids;
     $sth = prepare_execute_query($form, $dbh, $query, @values);
 
-    $ref = $sth->fetchrow_hashref(NAME_lc);
+    $ref = $sth->fetchrow_hashref("NAME_lc");
     map { $form->{$_} = $ref->{$_} } keys %$ref;
 
     $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ?
                                          "quonumber" : "ordnumber"};
 
     # set all entries for multiple ids blank that yield different information
-    while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+    while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
       map { $form->{$_} = '' if ($ref->{$_} ne $form->{$_}) } keys %$ref;
     }
 
@@ -740,7 +779,7 @@ sub retrieve {
       $query = qq|SELECT s.* FROM shipto s WHERE s.trans_id = ? AND s.module = 'OE'|;
       $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
 
-      $ref = $sth->fetchrow_hashref(NAME_lc);
+      $ref = $sth->fetchrow_hashref("NAME_lc");
       delete($ref->{id});
       map { $form->{$_} = $ref->{$_} } keys %$ref;
       $sth->finish;
@@ -749,7 +788,7 @@ sub retrieve {
       $query = qq|SELECT s.printed, s.emailed, s.spoolfile, s.formname FROM status s WHERE s.trans_id = ?|;
       $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
 
-      while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+      while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
         $form->{printed} .= "$ref->{formname} " if $ref->{printed};
         $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
         $form->{queued}  .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
@@ -797,7 +836,16 @@ sub retrieve {
     @ids = $form->{id} ? ($form->{id}) : @ids;
     $sth = prepare_execute_query($form, $dbh, $query, @values);
 
-    while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+    while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
+      # Retrieve custom variables.
+      my $cvars = CVar->get_custom_variables(dbh        => $dbh,
+                                             module     => 'IC',
+                                             sub_module => 'orderitems',
+                                             trans_id   => $ref->{orderitems_id},
+                                            );
+      map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
+
+      # Handle accounts.
       if (!$ref->{"part_inventory_accno_id"}) {
         map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid));
       }
@@ -847,7 +895,7 @@ sub retrieve {
       delete $ref->{orderitems_id} if (@ids);
 
       # get tax rates and description
-      $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
+      my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
       $query =
         qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber | .
         qq|FROM tax t LEFT JOIN chart c on (c.id = t.chart_id) | .
@@ -855,10 +903,10 @@ sub retrieve {
         qq|               WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?) | .
         qq|                 AND startdate <= $transdate ORDER BY startdate DESC LIMIT 1) | .
         qq|ORDER BY c.accno|;
-      $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
+      my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
       $ref->{taxaccounts} = "";
       my $i = 0;
-      while ($ptr = $stw->fetchrow_hashref(NAME_lc)) {
+      while (my $ptr = $stw->fetchrow_hashref("NAME_lc")) {
         if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
           $i++;
           $ptr->{accno} = $i;
@@ -874,6 +922,7 @@ sub retrieve {
       }
 
       chop $ref->{taxaccounts};
+
       push @{ $form->{form_details} }, $ref;
       $stw->finish;
     }
@@ -899,6 +948,30 @@ sub retrieve {
   return $rc;
 }
 
+sub retrieve_simple {
+  $main::lxdebug->enter_sub();
+
+  my $self     = shift;
+  my %params   = @_;
+
+  Common::check_params(\%params, qw(id));
+
+  my $myconfig    = \%main::myconfig;
+  my $form        = $main::form;
+
+  my $dbh         = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+  my $oe_query    = qq|SELECT * FROM oe         WHERE id = ?|;
+  my $oi_query    = qq|SELECT * FROM orderitems WHERE trans_id = ?|;
+
+  my $order            = selectfirst_hashref_query($form, $dbh, $oe_query, conv_i($params{id}));
+  $order->{orderitems} = selectall_hashref_query(  $form, $dbh, $oi_query, conv_i($params{id}));
+
+  $main::lxdebug->leave_sub();
+
+  return $order;
+}
+
 sub order_details {
   $main::lxdebug->enter_sub();
 
@@ -920,11 +993,16 @@ sub order_details {
   my $position = 0;
   my $subtotal_header = 0;
   my $subposition = 0;
+  my %taxaccounts;
+  my %taxbase;
+  my $tax_rate;
+  my $taxamount;
+
 
   my %oid = ('Pg'     => 'oid',
              'Oracle' => 'rowid');
 
-  my (@project_ids, %projectnumbers);
+  my (@project_ids, %projectnumbers, %projectdescriptions);
 
   push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});
 
@@ -956,31 +1034,38 @@ sub order_details {
   }
 
   if (@project_ids) {
-    $query = "SELECT id, projectnumber FROM project WHERE id IN (" .
+    $query = "SELECT id, projectnumber, description FROM project WHERE id IN (" .
       join(", ", map("?", @project_ids)) . ")";
     $sth = prepare_execute_query($form, $dbh, $query, @project_ids);
     while (my $ref = $sth->fetchrow_hashref()) {
       $projectnumbers{$ref->{id}} = $ref->{projectnumber};
+      $projectdescriptions{$ref->{id}} = $ref->{description};
     }
     $sth->finish();
   }
 
   $form->{"globalprojectnumber"} = $projectnumbers{$form->{"globalproject_id"}};
+  $form->{"globalprojectdescription"} = $projectdescriptions{$form->{"globalproject_id"}};
 
   $form->{discount} = [];
 
+  $form->{TEMPLATE_ARRAYS} = { };
   IC->prepare_parts_for_printing();
 
+  my $ic_cvar_configs = CVar->get_configs(module => 'IC');
+
   my @arrays =
     qw(runningnumber number description longdescription qty ship unit bin
        partnotes serialnumber reqdate sellprice listprice netprice
        discount p_discount discount_sub nodiscount_sub
-       linetotal  nodiscount_linetotal tax_rate projectnumber
+       linetotal  nodiscount_linetotal tax_rate projectnumber projectdescription
        price_factor price_factor_name partsgroup);
 
+  push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };
+
   my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);
 
-  $form->{TEMPLATE_ARRAYS} = { map { $_ => [] } (@arrays, @tax_arrays) };
+  map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays);
 
   my $sameitem = "";
   foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
@@ -1081,6 +1166,7 @@ sub order_details {
       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} }, $form->format_amount($myconfig, $nodiscount_linetotal, 2);
 
       push(@{ $form->{TEMPLATE_ARRAYS}->{projectnumber} }, $projectnumbers{$form->{"project_id_$i"}});
+      push(@{ $form->{TEMPLATE_ARRAYS}->{projectdescription} }, $projectdescriptions{$form->{"project_id_$i"}});
 
       my ($taxamount, $taxbase);
       my $taxrate = 0;
@@ -1119,17 +1205,17 @@ sub order_details {
         }
 
         $query = qq|SELECT p.partnumber, p.description, p.unit, a.qty, | .
-                      qq|pg.partsgroup | .
-                      qq|FROM assembly a | .
-                            qq|  JOIN parts p ON (a.parts_id = p.id) | .
-                            qq|    LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
-                            qq|    WHERE a.bom = '1' | .
-                            qq|    AND a.id = ? | . $sortorder;
-                   @values = ($form->{"id_$i"});
+                 qq|pg.partsgroup | .
+                 qq|FROM assembly a | .
+                 qq|  JOIN parts p ON (a.parts_id = p.id) | .
+                 qq|    LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
+                 qq|    WHERE a.bom = '1' | .
+                 qq|    AND a.id = ? | . $sortorder;
+        @values = ($form->{"id_$i"});
         $sth = $dbh->prepare($query);
         $sth->execute(@values) || $form->dberror($query);
 
-        while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+        while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
           if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
             map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
             $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
@@ -1142,6 +1228,7 @@ sub order_details {
         $sth->finish;
       }
 
+      map { push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} }, $form->{"ic_cvar_$_->{name}_$i"} } @{ $ic_cvar_configs };
     }
   }
 
@@ -1191,11 +1278,77 @@ sub project_description {
   my ($self, $dbh, $id) = @_;
 
   my $query = qq|SELECT description FROM project WHERE id = ?|;
-  my ($value) = selectrow_query($form, $dbh, $query, $id);
+  my ($value) = selectrow_query($main::form, $dbh, $query, $id);
 
   $main::lxdebug->leave_sub();
 
   return $value;
 }
 
+##########################
+# Get data for the submitted order id
+# from database
+#
+sub get_order_data_by_ordnumber {
+  $main::lxdebug->enter_sub();
+
+  my $self      = shift;
+  my %params    = @_;
+
+  Common::check_params(\%params, qw(ordnumber));
+
+  my $form     = $main::form;
+  my %myconfig = %main::myconfig;
+  my $dbh      = $form->get_standard_dbh();
+
+  my @values = ($params{ordnumber});
+
+  # We query the database for the fields we need using the submitted "ordnumber"
+  my $query = <<SQL;
+    SELECT o.payment_id, o.salesman_id, o.transdate AS orddate, o.taxzone_id, o.quonumber
+    FROM oe o
+    WHERE o.ordnumber = ?;
+SQL
+
+  # Do the actual query and return the results for later processing by our "frontend"
+  my $result = selectfirst_hashref_query($form, $dbh, $query, @values);
+
+  $main::lxdebug->leave_sub();
+
+  return $result;
+}
+
 1;
+
+__END__
+
+=head1 NAME
+
+OE.pm - Order entry module
+
+=head1 DESCRIPTION
+
+OE.pm is part of the OE module. OE is responsible for sales and purchase orders, as well as sales quotations and purchase requests. This file abstracts the database tables C<oe> and C<orderitems>.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item retrieve_simple PARAMS
+
+simple OE retrieval by id. does not look up customer, vendor, units or any other stuff. only oe and orderitems.
+
+  my $order = retrieve_simple(id => 2);
+
+  $order => {
+    %_OE_CONTENT,
+    orderitems => [
+      %_ORDERITEM_ROW_1,
+      %_ORDERITEM_ROW_2,
+      ...
+    ]
+  }
+
+=back
+
+=cut