1 #====================================================================
 
   4 # Based on SQL-Ledger Version 2.1.9
 
   5 # Web http://www.lx-office.org
 
   7 #=====================================================================
 
   8 # SQL-Ledger Accounting
 
   9 # Copyright (C) 1999-2003
 
  11 #  Author: Dieter Simader
 
  12 #   Email: dsimader@sql-ledger.org
 
  13 #     Web: http://www.sql-ledger.org
 
  17 # This program is free software; you can redistribute it and/or modify
 
  18 # it under the terms of the GNU General Public License as published by
 
  19 # the Free Software Foundation; either version 2 of the License, or
 
  20 # (at your option) any later version.
 
  22 # This program is distributed in the hope that it will be useful,
 
  23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  25 # GNU General Public License for more details.
 
  26 # You should have received a copy of the GNU General Public License
 
  27 # along with this program; if not, write to the Free Software
 
  28 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
  29 #======================================================================
 
  33 #======================================================================
 
  37 use List::Util qw(max first);
 
  47   $main::lxdebug->enter_sub();
 
  49   my ($self, $myconfig, $form) = @_;
 
  52   my $dbh = $form->dbconnect($myconfig);
 
  55   my $ordnumber = 'ordnumber';
 
  61   my $rate = ($form->{vc} eq 'customer') ? 'buy' : 'sell';
 
  63   if ($form->{type} =~ /_quotation$/) {
 
  65     $ordnumber = 'quonumber';
 
  68   my $vc = $form->{vc} eq "customer" ? "customer" : "vendor";
 
  71     qq|SELECT o.id, o.ordnumber, o.transdate, o.reqdate, | .
 
  72     qq|  o.amount, ct.name, o.netamount, o.${vc}_id, o.globalproject_id, | .
 
  73     qq|  o.closed, o.delivered, o.quonumber, o.shippingpoint, o.shipvia, | .
 
  74     qq|  o.transaction_description, | .
 
  75     qq|  o.marge_total, o.marge_percent, | .
 
  76     qq|  ex.$rate AS exchangerate, | .
 
  77     qq|  pr.projectnumber AS globalprojectnumber, | .
 
  78     qq|  e.name AS employee, s.name AS salesman, | .
 
  79     qq|  ct.${vc}number AS vcnumber, ct.country, ct.ustid  | .
 
  81     qq|JOIN $vc ct ON (o.${vc}_id = ct.id) | .
 
  82     qq|LEFT JOIN employee e ON (o.employee_id = e.id) | .
 
  83     qq|LEFT JOIN employee s ON (o.salesman_id = s.id) | .
 
  84     qq|LEFT JOIN exchangerate ex ON (ex.curr = o.curr | .
 
  85     qq|  AND ex.transdate = o.transdate) | .
 
  86     qq|LEFT JOIN project pr ON (o.globalproject_id = pr.id) | .
 
  87     qq|WHERE (o.quotation = ?) |;
 
  88   push(@values, $quotation);
 
  90   my ($null, $split_department_id) = split /--/, $form->{department};
 
  91   my $department_id = $form->{department_id} || $split_department_id;
 
  93     $query .= qq| AND o.department_id = ?|;
 
  94     push(@values, $department_id);
 
  97   if ($form->{"project_id"}) {
 
  99       qq|AND ((globalproject_id = ?) OR EXISTS | .
 
 100       qq|  (SELECT * FROM orderitems oi | .
 
 101       qq|   WHERE oi.project_id = ? AND oi.trans_id = o.id))|;
 
 102     push(@values, conv_i($form->{"project_id"}), conv_i($form->{"project_id"}));
 
 105   if ($form->{"projectnumber"}) {
 
 107       AND (pr.projectnumber ILIKE ?) OR EXISTS (
 
 108         SELECT * FROM orderitems oi
 
 109         LEFT JOIN project proi ON proi.id = oi.project_id
 
 110         WHERE proi.projectnumber ILIKE ? AND oi.trans_id = o.id
 
 113     push @values, "%" . $form->{"projectnumber"} . "%", "%" . $form->{"projectnumber"} . "%" ;
 
 116   if ($form->{"${vc}_id"}) {
 
 117     $query .= " AND o.${vc}_id = ?";
 
 118     push(@values, $form->{"${vc}_id"});
 
 120   } elsif ($form->{$vc}) {
 
 121     $query .= " AND ct.name ILIKE ?";
 
 122     push(@values, '%' . $form->{$vc} . '%');
 
 125   if (!$main::auth->assert('sales_all_edit', 1)) {
 
 126     $query .= " AND o.employee_id = (select id from employee where login= ?)";
 
 127     push @values, $form->{login};
 
 129   if ($form->{employee_id}) {
 
 130     $query .= " AND o.employee_id = ?";
 
 131     push @values, conv_i($form->{employee_id});
 
 134   if ($form->{salesman_id}) {
 
 135     $query .= " AND o.salesman_id = ?";
 
 136     push @values, conv_i($form->{salesman_id});
 
 139   if (!$form->{open} && !$form->{closed}) {
 
 140     $query .= " AND o.id = 0";
 
 141   } elsif (!($form->{open} && $form->{closed})) {
 
 142     $query .= ($form->{open}) ? " AND o.closed = '0'" : " AND o.closed = '1'";
 
 145   if (($form->{"notdelivered"} || $form->{"delivered"}) &&
 
 146       ($form->{"notdelivered"} ne $form->{"delivered"})) {
 
 147     $query .= $form->{"delivered"} ?
 
 148       " AND o.delivered " : " AND NOT o.delivered";
 
 151   if ($form->{$ordnumber}) {
 
 152     $query .= qq| AND o.$ordnumber ILIKE ?|;
 
 153     push(@values, '%' . $form->{$ordnumber} . '%');
 
 156   if($form->{transdatefrom}) {
 
 157     $query .= qq| AND o.transdate >= ?|;
 
 158     push(@values, conv_date($form->{transdatefrom}));
 
 161   if($form->{transdateto}) {
 
 162     $query .= qq| AND o.transdate <= ?|;
 
 163     push(@values, conv_date($form->{transdateto}));
 
 166   if($form->{reqdatefrom}) {
 
 167     $query .= qq| AND o.reqdate >= ?|;
 
 168     push(@values, conv_date($form->{reqdatefrom}));
 
 171   if($form->{reqdateto}) {
 
 172     $query .= qq| AND o.reqdate <= ?|;
 
 173     push(@values, conv_date($form->{reqdateto}));
 
 176   if ($form->{transaction_description}) {
 
 177     $query .= qq| AND o.transaction_description ILIKE ?|;
 
 178     push(@values, '%' . $form->{transaction_description} . '%');
 
 181   my $sortdir   = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
 
 182   my $sortorder = join(', ', map { "${_} ${sortdir} " } ("o.id", $form->sort_columns("transdate", $ordnumber, "name")));
 
 183   my %allowed_sort_columns = (
 
 184     "transdate"               => "o.transdate",
 
 185     "reqdate"                 => "o.reqdate",
 
 187     "ordnumber"               => "o.ordnumber",
 
 188     "quonumber"               => "o.quonumber",
 
 190     "employee"                => "e.name",
 
 191     "salesman"                => "e.name",
 
 192     "shipvia"                 => "o.shipvia",
 
 193     "transaction_description" => "o.transaction_description"
 
 195   if ($form->{sort} && grep($form->{sort}, keys(%allowed_sort_columns))) {
 
 196     $sortorder = $allowed_sort_columns{$form->{sort}} . " ${sortdir}";
 
 198   $query .= qq| ORDER by | . $sortorder;
 
 200   my $sth = $dbh->prepare($query);
 
 201   $sth->execute(@values) ||
 
 202     $form->dberror($query . " (" . join(", ", @values) . ")");
 
 206   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 207     $ref->{exchangerate} = 1 unless $ref->{exchangerate};
 
 208     push @{ $form->{OE} }, $ref if $ref->{id} != $id{ $ref->{id} };
 
 209     $id{ $ref->{id} } = $ref->{id};
 
 215   $main::lxdebug->leave_sub();
 
 218 sub transactions_for_todo_list {
 
 219   $main::lxdebug->enter_sub();
 
 224   my $myconfig = \%main::myconfig;
 
 225   my $form     = $main::form;
 
 227   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
 
 229   my $query    = qq|SELECT id FROM employee WHERE login = ?|;
 
 230   my ($e_id)   = selectrow_query($form, $dbh, $query, $form->{login});
 
 233     qq|SELECT oe.id, oe.transdate, oe.reqdate, oe.quonumber, oe.transaction_description, oe.amount,
 
 234          CASE WHEN (COALESCE(oe.customer_id, 0) = 0) THEN 'vendor' ELSE 'customer' END AS vc,
 
 239        LEFT JOIN customer c ON (oe.customer_id = c.id)
 
 240        LEFT JOIN vendor v   ON (oe.vendor_id   = v.id)
 
 241        LEFT JOIN employee e ON (oe.employee_id = e.id)
 
 242        WHERE (COALESCE(quotation, FALSE) = TRUE)
 
 243          AND (COALESCE(closed,    FALSE) = FALSE)
 
 244          AND ((oe.employee_id = ?) OR (oe.salesman_id = ?))
 
 245          AND NOT (oe.reqdate ISNULL)
 
 246          AND (oe.reqdate < current_date)
 
 249   my $quotations = selectall_hashref_query($form, $dbh, $query, $e_id, $e_id);
 
 251   $main::lxdebug->leave_sub();
 
 257   $main::lxdebug->enter_sub();
 
 259   my ($self, $myconfig, $form) = @_;
 
 261   # connect to database, turn off autocommit
 
 262   my $dbh = $form->dbconnect_noauto($myconfig);
 
 264   my ($query, @values, $sth, $null);
 
 265   my $exchangerate = 0;
 
 267   my $all_units = AM->retrieve_units($myconfig, $form);
 
 268   $form->{all_units} = $all_units;
 
 270   my $ic_cvar_configs = CVar->get_configs(module => 'IC',
 
 273   $form->{employee_id} = (split /--/, $form->{employee})[1] if !$form->{employee_id};
 
 274   unless ($form->{employee_id}) {
 
 275     $form->get_employee($dbh);
 
 278   my $ml = ($form->{type} eq 'sales_order') ? 1 : -1;
 
 281     $query = qq|DELETE FROM custom_variables
 
 282                 WHERE (config_id IN (SELECT id FROM custom_variable_configs WHERE module = 'IC'))
 
 283                   AND (sub_module = 'orderitems')
 
 284                   AND (trans_id IN (SELECT id FROM orderitems WHERE trans_id = ?))|;
 
 285     do_query($form, $dbh, $query, $form->{id});
 
 287     $query = qq|DELETE FROM orderitems WHERE trans_id = ?|;
 
 288     do_query($form, $dbh, $query, $form->{id});
 
 290     $query = qq|DELETE FROM shipto | .
 
 291              qq|WHERE trans_id = ? AND module = 'OE'|;
 
 292     do_query($form, $dbh, $query, $form->{id});
 
 296     $query = qq|SELECT nextval('id')|;
 
 297     ($form->{id}) = selectrow_query($form, $dbh, $query);
 
 299     $query = qq|INSERT INTO oe (id, ordnumber, employee_id) VALUES (?, '', ?)|;
 
 300     do_query($form, $dbh, $query, $form->{id}, $form->{employee_id});
 
 318   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
 
 319   my %price_factors = map { $_->{id} => $_->{factor} } @{ $form->{ALL_PRICE_FACTORS} };
 
 322   for my $i (1 .. $form->{rowcount}) {
 
 324     map({ $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"}) } qw(qty ship));
 
 326     if ($form->{"id_$i"}) {
 
 329       $query = qq|SELECT unit FROM parts WHERE id = ?|;
 
 330       my ($item_unit) = selectrow_query($form, $dbh, $query, $form->{"id_$i"});
 
 333       if (defined($all_units->{$item_unit}->{factor}) &&
 
 334           (($all_units->{$item_unit}->{factor} * 1) != 0)) {
 
 335         $basefactor = $all_units->{$form->{"unit_$i"}}->{factor} / $all_units->{$item_unit}->{factor};
 
 337       my $baseqty = $form->{"qty_$i"} * $basefactor;
 
 339       $form->{"marge_percent_$i"} = $form->parse_amount($myconfig, $form->{"marge_percent_$i"}) * 1;
 
 340       $form->{"marge_total_$i"} = $form->parse_amount($myconfig, $form->{"marge_total_$i"}) * 1;
 
 341       $form->{"lastcost_$i"} = $form->{"lastcost_$i"} * 1;
 
 343       # set values to 0 if nothing entered
 
 344       $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
 
 346       $form->{"sellprice_$i"} = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 347       $fxsellprice = $form->{"sellprice_$i"};
 
 349       my ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
 
 351       my $decimalplaces = ($dec > 2) ? $dec : 2;
 
 353       $discount = $form->round_amount($form->{"sellprice_$i"} * $form->{"discount_$i"}, $decimalplaces);
 
 354       $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} - $discount, $decimalplaces);
 
 356       $form->{"inventory_accno_$i"} *= 1;
 
 357       $form->{"expense_accno_$i"}   *= 1;
 
 359       $price_factor = $price_factors{ $form->{"price_factor_id_$i"} } || 1;
 
 360       $linetotal    = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2);
 
 362       @taxaccounts = split(/ /, $form->{"taxaccounts_$i"});
 
 366       map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;
 
 368       if ($form->{taxincluded}) {
 
 369         $taxamount = $linetotal * $taxrate / (1 + $taxrate);
 
 370         $taxbase   = $linetotal - $taxamount;
 
 372         # we are not keeping a natural price, do not round
 
 373         $form->{"sellprice_$i"} =
 
 374           $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
 
 376         $taxamount = $linetotal * $taxrate;
 
 377         $taxbase   = $linetotal;
 
 380       if ($form->round_amount($taxrate, 7) == 0) {
 
 381         if ($form->{taxincluded}) {
 
 382           foreach my $item (@taxaccounts) {
 
 383             $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2);
 
 384             $taxaccounts{$item} += $taxamount;
 
 385             $taxdiff            += $taxamount;
 
 386             $taxbase{$item}     += $taxbase;
 
 388           $taxaccounts{ $taxaccounts[0] } += $taxdiff;
 
 390           foreach my $item (@taxaccounts) {
 
 391             $taxaccounts{$item} += $linetotal * $form->{"${item}_rate"};
 
 392             $taxbase{$item}     += $taxbase;
 
 396         foreach my $item (@taxaccounts) {
 
 397           $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate;
 
 398           $taxbase{$item} += $taxbase;
 
 402       $netamount += $form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor;
 
 404       $reqdate = ($form->{"reqdate_$i"}) ? $form->{"reqdate_$i"} : undef;
 
 406       # get pricegroup_id and save ist
 
 407       ($null, my $pricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
 
 410       # save detail record in orderitems table
 
 411       my $orderitems_id = $form->{"orderitems_id_$i"};
 
 412       ($orderitems_id)  = selectfirst_array_query($form, $dbh, qq|SELECT nextval('orderitemsid')|) if (!$orderitems_id);
 
 415       $query = qq|INSERT INTO orderitems (
 
 416                     id, trans_id, parts_id, description, longdescription, qty, base_qty,
 
 417                     sellprice, discount, unit, reqdate, project_id, serialnumber, ship,
 
 418                     pricegroup_id, ordnumber, transdate, cusordnumber, subtotal,
 
 419                     marge_percent, marge_total, lastcost, price_factor_id, price_factor, marge_price_factor)
 
 420                   VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
 
 421                           (SELECT factor FROM price_factors WHERE id = ?), ?)|;
 
 423            conv_i($orderitems_id), conv_i($form->{id}), conv_i($form->{"id_$i"}),
 
 424            $form->{"description_$i"}, $form->{"longdescription_$i"},
 
 425            $form->{"qty_$i"}, $baseqty,
 
 426            $fxsellprice, $form->{"discount_$i"},
 
 427            $form->{"unit_$i"}, conv_date($reqdate), conv_i($form->{"project_id_$i"}),
 
 428            $form->{"serialnumber_$i"}, $form->{"ship_$i"}, conv_i($pricegroup_id),
 
 429            $form->{"ordnumber_$i"}, conv_date($form->{"transdate_$i"}),
 
 430            $form->{"cusordnumber_$i"}, $form->{"subtotal_$i"} ? 't' : 'f',
 
 431            $form->{"marge_percent_$i"}, $form->{"marge_total_$i"},
 
 432            $form->{"lastcost_$i"},
 
 433            conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
 
 434            conv_i($form->{"marge_price_factor_$i"}));
 
 435       do_query($form, $dbh, $query, @values);
 
 437       $form->{"sellprice_$i"} = $fxsellprice;
 
 438       $form->{"discount_$i"} *= 100;
 
 440       CVar->save_custom_variables(module       => 'IC',
 
 441                                   sub_module   => 'orderitems',
 
 442                                   trans_id     => $orderitems_id,
 
 443                                   configs      => $ic_cvar_configs,
 
 445                                   name_prefix  => 'ic_',
 
 446                                   name_postfix => "_$i",
 
 451   $reqdate = ($form->{reqdate}) ? $form->{reqdate} : undef;
 
 455   map { $tax += $form->round_amount($taxaccounts{$_}, 2) } keys %taxaccounts;
 
 457   $amount = $form->round_amount($netamount + $tax, 2);
 
 458   $netamount = $form->round_amount($netamount, 2);
 
 460   if ($form->{currency} eq $form->{defaultcurrency}) {
 
 461     $form->{exchangerate} = 1;
 
 463     $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? 'buy' : 'sell');
 
 466   $form->{exchangerate} = $exchangerate || $form->parse_amount($myconfig, $form->{exchangerate});
 
 468   my $quotation = $form->{type} =~ /_order$/ ? 'f' : 't';
 
 470   ($null, $form->{department_id}) = split(/--/, $form->{department}) if $form->{department};
 
 475          ordnumber = ?, quonumber = ?, cusordnumber = ?, transdate = ?, vendor_id = ?,
 
 476          customer_id = ?, amount = ?, netamount = ?, reqdate = ?, taxincluded = ?,
 
 477          shippingpoint = ?, shipvia = ?, notes = ?, intnotes = ?, curr = ?, closed = ?,
 
 478          delivered = ?, proforma = ?, quotation = ?, department_id = ?, language_id = ?,
 
 479          taxzone_id = ?, shipto_id = ?, payment_id = ?, delivery_vendor_id = ?, delivery_customer_id = ?,
 
 480          globalproject_id = ?, employee_id = ?, salesman_id = ?, cp_id = ?, transaction_description = ?, marge_total = ?, marge_percent = ?
 
 483   @values = ($form->{ordnumber} || '', $form->{quonumber},
 
 484              $form->{cusordnumber}, conv_date($form->{transdate}),
 
 485              conv_i($form->{vendor_id}), conv_i($form->{customer_id}),
 
 486              $amount, $netamount, conv_date($reqdate),
 
 487              $form->{taxincluded} ? 't' : 'f', $form->{shippingpoint},
 
 488              $form->{shipvia}, $form->{notes}, $form->{intnotes},
 
 489              substr($form->{currency}, 0, 3), $form->{closed} ? 't' : 'f',
 
 490              $form->{delivered} ? "t" : "f", $form->{proforma} ? 't' : 'f',
 
 491              $quotation, conv_i($form->{department_id}),
 
 492              conv_i($form->{language_id}), conv_i($form->{taxzone_id}),
 
 493              conv_i($form->{shipto_id}), conv_i($form->{payment_id}),
 
 494              conv_i($form->{delivery_vendor_id}),
 
 495              conv_i($form->{delivery_customer_id}),
 
 496              conv_i($form->{globalproject_id}), conv_i($form->{employee_id}),
 
 497              conv_i($form->{salesman_id}), conv_i($form->{cp_id}),
 
 498              $form->{transaction_description},
 
 499              $form->{marge_total} * 1, $form->{marge_percent} * 1,
 
 500              conv_i($form->{id}));
 
 501   do_query($form, $dbh, $query, @values);
 
 503   $form->{ordtotal} = $amount;
 
 506   $form->{name} = $form->{ $form->{vc} };
 
 507   $form->{name} =~ s/--\Q$form->{"$form->{vc}_id"}\E//;
 
 509   if (!$form->{shipto_id}) {
 
 510     $form->add_shipto($dbh, $form->{id}, "OE");
 
 513   # save printed, emailed, queued
 
 514   $form->save_status($dbh);
 
 516   # Link this record to the records it was created from.
 
 517   $form->{convert_from_oe_ids} =~ s/^\s+//;
 
 518   $form->{convert_from_oe_ids} =~ s/\s+$//;
 
 519   my @convert_from_oe_ids      =  split m/\s+/, $form->{convert_from_oe_ids};
 
 520   delete $form->{convert_from_oe_ids};
 
 522   if (scalar @convert_from_oe_ids) {
 
 523     RecordLinks->create_links('dbh'        => $dbh,
 
 525                               'from_table' => 'oe',
 
 526                               'from_ids'   => \@convert_from_oe_ids,
 
 528                               'to_id'      => $form->{id},
 
 531     $self->_close_quotations_rfqs('dbh'     => $dbh,
 
 532                                   'from_id' => \@convert_from_oe_ids,
 
 533                                   'to_id'   => $form->{id});
 
 536   if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
 
 537     if ($form->{vc} eq 'customer') {
 
 538       $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, $form->{exchangerate}, 0);
 
 540     if ($form->{vc} eq 'vendor') {
 
 541       $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, 0, $form->{exchangerate});
 
 545   $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ?
 
 546                                        "quonumber" : "ordnumber"};
 
 548   Common::webdav_folder($form) if ($main::webdav);
 
 550   my $rc = $dbh->commit;
 
 553   $main::lxdebug->leave_sub();
 
 558 sub _close_quotations_rfqs {
 
 559   $main::lxdebug->enter_sub();
 
 564   Common::check_params(\%params, qw(from_id to_id));
 
 566   my $myconfig = \%main::myconfig;
 
 567   my $form     = $main::form;
 
 569   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
 
 571   my $query    = qq|SELECT quotation FROM oe WHERE id = ?|;
 
 572   my $sth      = prepare_query($form, $dbh, $query);
 
 574   do_statement($form, $sth, $query, conv_i($params{to_id}));
 
 576   my ($quotation) = $sth->fetchrow_array();
 
 579     $main::lxdebug->leave_sub();
 
 585   foreach my $from_id (@{ $params{from_id} }) {
 
 586     $from_id = conv_i($from_id);
 
 587     do_statement($form, $sth, $query, $from_id);
 
 588     ($quotation) = $sth->fetchrow_array();
 
 589     push @close_ids, $from_id if ($quotation);
 
 594   if (scalar @close_ids) {
 
 595     $query = qq|UPDATE oe SET closed = TRUE WHERE id IN (| . join(', ', ('?') x scalar @close_ids) . qq|)|;
 
 596     do_query($form, $dbh, $query, @close_ids);
 
 598     $dbh->commit() unless ($params{dbh});
 
 601   $main::lxdebug->leave_sub();
 
 605   $main::lxdebug->enter_sub();
 
 607   my ($self, $myconfig, $form, $spool) = @_;
 
 609   # connect to database
 
 610   my $dbh = $form->dbconnect_noauto($myconfig);
 
 613   my $query = qq|SELECT s.spoolfile FROM status s | .
 
 614               qq|WHERE s.trans_id = ?|;
 
 615   my @values = (conv_i($form->{id}));
 
 616   my $sth = $dbh->prepare($query);
 
 617   $sth->execute(@values) || $self->dberror($query);
 
 622   while (($spoolfile) = $sth->fetchrow_array) {
 
 623     push @spoolfiles, $spoolfile;
 
 628   @values = (conv_i($form->{id}));
 
 630   # delete status entries
 
 631   $query = qq|DELETE FROM status | .
 
 632            qq|WHERE trans_id = ?|;
 
 633   do_query($form, $dbh, $query, @values);
 
 636   $query = qq|DELETE FROM oe | .
 
 638   do_query($form, $dbh, $query, @values);
 
 640   # delete individual entries
 
 641   $query = qq|DELETE FROM orderitems | .
 
 642            qq|WHERE trans_id = ?|;
 
 643   do_query($form, $dbh, $query, @values);
 
 645   $query = qq|DELETE FROM shipto | .
 
 646            qq|WHERE trans_id = ? AND module = 'OE'|;
 
 647   do_query($form, $dbh, $query, @values);
 
 649   my $rc = $dbh->commit;
 
 653     foreach $spoolfile (@spoolfiles) {
 
 654       unlink "$spool/$spoolfile" if $spoolfile;
 
 658   $main::lxdebug->leave_sub();
 
 664   $main::lxdebug->enter_sub();
 
 666   my ($self, $myconfig, $form) = @_;
 
 668   # connect to database
 
 669   my $dbh = $form->dbconnect_noauto($myconfig);
 
 671   my ($query, $query_add, @values, @ids, $sth);
 
 673   my $ic_cvar_configs = CVar->get_configs(module => 'IC',
 
 676   # translate the ids (given by id_# and trans_id_#) into one array of ids, so we can join them later
 
 678     push @ids, $form->{"trans_id_$_"}
 
 679       if ($form->{"multi_id_$_"} and $form->{"trans_id_$_"})
 
 680   } (1 .. $form->{"rowcount"});
 
 682   if ($form->{rowcount} && scalar @ids) {
 
 683     $form->{convert_from_oe_ids} = join ' ', @ids;
 
 686   # if called in multi id mode, and still only got one id, switch back to single id
 
 687   if ($form->{"rowcount"} and $#ids == 0) {
 
 688     $form->{"id"} = $ids[0];
 
 692   # and remember for the rest of the function
 
 693   my $is_collective_order = scalar @ids;
 
 696     my $wday         = (localtime(time))[6];
 
 697     my $next_workday = $wday == 5 ? 3 : $wday == 6 ? 2 : 1;
 
 698     $query_add       = qq|, current_date AS transdate, date(current_date + interval '${next_workday} days') AS reqdate|;
 
 701   # get default accounts
 
 702   $query = qq|SELECT (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
 
 703                      (SELECT c.accno FROM chart c WHERE d.income_accno_id    = c.id) AS income_accno,
 
 704                      (SELECT c.accno FROM chart c WHERE d.expense_accno_id   = c.id) AS expense_accno,
 
 705                      (SELECT c.accno FROM chart c WHERE d.fxgain_accno_id    = c.id) AS fxgain_accno,
 
 706                      (SELECT c.accno FROM chart c WHERE d.fxloss_accno_id    = c.id) AS fxloss_accno,
 
 710   my $ref = selectfirst_hashref_query($form, $dbh, $query);
 
 711   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 713   ($form->{currency}) = split(/:/, $form->{currencies}) unless ($form->{currency});
 
 715   # set reqdate if this is an invoice->order conversion. If someone knows a better check to ensure
 
 716   # we come from invoices, feel free.
 
 717   $form->{reqdate} = $form->{deliverydate}
 
 718     if (    $form->{deliverydate}
 
 719         and $form->{callback} =~ /action=ar_transactions/);
 
 721   my $vc = $form->{vc} eq "customer" ? "customer" : "vendor";
 
 723   if ($form->{id} or @ids) {
 
 725     # retrieve order for single id
 
 726     # NOTE: this query is intended to fetch all information only ONCE.
 
 727     # so if any of these infos is important (or even different) for any item,
 
 728     # it will be killed out and then has to be fetched from the item scope query further down
 
 730       qq|SELECT o.cp_id, o.ordnumber, o.transdate, o.reqdate,
 
 731            o.taxincluded, o.shippingpoint, o.shipvia, o.notes, o.intnotes,
 
 732            o.curr AS currency, e.name AS employee, o.employee_id, o.salesman_id,
 
 733            o.${vc}_id, cv.name AS ${vc}, o.amount AS invtotal,
 
 734            o.closed, o.reqdate, o.quonumber, o.department_id, o.cusordnumber,
 
 735            d.description AS department, o.payment_id, o.language_id, o.taxzone_id,
 
 736            o.delivery_customer_id, o.delivery_vendor_id, o.proforma, o.shipto_id,
 
 737            o.globalproject_id, o.delivered, o.transaction_description
 
 739          JOIN ${vc} cv ON (o.${vc}_id = cv.id)
 
 740          LEFT JOIN employee e ON (o.employee_id = e.id)
 
 741          LEFT JOIN department d ON (o.department_id = d.id) | .
 
 744          : "WHERE o.id IN (" . join(', ', map("? ", @ids)) . ")"
 
 746     @values = $form->{id} ? ($form->{id}) : @ids;
 
 747     $sth = prepare_execute_query($form, $dbh, $query, @values);
 
 749     $ref = $sth->fetchrow_hashref("NAME_lc");
 
 750     map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 752     $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ?
 
 753                                          "quonumber" : "ordnumber"};
 
 755     # set all entries for multiple ids blank that yield different information
 
 756     while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 757       map { $form->{$_} = '' if ($ref->{$_} ne $form->{$_}) } keys %$ref;
 
 760     # if not given, fill transdate with current_date
 
 761     $form->{transdate} = $form->current_date($myconfig)
 
 762       unless $form->{transdate};
 
 766     if ($form->{delivery_customer_id}) {
 
 767       $query = qq|SELECT name FROM customer WHERE id = ?|;
 
 768       ($form->{delivery_customer_string}) = selectrow_query($form, $dbh, $query, $form->{delivery_customer_id});
 
 771     if ($form->{delivery_vendor_id}) {
 
 772       $query = qq|SELECT name FROM customer WHERE id = ?|;
 
 773       ($form->{delivery_vendor_string}) = selectrow_query($form, $dbh, $query, $form->{delivery_vendor_id});
 
 776     # shipto and pinted/mailed/queued status makes only sense for single id retrieve
 
 778       $query = qq|SELECT s.* FROM shipto s WHERE s.trans_id = ? AND s.module = 'OE'|;
 
 779       $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
 
 781       $ref = $sth->fetchrow_hashref("NAME_lc");
 
 783       map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 786       # get printed, emailed and queued
 
 787       $query = qq|SELECT s.printed, s.emailed, s.spoolfile, s.formname FROM status s WHERE s.trans_id = ?|;
 
 788       $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
 
 790       while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 791         $form->{printed} .= "$ref->{formname} " if $ref->{printed};
 
 792         $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
 
 793         $form->{queued}  .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
 
 796       map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
 
 799     my %oid = ('Pg'     => 'oid',
 
 800                'Oracle' => 'rowid');
 
 802     my $transdate = $form->{transdate} ? $dbh->quote($form->{transdate}) : "current_date";
 
 804     $form->{taxzone_id} = 0 unless ($form->{taxzone_id});
 
 806     # retrieve individual items
 
 807     # this query looks up all information about the items
 
 808     # stuff different from the whole will not be overwritten, but saved with a suffix.
 
 810       qq|SELECT o.id AS orderitems_id,
 
 811            c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from as inventory_valid,
 
 812            c2.accno AS income_accno,    c2.new_chart_id AS income_new_chart,    date($transdate) - c2.valid_from as income_valid,
 
 813            c3.accno AS expense_accno,   c3.new_chart_id AS expense_new_chart,   date($transdate) - c3.valid_from as expense_valid,
 
 814            oe.ordnumber AS ordnumber_oe, oe.transdate AS transdate_oe, oe.cusordnumber AS cusordnumber_oe,
 
 815            p.partnumber, p.assembly, o.description, o.qty,
 
 816            o.sellprice, o.parts_id AS id, o.unit, o.discount, p.bin, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id,
 
 817            o.reqdate, o.project_id, o.serialnumber, o.ship, o.lastcost,
 
 818            o.ordnumber, o.transdate, o.cusordnumber, o.subtotal, o.longdescription,
 
 819            o.price_factor_id, o.price_factor, o.marge_price_factor,
 
 820            pr.projectnumber, p.formel,
 
 821            pg.partsgroup, o.pricegroup_id, (SELECT pricegroup FROM pricegroup WHERE id=o.pricegroup_id) as pricegroup
 
 823          JOIN parts p ON (o.parts_id = p.id)
 
 824          JOIN oe ON (o.trans_id = oe.id)
 
 825          LEFT JOIN chart c1 ON ((SELECT inventory_accno_id                   FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c1.id)
 
 826          LEFT JOIN chart c2 ON ((SELECT income_accno_id_$form->{taxzone_id}  FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c2.id)
 
 827          LEFT JOIN chart c3 ON ((SELECT expense_accno_id_$form->{taxzone_id} FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c3.id)
 
 828          LEFT JOIN project pr ON (o.project_id = pr.id)
 
 829          LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
 
 831        ? qq|WHERE o.trans_id = ?|
 
 832        : qq|WHERE o.trans_id IN (| . join(", ", map("?", @ids)) . qq|)|) .
 
 833       qq|ORDER BY o.$oid{$myconfig->{dbdriver}}|;
 
 835     @ids = $form->{id} ? ($form->{id}) : @ids;
 
 836     $sth = prepare_execute_query($form, $dbh, $query, @values);
 
 838     while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 839       # Retrieve custom variables.
 
 840       my $cvars = CVar->get_custom_variables(dbh        => $dbh,
 
 842                                              sub_module => 'orderitems',
 
 843                                              trans_id   => $ref->{orderitems_id},
 
 845       map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
 
 848       if (!$ref->{"part_inventory_accno_id"}) {
 
 849         map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid));
 
 851       delete($ref->{"part_inventory_accno_id"});
 
 853       # in collective order, copy global ordnumber, transdate, cusordnumber into item scope
 
 854       #   unless already present there
 
 855       # remove _oe entries afterwards
 
 856       map { $ref->{$_} = $ref->{"${_}_oe"} if ($ref->{$_} eq '') }
 
 857         qw|ordnumber transdate cusordnumber|
 
 859       map { delete $ref->{$_} } qw|ordnumber_oe transdate_oe cusordnumber_oe|;
 
 863       while ($ref->{inventory_new_chart} && ($ref->{inventory_valid} >= 0)) {
 
 865           qq|SELECT accno AS inventory_accno, | .
 
 866           qq|  new_chart_id AS inventory_new_chart, | .
 
 867           qq|  date($transdate) - valid_from AS inventory_valid | .
 
 868           qq|FROM chart WHERE id = $ref->{inventory_new_chart}|;
 
 869         ($ref->{inventory_accno}, $ref->{inventory_new_chart},
 
 870          $ref->{inventory_valid}) = selectrow_query($form, $dbh, $query);
 
 873       while ($ref->{income_new_chart} && ($ref->{income_valid} >= 0)) {
 
 875           qq|SELECT accno AS income_accno, | .
 
 876           qq|  new_chart_id AS income_new_chart, | .
 
 877           qq|  date($transdate) - valid_from AS income_valid | .
 
 878           qq|FROM chart WHERE id = $ref->{income_new_chart}|;
 
 879         ($ref->{income_accno}, $ref->{income_new_chart},
 
 880          $ref->{income_valid}) = selectrow_query($form, $dbh, $query);
 
 883       while ($ref->{expense_new_chart} && ($ref->{expense_valid} >= 0)) {
 
 885           qq|SELECT accno AS expense_accno, | .
 
 886           qq|  new_chart_id AS expense_new_chart, | .
 
 887           qq|  date($transdate) - valid_from AS expense_valid | .
 
 888           qq|FROM chart WHERE id = $ref->{expense_new_chart}|;
 
 889         ($ref->{expense_accno}, $ref->{expense_new_chart},
 
 890          $ref->{expense_valid}) = selectrow_query($form, $dbh, $query);
 
 893       # delete orderitems_id in collective orders, so that they get cloned no matter what
 
 894       delete $ref->{orderitems_id} if (@ids);
 
 896       # get tax rates and description
 
 897       my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
 
 899         qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber | .
 
 900         qq|FROM tax t LEFT JOIN chart c on (c.id = t.chart_id) | .
 
 901         qq|WHERE t.id IN (SELECT tk.tax_id FROM taxkeys tk | .
 
 902         qq|               WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?) | .
 
 903         qq|                 AND startdate <= $transdate ORDER BY startdate DESC LIMIT 1) | .
 
 904         qq|ORDER BY c.accno|;
 
 905       my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
 
 906       $ref->{taxaccounts} = "";
 
 908       while (my $ptr = $stw->fetchrow_hashref("NAME_lc")) {
 
 909         if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
 
 913         $ref->{taxaccounts} .= "$ptr->{accno} ";
 
 914         if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
 
 915           $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
 
 916           $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
 
 917           $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
 
 918           $form->{taxaccounts} .= "$ptr->{accno} ";
 
 923       chop $ref->{taxaccounts};
 
 925       push @{ $form->{form_details} }, $ref;
 
 933     $form->lastname_used($dbh, $myconfig, $form->{vc})
 
 934       unless $form->{"$form->{vc}_id"};
 
 938   $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? "buy" : "sell");
 
 940   Common::webdav_folder($form) if ($main::webdav);
 
 942   my $rc = $dbh->commit;
 
 945   $main::lxdebug->leave_sub();
 
 950 sub retrieve_simple {
 
 951   $main::lxdebug->enter_sub();
 
 956   Common::check_params(\%params, qw(id));
 
 958   my $myconfig    = \%main::myconfig;
 
 959   my $form        = $main::form;
 
 961   my $dbh         = $params{dbh} || $form->get_standard_dbh($myconfig);
 
 963   my $oe_query    = qq|SELECT * FROM oe         WHERE id = ?|;
 
 964   my $oi_query    = qq|SELECT * FROM orderitems WHERE trans_id = ?|;
 
 966   my $order            = selectfirst_hashref_query($form, $dbh, $oe_query, conv_i($params{id}));
 
 967   $order->{orderitems} = selectall_hashref_query(  $form, $dbh, $oi_query, conv_i($params{id}));
 
 969   $main::lxdebug->leave_sub();
 
 975   $main::lxdebug->enter_sub();
 
 977   my ($self, $myconfig, $form) = @_;
 
 979   # connect to database
 
 980   my $dbh = $form->dbconnect($myconfig);
 
 986   my $nodiscount_subtotal = 0;
 
 987   my $discount_subtotal = 0;
 
 993   my $subtotal_header = 0;
 
1001   my %oid = ('Pg'     => 'oid',
 
1002              'Oracle' => 'rowid');
 
1004   my (@project_ids, %projectnumbers);
 
1006   push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});
 
1008   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS',
 
1009                    'departments'   => 'ALL_DEPARTMENTS');
 
1012   foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
 
1013     $price_factors{$pfac->{id}}  = $pfac;
 
1014     $pfac->{factor}             *= 1;
 
1015     $pfac->{formatted_factor}    = $form->format_amount($myconfig, $pfac->{factor});
 
1019   foreach my $dept (@{ $form->{ALL_DEPARTMENTS} }) {
 
1020     next unless $dept->{id} eq $form->{department_id};
 
1021     $form->{department} = $dept->{description};
 
1025   # sort items by partsgroup
 
1026   for $i (1 .. $form->{rowcount}) {
 
1028     if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
 
1029       $partsgroup = $form->{"partsgroup_$i"};
 
1031     push @partsgroup, [$i, $partsgroup];
 
1032     push(@project_ids, $form->{"project_id_$i"}) if ($form->{"project_id_$i"});
 
1036     $query = "SELECT id, projectnumber FROM project WHERE id IN (" .
 
1037       join(", ", map("?", @project_ids)) . ")";
 
1038     $sth = prepare_execute_query($form, $dbh, $query, @project_ids);
 
1039     while (my $ref = $sth->fetchrow_hashref()) {
 
1040       $projectnumbers{$ref->{id}} = $ref->{projectnumber};
 
1045   $form->{"globalprojectnumber"} = $projectnumbers{$form->{"globalproject_id"}};
 
1047   $form->{discount} = [];
 
1049   $form->{TEMPLATE_ARRAYS} = { };
 
1050   IC->prepare_parts_for_printing();
 
1052   my $ic_cvar_configs = CVar->get_configs(module => 'IC');
 
1055     qw(runningnumber number description longdescription qty ship unit bin
 
1056        partnotes serialnumber reqdate sellprice listprice netprice
 
1057        discount p_discount discount_sub nodiscount_sub
 
1058        linetotal  nodiscount_linetotal tax_rate projectnumber
 
1059        price_factor price_factor_name partsgroup);
 
1061   push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };
 
1063   my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);
 
1065   map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays);
 
1068   foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
 
1071     if ($item->[1] ne $sameitem) {
 
1072       push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, qq|$item->[1]|);
 
1073       $sameitem = $item->[1];
 
1075       map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
1078     $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
 
1080     if ($form->{"id_$i"} != 0) {
 
1082       # add number, description and qty to $form->{number}, ....
 
1084       if ($form->{"subtotal_$i"} && !$subtotal_header) {
 
1085         $subtotal_header = $i;
 
1086         $position = int($position);
 
1089       } elsif ($subtotal_header) {
 
1091         $position = int($position);
 
1092         $position = $position.".".$subposition;
 
1094         $position = int($position);
 
1098       my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || { 'factor' => 1 };
 
1100       push @{ $form->{TEMPLATE_ARRAYS}->{runningnumber} },     $position;
 
1101       push @{ $form->{TEMPLATE_ARRAYS}->{number} },            $form->{"partnumber_$i"};
 
1102       push @{ $form->{TEMPLATE_ARRAYS}->{description} },       $form->{"description_$i"};
 
1103       push @{ $form->{TEMPLATE_ARRAYS}->{longdescription} },   $form->{"longdescription_$i"};
 
1104       push @{ $form->{TEMPLATE_ARRAYS}->{qty} },               $form->format_amount($myconfig, $form->{"qty_$i"});
 
1105       push @{ $form->{TEMPLATE_ARRAYS}->{ship} },              $form->format_amount($myconfig, $form->{"ship_$i"});
 
1106       push @{ $form->{TEMPLATE_ARRAYS}->{unit} },              $form->{"unit_$i"};
 
1107       push @{ $form->{TEMPLATE_ARRAYS}->{bin} },               $form->{"bin_$i"};
 
1108       push @{ $form->{TEMPLATE_ARRAYS}->{partnotes} },         $form->{"partnotes_$i"};
 
1109       push @{ $form->{TEMPLATE_ARRAYS}->{serialnumber} },      $form->{"serialnumber_$i"};
 
1110       push @{ $form->{TEMPLATE_ARRAYS}->{reqdate} },           $form->{"reqdate_$i"};
 
1111       push @{ $form->{TEMPLATE_ARRAYS}->{sellprice} },         $form->{"sellprice_$i"};
 
1112       push @{ $form->{TEMPLATE_ARRAYS}->{listprice} },         $form->{"listprice_$i"};
 
1113       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor} },      $price_factor->{formatted_factor};
 
1114       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor_name} }, $price_factor->{description};
 
1115       push @{ $form->{TEMPLATE_ARRAYS}->{partsgroup} },        $form->{"partsgroup_$i"};
 
1117       my $sellprice     = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
1118       my ($dec)         = ($sellprice =~ /\.(\d+)/);
 
1119       my $decimalplaces = max 2, length($dec);
 
1121       my $parsed_discount      = $form->parse_amount($myconfig, $form->{"discount_$i"});
 
1122       my $linetotal_exact      =                     $form->{"qty_$i"} * $sellprice * (100 - $parsed_discount) / 100 / $price_factor->{factor};
 
1123       my $linetotal            = $form->round_amount($linetotal_exact, 2);
 
1124       my $discount             = $form->round_amount($form->{"qty_$i"} * $sellprice * $parsed_discount / 100 / $price_factor->{factor} - ($linetotal - $linetotal_exact),
 
1126       my $nodiscount_linetotal = $form->round_amount($form->{"qty_$i"} * $sellprice / $price_factor->{factor}, 2);
 
1127       $form->{"netprice_$i"}   = $form->round_amount($form->{"qty_$i"} ? ($linetotal / $form->{"qty_$i"}) : 0, 2);
 
1129       push @{ $form->{TEMPLATE_ARRAYS}->{netprice} }, ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : '';
 
1131       $linetotal = ($linetotal != 0) ? $linetotal : '';
 
1133       push @{ $form->{TEMPLATE_ARRAYS}->{discount} },  ($discount  != 0) ? $form->format_amount($myconfig, $discount * -1, 2) : '';
 
1134       push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} }, $form->{"discount_$i"};
 
1136       $form->{ordtotal}         += $linetotal;
 
1137       $form->{nodiscount_total} += $nodiscount_linetotal;
 
1138       $form->{discount_total}   += $discount;
 
1140       if ($subtotal_header) {
 
1141         $discount_subtotal   += $linetotal;
 
1142         $nodiscount_subtotal += $nodiscount_linetotal;
 
1145       if ($form->{"subtotal_$i"} && $subtotal_header && ($subtotal_header != $i)) {
 
1146         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} },   $form->format_amount($myconfig, $discount_subtotal,   2);
 
1147         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, $form->format_amount($myconfig, $nodiscount_subtotal, 2);
 
1149         $discount_subtotal   = 0;
 
1150         $nodiscount_subtotal = 0;
 
1151         $subtotal_header     = 0;
 
1154         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} },   "";
 
1155         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, "";
 
1158       if (!$form->{"discount_$i"}) {
 
1159         $nodiscount += $linetotal;
 
1162       push @{ $form->{TEMPLATE_ARRAYS}->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2);
 
1163       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} }, $form->format_amount($myconfig, $nodiscount_linetotal, 2);
 
1165       push(@{ $form->{TEMPLATE_ARRAYS}->{projectnumber} }, $projectnumbers{$form->{"project_id_$i"}});
 
1167       my ($taxamount, $taxbase);
 
1170       map { $taxrate += $form->{"${_}_rate"} } split(/ /, $form->{"taxaccounts_$i"});
 
1172       if ($form->{taxincluded}) {
 
1175         $taxamount = $linetotal * $taxrate / (1 + $taxrate);
 
1176         $taxbase = $linetotal / (1 + $taxrate);
 
1178         $taxamount = $linetotal * $taxrate;
 
1179         $taxbase   = $linetotal;
 
1182       if ($taxamount != 0) {
 
1183         foreach my $accno (split / /, $form->{"taxaccounts_$i"}) {
 
1184           $taxaccounts{$accno} += $taxamount * $form->{"${accno}_rate"} / $taxrate;
 
1185           $taxbase{$accno}     += $taxbase;
 
1189       $tax_rate = $taxrate * 100;
 
1190       push(@{ $form->{TEMPLATE_ARRAYS}->{tax_rate} }, qq|$tax_rate|);
 
1192       if ($form->{"assembly_$i"}) {
 
1195         # get parts and push them onto the stack
 
1197         if ($form->{groupitems}) {
 
1198           $sortorder = qq|ORDER BY pg.partsgroup, a.$oid{$myconfig->{dbdriver}}|;
 
1200           $sortorder = qq|ORDER BY a.$oid{$myconfig->{dbdriver}}|;
 
1203         $query = qq|SELECT p.partnumber, p.description, p.unit, a.qty, | .
 
1204                  qq|pg.partsgroup | .
 
1205                  qq|FROM assembly a | .
 
1206                  qq|  JOIN parts p ON (a.parts_id = p.id) | .
 
1207                  qq|    LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
 
1208                  qq|    WHERE a.bom = '1' | .
 
1209                  qq|    AND a.id = ? | . $sortorder;
 
1210         @values = ($form->{"id_$i"});
 
1211         $sth = $dbh->prepare($query);
 
1212         $sth->execute(@values) || $form->dberror($query);
 
1214         while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
 
1215           if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
 
1216             map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
1217             $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
 
1218             push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $sameitem);
 
1221           push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}) . qq|, $ref->{partnumber}, $ref->{description}|);
 
1222           map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
1227       map { push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} }, $form->{"ic_cvar_$_->{name}_$i"} } @{ $ic_cvar_configs };
 
1232   foreach $item (sort keys %taxaccounts) {
 
1233     $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
 
1235     push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase} },        $form->format_amount($myconfig, $taxbase{$item}, 2));
 
1236     push(@{ $form->{TEMPLATE_ARRAYS}->{tax} },            $form->format_amount($myconfig, $taxamount,      2));
 
1237     push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate} },        $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
 
1238     push(@{ $form->{TEMPLATE_ARRAYS}->{taxdescription} }, $form->{"${item}_description"} . q{ } . 100 * $form->{"${item}_rate"} . q{%});
 
1239     push(@{ $form->{TEMPLATE_ARRAYS}->{taxnumber} },      $form->{"${item}_taxnumber"});
 
1242   $form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
 
1243   $form->{discount_total}      = $form->format_amount($myconfig, $form->{discount_total}, 2);
 
1244   $form->{nodiscount}          = $form->format_amount($myconfig, $nodiscount, 2);
 
1245   $form->{yesdiscount}         = $form->format_amount($myconfig, $form->{nodiscount_total} - $nodiscount, 2);
 
1247   if($form->{taxincluded}) {
 
1248     $form->{subtotal} = $form->format_amount($myconfig, $form->{ordtotal} - $tax, 2);
 
1250     $form->{subtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
 
1253   $form->{ordtotal} = ($form->{taxincluded}) ? $form->{ordtotal} : $form->{ordtotal} + $tax;
 
1256   $form->{quototal} = $form->{ordtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
 
1258   if ($form->{type} =~ /_quotation/) {
 
1259     $form->set_payment_options($myconfig, $form->{quodate});
 
1261     $form->set_payment_options($myconfig, $form->{orddate});
 
1264   $form->{username} = $myconfig->{name};
 
1268   $main::lxdebug->leave_sub();
 
1271 sub project_description {
 
1272   $main::lxdebug->enter_sub();
 
1274   my ($self, $dbh, $id) = @_;
 
1276   my $query = qq|SELECT description FROM project WHERE id = ?|;
 
1277   my ($value) = selectrow_query($main::form, $dbh, $query, $id);
 
1279   $main::lxdebug->leave_sub();
 
1284 ##########################
 
1285 # Get data for the submitted order id
 
1288 sub get_order_data_by_ordnumber {
 
1289   $main::lxdebug->enter_sub();
 
1294   Common::check_params(\%params, qw(ordnumber));
 
1296   my $form     = $main::form;
 
1297   my %myconfig = %main::myconfig;
 
1298   my $dbh      = $form->get_standard_dbh();
 
1300   my @values = ($params{ordnumber});
 
1302   # We query the database for the fields we need using the submitted "ordnumber"
 
1304     SELECT o.payment_id, o.salesman_id, o.transdate AS orddate, o.taxzone_id, o.quonumber
 
1306     WHERE o.ordnumber = ?;
 
1309   # Do the actual query and return the results for later processing by our "frontend"
 
1310   my $result = selectfirst_hashref_query($form, $dbh, $query, @values);
 
1312   $main::lxdebug->leave_sub();
 
1323 OE.pm - Order entry module
 
1327 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>.
 
1333 =item retrieve_simple PARAMS
 
1335 simple OE retrieval by id. does not look up customer, vendor, units or any other stuff. only oe and orderitems.
 
1337   my $order = retrieve_simple(id => 2);