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_absolut_$i"} = $form->parse_amount($myconfig, $form->{"marge_absolut_$i"}) * 1;
 
 342       $form->{"lastcost_$i"} = $form->parse_amount($myconfig, $form->{"lastcost_$i"});
 
 344       # set values to 0 if nothing entered
 
 345       $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
 
 347       $form->{"sellprice_$i"} = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 348       $fxsellprice = $form->{"sellprice_$i"};
 
 350       my ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
 
 352       my $decimalplaces = ($dec > 2) ? $dec : 2;
 
 354       $discount = $form->round_amount($form->{"sellprice_$i"} * $form->{"discount_$i"}, $decimalplaces);
 
 355       $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} - $discount, $decimalplaces);
 
 357       $form->{"inventory_accno_$i"} *= 1;
 
 358       $form->{"expense_accno_$i"}   *= 1;
 
 360       $price_factor = $price_factors{ $form->{"price_factor_id_$i"} } || 1;
 
 361       $linetotal    = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2);
 
 363       @taxaccounts = split(/ /, $form->{"taxaccounts_$i"});
 
 367       map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;
 
 369       if ($form->{taxincluded}) {
 
 370         $taxamount = $linetotal * $taxrate / (1 + $taxrate);
 
 371         $taxbase   = $linetotal - $taxamount;
 
 373         # we are not keeping a natural price, do not round
 
 374         $form->{"sellprice_$i"} =
 
 375           $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
 
 377         $taxamount = $linetotal * $taxrate;
 
 378         $taxbase   = $linetotal;
 
 381       if ($form->round_amount($taxrate, 7) == 0) {
 
 382         if ($form->{taxincluded}) {
 
 383           foreach my $item (@taxaccounts) {
 
 384             $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2);
 
 385             $taxaccounts{$item} += $taxamount;
 
 386             $taxdiff            += $taxamount;
 
 387             $taxbase{$item}     += $taxbase;
 
 389           $taxaccounts{ $taxaccounts[0] } += $taxdiff;
 
 391           foreach my $item (@taxaccounts) {
 
 392             $taxaccounts{$item} += $linetotal * $form->{"${item}_rate"};
 
 393             $taxbase{$item}     += $taxbase;
 
 397         foreach my $item (@taxaccounts) {
 
 398           $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate;
 
 399           $taxbase{$item} += $taxbase;
 
 403       $netamount += $form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor;
 
 405       $reqdate = ($form->{"reqdate_$i"}) ? $form->{"reqdate_$i"} : undef;
 
 407       # get pricegroup_id and save ist
 
 408       ($null, my $pricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
 
 411       # save detail record in orderitems table
 
 412       my $orderitems_id = $form->{"orderitems_id_$i"};
 
 413       ($orderitems_id)  = selectfirst_array_query($form, $dbh, qq|SELECT nextval('orderitemsid')|) if (!$orderitems_id);
 
 416       $query = qq|INSERT INTO orderitems (
 
 417                     id, trans_id, parts_id, description, longdescription, qty, base_qty,
 
 418                     sellprice, discount, unit, reqdate, project_id, serialnumber, ship,
 
 419                     pricegroup_id, ordnumber, transdate, cusordnumber, subtotal,
 
 420                     marge_percent, marge_total, lastcost, price_factor_id, price_factor, marge_price_factor)
 
 421                   VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
 
 422                           (SELECT factor FROM price_factors WHERE id = ?), ?)|;
 
 424            conv_i($orderitems_id), conv_i($form->{id}), conv_i($form->{"id_$i"}),
 
 425            $form->{"description_$i"}, $form->{"longdescription_$i"},
 
 426            $form->{"qty_$i"}, $baseqty,
 
 427            $fxsellprice, $form->{"discount_$i"},
 
 428            $form->{"unit_$i"}, conv_date($reqdate), conv_i($form->{"project_id_$i"}),
 
 429            $form->{"serialnumber_$i"}, $form->{"ship_$i"}, conv_i($pricegroup_id),
 
 430            $form->{"ordnumber_$i"}, conv_date($form->{"transdate_$i"}),
 
 431            $form->{"cusordnumber_$i"}, $form->{"subtotal_$i"} ? 't' : 'f',
 
 432            $form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
 
 433            $form->{"lastcost_$i"},
 
 434            conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
 
 435            conv_i($form->{"marge_price_factor_$i"}));
 
 436       do_query($form, $dbh, $query, @values);
 
 438       $form->{"sellprice_$i"} = $fxsellprice;
 
 439       $form->{"discount_$i"} *= 100;
 
 441       CVar->save_custom_variables(module       => 'IC',
 
 442                                   sub_module   => 'orderitems',
 
 443                                   trans_id     => $orderitems_id,
 
 444                                   configs      => $ic_cvar_configs,
 
 446                                   name_prefix  => 'ic_',
 
 447                                   name_postfix => "_$i",
 
 452   $reqdate = ($form->{reqdate}) ? $form->{reqdate} : undef;
 
 456   map { $tax += $form->round_amount($taxaccounts{$_}, 2) } keys %taxaccounts;
 
 458   $amount = $form->round_amount($netamount + $tax, 2);
 
 459   $netamount = $form->round_amount($netamount, 2);
 
 461   if ($form->{currency} eq $form->{defaultcurrency}) {
 
 462     $form->{exchangerate} = 1;
 
 464     $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? 'buy' : 'sell');
 
 467   $form->{exchangerate} = $exchangerate || $form->parse_amount($myconfig, $form->{exchangerate});
 
 469   my $quotation = $form->{type} =~ /_order$/ ? 'f' : 't';
 
 471   ($null, $form->{department_id}) = split(/--/, $form->{department}) if $form->{department};
 
 476          ordnumber = ?, quonumber = ?, cusordnumber = ?, transdate = ?, vendor_id = ?,
 
 477          customer_id = ?, amount = ?, netamount = ?, reqdate = ?, taxincluded = ?,
 
 478          shippingpoint = ?, shipvia = ?, notes = ?, intnotes = ?, curr = ?, closed = ?,
 
 479          delivered = ?, proforma = ?, quotation = ?, department_id = ?, language_id = ?,
 
 480          taxzone_id = ?, shipto_id = ?, payment_id = ?, delivery_vendor_id = ?, delivery_customer_id = ?,
 
 481          globalproject_id = ?, employee_id = ?, salesman_id = ?, cp_id = ?, transaction_description = ?, marge_total = ?, marge_percent = ?
 
 484   @values = ($form->{ordnumber} || '', $form->{quonumber},
 
 485              $form->{cusordnumber}, conv_date($form->{transdate}),
 
 486              conv_i($form->{vendor_id}), conv_i($form->{customer_id}),
 
 487              $amount, $netamount, conv_date($reqdate),
 
 488              $form->{taxincluded} ? 't' : 'f', $form->{shippingpoint},
 
 489              $form->{shipvia}, $form->{notes}, $form->{intnotes},
 
 490              substr($form->{currency}, 0, 3), $form->{closed} ? 't' : 'f',
 
 491              $form->{delivered} ? "t" : "f", $form->{proforma} ? 't' : 'f',
 
 492              $quotation, conv_i($form->{department_id}),
 
 493              conv_i($form->{language_id}), conv_i($form->{taxzone_id}),
 
 494              conv_i($form->{shipto_id}), conv_i($form->{payment_id}),
 
 495              conv_i($form->{delivery_vendor_id}),
 
 496              conv_i($form->{delivery_customer_id}),
 
 497              conv_i($form->{globalproject_id}), conv_i($form->{employee_id}),
 
 498              conv_i($form->{salesman_id}), conv_i($form->{cp_id}),
 
 499              $form->{transaction_description},
 
 500              $form->{marge_total} * 1, $form->{marge_percent} * 1,
 
 501              conv_i($form->{id}));
 
 502   do_query($form, $dbh, $query, @values);
 
 504   $form->{ordtotal} = $amount;
 
 507   $form->{name} = $form->{ $form->{vc} };
 
 508   $form->{name} =~ s/--\Q$form->{"$form->{vc}_id"}\E//;
 
 510   if (!$form->{shipto_id}) {
 
 511     $form->add_shipto($dbh, $form->{id}, "OE");
 
 514   # save printed, emailed, queued
 
 515   $form->save_status($dbh);
 
 517   # Link this record to the records it was created from.
 
 518   $form->{convert_from_oe_ids} =~ s/^\s+//;
 
 519   $form->{convert_from_oe_ids} =~ s/\s+$//;
 
 520   my @convert_from_oe_ids      =  split m/\s+/, $form->{convert_from_oe_ids};
 
 521   delete $form->{convert_from_oe_ids};
 
 523   if (scalar @convert_from_oe_ids) {
 
 524     RecordLinks->create_links('dbh'        => $dbh,
 
 526                               'from_table' => 'oe',
 
 527                               'from_ids'   => \@convert_from_oe_ids,
 
 529                               'to_id'      => $form->{id},
 
 532     $self->_close_quotations_rfqs('dbh'     => $dbh,
 
 533                                   'from_id' => \@convert_from_oe_ids,
 
 534                                   'to_id'   => $form->{id});
 
 537   if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
 
 538     if ($form->{vc} eq 'customer') {
 
 539       $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, $form->{exchangerate}, 0);
 
 541     if ($form->{vc} eq 'vendor') {
 
 542       $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, 0, $form->{exchangerate});
 
 546   $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ?
 
 547                                        "quonumber" : "ordnumber"};
 
 549   Common::webdav_folder($form) if ($main::webdav);
 
 551   my $rc = $dbh->commit;
 
 554   $main::lxdebug->leave_sub();
 
 559 sub _close_quotations_rfqs {
 
 560   $main::lxdebug->enter_sub();
 
 565   Common::check_params(\%params, qw(from_id to_id));
 
 567   my $myconfig = \%main::myconfig;
 
 568   my $form     = $main::form;
 
 570   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
 
 572   my $query    = qq|SELECT quotation FROM oe WHERE id = ?|;
 
 573   my $sth      = prepare_query($form, $dbh, $query);
 
 575   do_statement($form, $sth, $query, conv_i($params{to_id}));
 
 577   my ($quotation) = $sth->fetchrow_array();
 
 580     $main::lxdebug->leave_sub();
 
 586   foreach my $from_id (@{ $params{from_id} }) {
 
 587     $from_id = conv_i($from_id);
 
 588     do_statement($form, $sth, $query, $from_id);
 
 589     ($quotation) = $sth->fetchrow_array();
 
 590     push @close_ids, $from_id if ($quotation);
 
 595   if (scalar @close_ids) {
 
 596     $query = qq|UPDATE oe SET closed = TRUE WHERE id IN (| . join(', ', ('?') x scalar @close_ids) . qq|)|;
 
 597     do_query($form, $dbh, $query, @close_ids);
 
 599     $dbh->commit() unless ($params{dbh});
 
 602   $main::lxdebug->leave_sub();
 
 606   $main::lxdebug->enter_sub();
 
 608   my ($self, $myconfig, $form, $spool) = @_;
 
 610   # connect to database
 
 611   my $dbh = $form->dbconnect_noauto($myconfig);
 
 614   my $query = qq|SELECT s.spoolfile FROM status s | .
 
 615               qq|WHERE s.trans_id = ?|;
 
 616   my @values = (conv_i($form->{id}));
 
 617   my $sth = $dbh->prepare($query);
 
 618   $sth->execute(@values) || $self->dberror($query);
 
 623   while (($spoolfile) = $sth->fetchrow_array) {
 
 624     push @spoolfiles, $spoolfile;
 
 629   @values = (conv_i($form->{id}));
 
 631   # delete status entries
 
 632   $query = qq|DELETE FROM status | .
 
 633            qq|WHERE trans_id = ?|;
 
 634   do_query($form, $dbh, $query, @values);
 
 637   $query = qq|DELETE FROM oe | .
 
 639   do_query($form, $dbh, $query, @values);
 
 641   # delete individual entries
 
 642   $query = qq|DELETE FROM orderitems | .
 
 643            qq|WHERE trans_id = ?|;
 
 644   do_query($form, $dbh, $query, @values);
 
 646   $query = qq|DELETE FROM shipto | .
 
 647            qq|WHERE trans_id = ? AND module = 'OE'|;
 
 648   do_query($form, $dbh, $query, @values);
 
 650   my $rc = $dbh->commit;
 
 654     foreach $spoolfile (@spoolfiles) {
 
 655       unlink "$spool/$spoolfile" if $spoolfile;
 
 659   $main::lxdebug->leave_sub();
 
 665   $main::lxdebug->enter_sub();
 
 667   my ($self, $myconfig, $form) = @_;
 
 669   # connect to database
 
 670   my $dbh = $form->dbconnect_noauto($myconfig);
 
 672   my ($query, $query_add, @values, @ids, $sth);
 
 674   my $ic_cvar_configs = CVar->get_configs(module => 'IC',
 
 677   # translate the ids (given by id_# and trans_id_#) into one array of ids, so we can join them later
 
 679     push @ids, $form->{"trans_id_$_"}
 
 680       if ($form->{"multi_id_$_"} and $form->{"trans_id_$_"})
 
 681   } (1 .. $form->{"rowcount"});
 
 683   if ($form->{rowcount} && scalar @ids) {
 
 684     $form->{convert_from_oe_ids} = join ' ', @ids;
 
 687   # if called in multi id mode, and still only got one id, switch back to single id
 
 688   if ($form->{"rowcount"} and $#ids == 0) {
 
 689     $form->{"id"} = $ids[0];
 
 693   # and remember for the rest of the function
 
 694   my $is_collective_order = scalar @ids;
 
 697     my $wday         = (localtime(time))[6];
 
 698     my $next_workday = $wday == 5 ? 3 : $wday == 6 ? 2 : 1;
 
 699     $query_add       = qq|, current_date AS transdate, date(current_date + interval '${next_workday} days') AS reqdate|;
 
 702   # get default accounts
 
 703   $query = qq|SELECT (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
 
 704                      (SELECT c.accno FROM chart c WHERE d.income_accno_id    = c.id) AS income_accno,
 
 705                      (SELECT c.accno FROM chart c WHERE d.expense_accno_id   = c.id) AS expense_accno,
 
 706                      (SELECT c.accno FROM chart c WHERE d.fxgain_accno_id    = c.id) AS fxgain_accno,
 
 707                      (SELECT c.accno FROM chart c WHERE d.fxloss_accno_id    = c.id) AS fxloss_accno,
 
 711   my $ref = selectfirst_hashref_query($form, $dbh, $query);
 
 712   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 714   ($form->{currency}) = split(/:/, $form->{currencies}) unless ($form->{currency});
 
 716   # set reqdate if this is an invoice->order conversion. If someone knows a better check to ensure
 
 717   # we come from invoices, feel free.
 
 718   $form->{reqdate} = $form->{deliverydate}
 
 719     if (    $form->{deliverydate}
 
 720         and $form->{callback} =~ /action=ar_transactions/);
 
 722   my $vc = $form->{vc} eq "customer" ? "customer" : "vendor";
 
 724   if ($form->{id} or @ids) {
 
 726     # retrieve order for single id
 
 727     # NOTE: this query is intended to fetch all information only ONCE.
 
 728     # so if any of these infos is important (or even different) for any item,
 
 729     # it will be killed out and then has to be fetched from the item scope query further down
 
 731       qq|SELECT o.cp_id, o.ordnumber, o.transdate, o.reqdate,
 
 732            o.taxincluded, o.shippingpoint, o.shipvia, o.notes, o.intnotes,
 
 733            o.curr AS currency, e.name AS employee, o.employee_id, o.salesman_id,
 
 734            o.${vc}_id, cv.name AS ${vc}, o.amount AS invtotal,
 
 735            o.closed, o.reqdate, o.quonumber, o.department_id, o.cusordnumber,
 
 736            d.description AS department, o.payment_id, o.language_id, o.taxzone_id,
 
 737            o.delivery_customer_id, o.delivery_vendor_id, o.proforma, o.shipto_id,
 
 738            o.globalproject_id, o.delivered, o.transaction_description
 
 740          JOIN ${vc} cv ON (o.${vc}_id = cv.id)
 
 741          LEFT JOIN employee e ON (o.employee_id = e.id)
 
 742          LEFT JOIN department d ON (o.department_id = d.id) | .
 
 745          : "WHERE o.id IN (" . join(', ', map("? ", @ids)) . ")"
 
 747     @values = $form->{id} ? ($form->{id}) : @ids;
 
 748     $sth = prepare_execute_query($form, $dbh, $query, @values);
 
 750     $ref = $sth->fetchrow_hashref("NAME_lc");
 
 751     map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 753     $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ?
 
 754                                          "quonumber" : "ordnumber"};
 
 756     # set all entries for multiple ids blank that yield different information
 
 757     while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 758       map { $form->{$_} = '' if ($ref->{$_} ne $form->{$_}) } keys %$ref;
 
 761     # if not given, fill transdate with current_date
 
 762     $form->{transdate} = $form->current_date($myconfig)
 
 763       unless $form->{transdate};
 
 767     if ($form->{delivery_customer_id}) {
 
 768       $query = qq|SELECT name FROM customer WHERE id = ?|;
 
 769       ($form->{delivery_customer_string}) = selectrow_query($form, $dbh, $query, $form->{delivery_customer_id});
 
 772     if ($form->{delivery_vendor_id}) {
 
 773       $query = qq|SELECT name FROM customer WHERE id = ?|;
 
 774       ($form->{delivery_vendor_string}) = selectrow_query($form, $dbh, $query, $form->{delivery_vendor_id});
 
 777     # shipto and pinted/mailed/queued status makes only sense for single id retrieve
 
 779       $query = qq|SELECT s.* FROM shipto s WHERE s.trans_id = ? AND s.module = 'OE'|;
 
 780       $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
 
 782       $ref = $sth->fetchrow_hashref("NAME_lc");
 
 784       map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 787       # get printed, emailed and queued
 
 788       $query = qq|SELECT s.printed, s.emailed, s.spoolfile, s.formname FROM status s WHERE s.trans_id = ?|;
 
 789       $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
 
 791       while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 792         $form->{printed} .= "$ref->{formname} " if $ref->{printed};
 
 793         $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
 
 794         $form->{queued}  .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
 
 797       map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
 
 800     my %oid = ('Pg'     => 'oid',
 
 801                'Oracle' => 'rowid');
 
 803     my $transdate = $form->{transdate} ? $dbh->quote($form->{transdate}) : "current_date";
 
 805     $form->{taxzone_id} = 0 unless ($form->{taxzone_id});
 
 807     # retrieve individual items
 
 808     # this query looks up all information about the items
 
 809     # stuff different from the whole will not be overwritten, but saved with a suffix.
 
 811       qq|SELECT o.id AS orderitems_id,
 
 812            c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from as inventory_valid,
 
 813            c2.accno AS income_accno,    c2.new_chart_id AS income_new_chart,    date($transdate) - c2.valid_from as income_valid,
 
 814            c3.accno AS expense_accno,   c3.new_chart_id AS expense_new_chart,   date($transdate) - c3.valid_from as expense_valid,
 
 815            oe.ordnumber AS ordnumber_oe, oe.transdate AS transdate_oe, oe.cusordnumber AS cusordnumber_oe,
 
 816            p.partnumber, p.assembly, o.description, o.qty,
 
 817            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,
 
 818            o.reqdate, o.project_id, o.serialnumber, o.ship, o.lastcost,
 
 819            o.ordnumber, o.transdate, o.cusordnumber, o.subtotal, o.longdescription,
 
 820            o.price_factor_id, o.price_factor, o.marge_price_factor,
 
 821            pr.projectnumber, p.formel,
 
 822            pg.partsgroup, o.pricegroup_id, (SELECT pricegroup FROM pricegroup WHERE id=o.pricegroup_id) as pricegroup
 
 824          JOIN parts p ON (o.parts_id = p.id)
 
 825          JOIN oe ON (o.trans_id = oe.id)
 
 826          LEFT JOIN chart c1 ON ((SELECT inventory_accno_id                   FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c1.id)
 
 827          LEFT JOIN chart c2 ON ((SELECT income_accno_id_$form->{taxzone_id}  FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c2.id)
 
 828          LEFT JOIN chart c3 ON ((SELECT expense_accno_id_$form->{taxzone_id} FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c3.id)
 
 829          LEFT JOIN project pr ON (o.project_id = pr.id)
 
 830          LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
 
 832        ? qq|WHERE o.trans_id = ?|
 
 833        : qq|WHERE o.trans_id IN (| . join(", ", map("?", @ids)) . qq|)|) .
 
 834       qq|ORDER BY o.$oid{$myconfig->{dbdriver}}|;
 
 836     @ids = $form->{id} ? ($form->{id}) : @ids;
 
 837     $sth = prepare_execute_query($form, $dbh, $query, @values);
 
 839     while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 840       # Retrieve custom variables.
 
 841       my $cvars = CVar->get_custom_variables(dbh        => $dbh,
 
 843                                              sub_module => 'orderitems',
 
 844                                              trans_id   => $ref->{orderitems_id},
 
 846       map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
 
 849       if (!$ref->{"part_inventory_accno_id"}) {
 
 850         map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid));
 
 852       delete($ref->{"part_inventory_accno_id"});
 
 854       # in collective order, copy global ordnumber, transdate, cusordnumber into item scope
 
 855       #   unless already present there
 
 856       # remove _oe entries afterwards
 
 857       map { $ref->{$_} = $ref->{"${_}_oe"} if ($ref->{$_} eq '') }
 
 858         qw|ordnumber transdate cusordnumber|
 
 860       map { delete $ref->{$_} } qw|ordnumber_oe transdate_oe cusordnumber_oe|;
 
 864       while ($ref->{inventory_new_chart} && ($ref->{inventory_valid} >= 0)) {
 
 866           qq|SELECT accno AS inventory_accno, | .
 
 867           qq|  new_chart_id AS inventory_new_chart, | .
 
 868           qq|  date($transdate) - valid_from AS inventory_valid | .
 
 869           qq|FROM chart WHERE id = $ref->{inventory_new_chart}|;
 
 870         ($ref->{inventory_accno}, $ref->{inventory_new_chart},
 
 871          $ref->{inventory_valid}) = selectrow_query($form, $dbh, $query);
 
 874       while ($ref->{income_new_chart} && ($ref->{income_valid} >= 0)) {
 
 876           qq|SELECT accno AS income_accno, | .
 
 877           qq|  new_chart_id AS income_new_chart, | .
 
 878           qq|  date($transdate) - valid_from AS income_valid | .
 
 879           qq|FROM chart WHERE id = $ref->{income_new_chart}|;
 
 880         ($ref->{income_accno}, $ref->{income_new_chart},
 
 881          $ref->{income_valid}) = selectrow_query($form, $dbh, $query);
 
 884       while ($ref->{expense_new_chart} && ($ref->{expense_valid} >= 0)) {
 
 886           qq|SELECT accno AS expense_accno, | .
 
 887           qq|  new_chart_id AS expense_new_chart, | .
 
 888           qq|  date($transdate) - valid_from AS expense_valid | .
 
 889           qq|FROM chart WHERE id = $ref->{expense_new_chart}|;
 
 890         ($ref->{expense_accno}, $ref->{expense_new_chart},
 
 891          $ref->{expense_valid}) = selectrow_query($form, $dbh, $query);
 
 894       # delete orderitems_id in collective orders, so that they get cloned no matter what
 
 895       delete $ref->{orderitems_id} if (@ids);
 
 897       # get tax rates and description
 
 898       my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
 
 900         qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber | .
 
 901         qq|FROM tax t LEFT JOIN chart c on (c.id = t.chart_id) | .
 
 902         qq|WHERE t.id IN (SELECT tk.tax_id FROM taxkeys tk | .
 
 903         qq|               WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?) | .
 
 904         qq|                 AND startdate <= $transdate ORDER BY startdate DESC LIMIT 1) | .
 
 905         qq|ORDER BY c.accno|;
 
 906       my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
 
 907       $ref->{taxaccounts} = "";
 
 909       while (my $ptr = $stw->fetchrow_hashref("NAME_lc")) {
 
 910         if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
 
 914         $ref->{taxaccounts} .= "$ptr->{accno} ";
 
 915         if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
 
 916           $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
 
 917           $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
 
 918           $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
 
 919           $form->{taxaccounts} .= "$ptr->{accno} ";
 
 924       chop $ref->{taxaccounts};
 
 926       push @{ $form->{form_details} }, $ref;
 
 934     $form->lastname_used($dbh, $myconfig, $form->{vc})
 
 935       unless $form->{"$form->{vc}_id"};
 
 939   $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? "buy" : "sell");
 
 941   Common::webdav_folder($form) if ($main::webdav);
 
 943   my $rc = $dbh->commit;
 
 946   $main::lxdebug->leave_sub();
 
 951 sub retrieve_simple {
 
 952   $main::lxdebug->enter_sub();
 
 957   Common::check_params(\%params, qw(id));
 
 959   my $myconfig    = \%main::myconfig;
 
 960   my $form        = $main::form;
 
 962   my $dbh         = $params{dbh} || $form->get_standard_dbh($myconfig);
 
 964   my $oe_query    = qq|SELECT * FROM oe         WHERE id = ?|;
 
 965   my $oi_query    = qq|SELECT * FROM orderitems WHERE trans_id = ?|;
 
 967   my $order            = selectfirst_hashref_query($form, $dbh, $oe_query, conv_i($params{id}));
 
 968   $order->{orderitems} = selectall_hashref_query(  $form, $dbh, $oi_query, conv_i($params{id}));
 
 970   $main::lxdebug->leave_sub();
 
 976   $main::lxdebug->enter_sub();
 
 978   my ($self, $myconfig, $form) = @_;
 
 980   # connect to database
 
 981   my $dbh = $form->dbconnect($myconfig);
 
 987   my $nodiscount_subtotal = 0;
 
 988   my $discount_subtotal = 0;
 
 994   my $subtotal_header = 0;
 
1002   my %oid = ('Pg'     => 'oid',
 
1003              'Oracle' => 'rowid');
 
1005   my (@project_ids, %projectnumbers, %projectdescriptions);
 
1007   push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});
 
1009   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS',
 
1010                    'departments'   => 'ALL_DEPARTMENTS');
 
1013   foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
 
1014     $price_factors{$pfac->{id}}  = $pfac;
 
1015     $pfac->{factor}             *= 1;
 
1016     $pfac->{formatted_factor}    = $form->format_amount($myconfig, $pfac->{factor});
 
1020   foreach my $dept (@{ $form->{ALL_DEPARTMENTS} }) {
 
1021     next unless $dept->{id} eq $form->{department_id};
 
1022     $form->{department} = $dept->{description};
 
1026   # sort items by partsgroup
 
1027   for $i (1 .. $form->{rowcount}) {
 
1029     if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
 
1030       $partsgroup = $form->{"partsgroup_$i"};
 
1032     push @partsgroup, [$i, $partsgroup];
 
1033     push(@project_ids, $form->{"project_id_$i"}) if ($form->{"project_id_$i"});
 
1037     $query = "SELECT id, projectnumber, description FROM project WHERE id IN (" .
 
1038       join(", ", map("?", @project_ids)) . ")";
 
1039     $sth = prepare_execute_query($form, $dbh, $query, @project_ids);
 
1040     while (my $ref = $sth->fetchrow_hashref()) {
 
1041       $projectnumbers{$ref->{id}} = $ref->{projectnumber};
 
1042       $projectdescriptions{$ref->{id}} = $ref->{description};
 
1047   $form->{"globalprojectnumber"} = $projectnumbers{$form->{"globalproject_id"}};
 
1048   $form->{"globalprojectdescription"} = $projectdescriptions{$form->{"globalproject_id"}};
 
1050   $form->{discount} = [];
 
1052   $form->{TEMPLATE_ARRAYS} = { };
 
1053   IC->prepare_parts_for_printing();
 
1055   my $ic_cvar_configs = CVar->get_configs(module => 'IC');
 
1058     qw(runningnumber number description longdescription qty ship unit bin
 
1059        partnotes serialnumber reqdate sellprice listprice netprice
 
1060        discount p_discount discount_sub nodiscount_sub
 
1061        linetotal  nodiscount_linetotal tax_rate projectnumber projectdescription
 
1062        price_factor price_factor_name partsgroup);
 
1064   push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };
 
1066   my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);
 
1068   map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays);
 
1071   foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
 
1074     if ($item->[1] ne $sameitem) {
 
1075       push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, qq|$item->[1]|);
 
1076       $sameitem = $item->[1];
 
1078       map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
1081     $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
 
1083     if ($form->{"id_$i"} != 0) {
 
1085       # add number, description and qty to $form->{number}, ....
 
1087       if ($form->{"subtotal_$i"} && !$subtotal_header) {
 
1088         $subtotal_header = $i;
 
1089         $position = int($position);
 
1092       } elsif ($subtotal_header) {
 
1094         $position = int($position);
 
1095         $position = $position.".".$subposition;
 
1097         $position = int($position);
 
1101       my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || { 'factor' => 1 };
 
1103       push @{ $form->{TEMPLATE_ARRAYS}->{runningnumber} },     $position;
 
1104       push @{ $form->{TEMPLATE_ARRAYS}->{number} },            $form->{"partnumber_$i"};
 
1105       push @{ $form->{TEMPLATE_ARRAYS}->{description} },       $form->{"description_$i"};
 
1106       push @{ $form->{TEMPLATE_ARRAYS}->{longdescription} },   $form->{"longdescription_$i"};
 
1107       push @{ $form->{TEMPLATE_ARRAYS}->{qty} },               $form->format_amount($myconfig, $form->{"qty_$i"});
 
1108       push @{ $form->{TEMPLATE_ARRAYS}->{ship} },              $form->format_amount($myconfig, $form->{"ship_$i"});
 
1109       push @{ $form->{TEMPLATE_ARRAYS}->{unit} },              $form->{"unit_$i"};
 
1110       push @{ $form->{TEMPLATE_ARRAYS}->{bin} },               $form->{"bin_$i"};
 
1111       push @{ $form->{TEMPLATE_ARRAYS}->{partnotes} },         $form->{"partnotes_$i"};
 
1112       push @{ $form->{TEMPLATE_ARRAYS}->{serialnumber} },      $form->{"serialnumber_$i"};
 
1113       push @{ $form->{TEMPLATE_ARRAYS}->{reqdate} },           $form->{"reqdate_$i"};
 
1114       push @{ $form->{TEMPLATE_ARRAYS}->{sellprice} },         $form->{"sellprice_$i"};
 
1115       push @{ $form->{TEMPLATE_ARRAYS}->{listprice} },         $form->{"listprice_$i"};
 
1116       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor} },      $price_factor->{formatted_factor};
 
1117       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor_name} }, $price_factor->{description};
 
1118       push @{ $form->{TEMPLATE_ARRAYS}->{partsgroup} },        $form->{"partsgroup_$i"};
 
1120       my $sellprice     = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
1121       my ($dec)         = ($sellprice =~ /\.(\d+)/);
 
1122       my $decimalplaces = max 2, length($dec);
 
1124       my $parsed_discount      = $form->parse_amount($myconfig, $form->{"discount_$i"});
 
1125       my $linetotal_exact      =                     $form->{"qty_$i"} * $sellprice * (100 - $parsed_discount) / 100 / $price_factor->{factor};
 
1126       my $linetotal            = $form->round_amount($linetotal_exact, 2);
 
1127       my $discount             = $form->round_amount($form->{"qty_$i"} * $sellprice * $parsed_discount / 100 / $price_factor->{factor} - ($linetotal - $linetotal_exact),
 
1129       my $nodiscount_linetotal = $form->round_amount($form->{"qty_$i"} * $sellprice / $price_factor->{factor}, 2);
 
1130       $form->{"netprice_$i"}   = $form->round_amount($form->{"qty_$i"} ? ($linetotal / $form->{"qty_$i"}) : 0, 2);
 
1132       push @{ $form->{TEMPLATE_ARRAYS}->{netprice} }, ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : '';
 
1134       $linetotal = ($linetotal != 0) ? $linetotal : '';
 
1136       push @{ $form->{TEMPLATE_ARRAYS}->{discount} },  ($discount  != 0) ? $form->format_amount($myconfig, $discount * -1, 2) : '';
 
1137       push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} }, $form->{"discount_$i"};
 
1139       $form->{ordtotal}         += $linetotal;
 
1140       $form->{nodiscount_total} += $nodiscount_linetotal;
 
1141       $form->{discount_total}   += $discount;
 
1143       if ($subtotal_header) {
 
1144         $discount_subtotal   += $linetotal;
 
1145         $nodiscount_subtotal += $nodiscount_linetotal;
 
1148       if ($form->{"subtotal_$i"} && $subtotal_header && ($subtotal_header != $i)) {
 
1149         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} },   $form->format_amount($myconfig, $discount_subtotal,   2);
 
1150         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, $form->format_amount($myconfig, $nodiscount_subtotal, 2);
 
1152         $discount_subtotal   = 0;
 
1153         $nodiscount_subtotal = 0;
 
1154         $subtotal_header     = 0;
 
1157         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} },   "";
 
1158         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, "";
 
1161       if (!$form->{"discount_$i"}) {
 
1162         $nodiscount += $linetotal;
 
1165       push @{ $form->{TEMPLATE_ARRAYS}->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2);
 
1166       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} }, $form->format_amount($myconfig, $nodiscount_linetotal, 2);
 
1168       push(@{ $form->{TEMPLATE_ARRAYS}->{projectnumber} }, $projectnumbers{$form->{"project_id_$i"}});
 
1169       push(@{ $form->{TEMPLATE_ARRAYS}->{projectdescription} }, $projectdescriptions{$form->{"project_id_$i"}});
 
1171       my ($taxamount, $taxbase);
 
1174       map { $taxrate += $form->{"${_}_rate"} } split(/ /, $form->{"taxaccounts_$i"});
 
1176       if ($form->{taxincluded}) {
 
1179         $taxamount = $linetotal * $taxrate / (1 + $taxrate);
 
1180         $taxbase = $linetotal / (1 + $taxrate);
 
1182         $taxamount = $linetotal * $taxrate;
 
1183         $taxbase   = $linetotal;
 
1186       if ($taxamount != 0) {
 
1187         foreach my $accno (split / /, $form->{"taxaccounts_$i"}) {
 
1188           $taxaccounts{$accno} += $taxamount * $form->{"${accno}_rate"} / $taxrate;
 
1189           $taxbase{$accno}     += $taxbase;
 
1193       $tax_rate = $taxrate * 100;
 
1194       push(@{ $form->{TEMPLATE_ARRAYS}->{tax_rate} }, qq|$tax_rate|);
 
1196       if ($form->{"assembly_$i"}) {
 
1199         # get parts and push them onto the stack
 
1201         if ($form->{groupitems}) {
 
1202           $sortorder = qq|ORDER BY pg.partsgroup, a.$oid{$myconfig->{dbdriver}}|;
 
1204           $sortorder = qq|ORDER BY a.$oid{$myconfig->{dbdriver}}|;
 
1207         $query = qq|SELECT p.partnumber, p.description, p.unit, a.qty, | .
 
1208                  qq|pg.partsgroup | .
 
1209                  qq|FROM assembly a | .
 
1210                  qq|  JOIN parts p ON (a.parts_id = p.id) | .
 
1211                  qq|    LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
 
1212                  qq|    WHERE a.bom = '1' | .
 
1213                  qq|    AND a.id = ? | . $sortorder;
 
1214         @values = ($form->{"id_$i"});
 
1215         $sth = $dbh->prepare($query);
 
1216         $sth->execute(@values) || $form->dberror($query);
 
1218         while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
 
1219           if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
 
1220             map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
1221             $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
 
1222             push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $sameitem);
 
1225           push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}) . qq|, $ref->{partnumber}, $ref->{description}|);
 
1226           map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
1231       map { push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} }, $form->{"ic_cvar_$_->{name}_$i"} } @{ $ic_cvar_configs };
 
1236   foreach $item (sort keys %taxaccounts) {
 
1237     $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
 
1239     push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase} },        $form->format_amount($myconfig, $taxbase{$item}, 2));
 
1240     push(@{ $form->{TEMPLATE_ARRAYS}->{tax} },            $form->format_amount($myconfig, $taxamount,      2));
 
1241     push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate} },        $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
 
1242     push(@{ $form->{TEMPLATE_ARRAYS}->{taxdescription} }, $form->{"${item}_description"} . q{ } . 100 * $form->{"${item}_rate"} . q{%});
 
1243     push(@{ $form->{TEMPLATE_ARRAYS}->{taxnumber} },      $form->{"${item}_taxnumber"});
 
1246   $form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
 
1247   $form->{discount_total}      = $form->format_amount($myconfig, $form->{discount_total}, 2);
 
1248   $form->{nodiscount}          = $form->format_amount($myconfig, $nodiscount, 2);
 
1249   $form->{yesdiscount}         = $form->format_amount($myconfig, $form->{nodiscount_total} - $nodiscount, 2);
 
1251   if($form->{taxincluded}) {
 
1252     $form->{subtotal} = $form->format_amount($myconfig, $form->{ordtotal} - $tax, 2);
 
1254     $form->{subtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
 
1257   $form->{ordtotal} = ($form->{taxincluded}) ? $form->{ordtotal} : $form->{ordtotal} + $tax;
 
1260   $form->{quototal} = $form->{ordtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
 
1262   if ($form->{type} =~ /_quotation/) {
 
1263     $form->set_payment_options($myconfig, $form->{quodate});
 
1265     $form->set_payment_options($myconfig, $form->{orddate});
 
1268   $form->{username} = $myconfig->{name};
 
1272   $main::lxdebug->leave_sub();
 
1275 sub project_description {
 
1276   $main::lxdebug->enter_sub();
 
1278   my ($self, $dbh, $id) = @_;
 
1280   my $query = qq|SELECT description FROM project WHERE id = ?|;
 
1281   my ($value) = selectrow_query($main::form, $dbh, $query, $id);
 
1283   $main::lxdebug->leave_sub();
 
1288 ##########################
 
1289 # Get data for the submitted order id
 
1292 sub get_order_data_by_ordnumber {
 
1293   $main::lxdebug->enter_sub();
 
1298   Common::check_params(\%params, qw(ordnumber));
 
1300   my $form     = $main::form;
 
1301   my %myconfig = %main::myconfig;
 
1302   my $dbh      = $form->get_standard_dbh();
 
1304   my @values = ($params{ordnumber});
 
1306   # We query the database for the fields we need using the submitted "ordnumber"
 
1308     SELECT o.payment_id, o.salesman_id, o.transdate AS orddate, o.taxzone_id, o.quonumber
 
1310     WHERE o.ordnumber = ?;
 
1313   # Do the actual query and return the results for later processing by our "frontend"
 
1314   my $result = selectfirst_hashref_query($form, $dbh, $query, @values);
 
1316   $main::lxdebug->leave_sub();
 
1327 OE.pm - Order entry module
 
1331 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>.
 
1337 =item retrieve_simple PARAMS
 
1339 simple OE retrieval by id. does not look up customer, vendor, units or any other stuff. only oe and orderitems.
 
1341   my $order = retrieve_simple(id => 2);