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);
 
  44 use SL::DB::PeriodicInvoicesConfig;
 
  53   $main::lxdebug->enter_sub();
 
  55   my ($self, $myconfig, $form) = @_;
 
  58   my $dbh = $form->get_standard_dbh;
 
  61   my $ordnumber = 'ordnumber';
 
  67   my ($periodic_invoices_columns, $periodic_invoices_joins);
 
  69   my $rate = ($form->{vc} eq 'customer') ? 'buy' : 'sell';
 
  71   if ($form->{type} =~ /_quotation$/) {
 
  73     $ordnumber = 'quonumber';
 
  75   } elsif ($form->{type} eq 'sales_order') {
 
  76     $periodic_invoices_columns = qq| , COALESCE(pcfg.active, 'f') AS periodic_invoices |;
 
  77     $periodic_invoices_joins   = qq| LEFT JOIN periodic_invoices_configs pcfg ON (o.id = pcfg.oe_id) |;
 
  80   my $vc = $form->{vc} eq "customer" ? "customer" : "vendor";
 
  83     qq|SELECT o.id, o.ordnumber, o.transdate, o.reqdate, | .
 
  84     qq|  o.amount, ct.${vc}number, ct.name, o.netamount, o.${vc}_id, o.globalproject_id, | .
 
  85     qq|  o.closed, o.delivered, o.quonumber, o.shippingpoint, o.shipvia, | .
 
  86     qq|  o.transaction_description, | .
 
  87     qq|  o.marge_total, o.marge_percent, | .
 
  88     qq|  ex.$rate AS exchangerate, | .
 
  89     qq|  pr.projectnumber AS globalprojectnumber, | .
 
  90     qq|  e.name AS employee, s.name AS salesman, | .
 
  91     qq|  ct.${vc}number AS vcnumber, ct.country, ct.ustid, ct.business_id,  | .
 
  92     qq|  tz.description AS taxzone | .
 
  93     $periodic_invoices_columns .
 
  95     qq|JOIN $vc ct ON (o.${vc}_id = ct.id) | .
 
  96     qq|LEFT JOIN employee e ON (o.employee_id = e.id) | .
 
  97     qq|LEFT JOIN employee s ON (o.salesman_id = s.id) | .
 
  98     qq|LEFT JOIN exchangerate ex ON (ex.currency_id = o.currency_id | .
 
  99     qq|  AND ex.transdate = o.transdate) | .
 
 100     qq|LEFT JOIN project pr ON (o.globalproject_id = pr.id) | .
 
 101     qq|LEFT JOIN tax_zones tz ON (o.taxzone_id = tz.id) | .
 
 102     qq|$periodic_invoices_joins | .
 
 103     qq|WHERE (o.quotation = ?) |;
 
 104   push(@values, $quotation);
 
 106   my ($null, $split_department_id) = split /--/, $form->{department};
 
 107   my $department_id = $form->{department_id} || $split_department_id;
 
 108   if ($department_id) {
 
 109     $query .= qq| AND o.department_id = ?|;
 
 110     push(@values, $department_id);
 
 113   if ($form->{"project_id"}) {
 
 115       qq|AND ((globalproject_id = ?) OR EXISTS | .
 
 116       qq|  (SELECT * FROM orderitems oi | .
 
 117       qq|   WHERE oi.project_id = ? AND oi.trans_id = o.id))|;
 
 118     push(@values, conv_i($form->{"project_id"}), conv_i($form->{"project_id"}));
 
 121   if ($form->{"projectnumber"}) {
 
 123       AND ((pr.projectnumber ILIKE ?) OR EXISTS (
 
 124         SELECT * FROM orderitems oi
 
 125         LEFT JOIN project proi ON proi.id = oi.project_id
 
 126         WHERE proi.projectnumber ILIKE ? AND oi.trans_id = o.id
 
 129     push @values, "%" . $form->{"projectnumber"} . "%", "%" . $form->{"projectnumber"} . "%" ;
 
 132   if ($form->{"business_id"}) {
 
 133     $query .= " AND ct.business_id = ?";
 
 134     push(@values, $form->{"business_id"});
 
 137   if ($form->{"${vc}_id"}) {
 
 138     $query .= " AND o.${vc}_id = ?";
 
 139     push(@values, $form->{"${vc}_id"});
 
 141   } elsif ($form->{$vc}) {
 
 142     $query .= " AND ct.name ILIKE ?";
 
 143     push(@values, '%' . $form->{$vc} . '%');
 
 146   if (!$main::auth->assert('sales_all_edit', 1)) {
 
 147     $query .= " AND o.employee_id = (select id from employee where login= ?)";
 
 148     push @values, $form->{login};
 
 150   if ($form->{employee_id}) {
 
 151     $query .= " AND o.employee_id = ?";
 
 152     push @values, conv_i($form->{employee_id});
 
 155   if ($form->{salesman_id}) {
 
 156     $query .= " AND o.salesman_id = ?";
 
 157     push @values, conv_i($form->{salesman_id});
 
 160   if (!$form->{open} && !$form->{closed}) {
 
 161     $query .= " AND o.id = 0";
 
 162   } elsif (!($form->{open} && $form->{closed})) {
 
 163     $query .= ($form->{open}) ? " AND o.closed = '0'" : " AND o.closed = '1'";
 
 166   if (($form->{"notdelivered"} || $form->{"delivered"}) &&
 
 167       ($form->{"notdelivered"} ne $form->{"delivered"})) {
 
 168     $query .= $form->{"delivered"} ?
 
 169       " AND o.delivered " : " AND NOT o.delivered";
 
 172   if ($form->{$ordnumber}) {
 
 173     $query .= qq| AND o.$ordnumber ILIKE ?|;
 
 174     push(@values, '%' . $form->{$ordnumber} . '%');
 
 177   if($form->{transdatefrom}) {
 
 178     $query .= qq| AND o.transdate >= ?|;
 
 179     push(@values, conv_date($form->{transdatefrom}));
 
 182   if($form->{transdateto}) {
 
 183     $query .= qq| AND o.transdate <= ?|;
 
 184     push(@values, conv_date($form->{transdateto}));
 
 187   if($form->{reqdatefrom}) {
 
 188     $query .= qq| AND o.reqdate >= ?|;
 
 189     push(@values, conv_date($form->{reqdatefrom}));
 
 192   if($form->{reqdateto}) {
 
 193     $query .= qq| AND o.reqdate <= ?|;
 
 194     push(@values, conv_date($form->{reqdateto}));
 
 197   if ($form->{shippingpoint}) {
 
 198     $query .= qq| AND o.shippingpoint ILIKE ?|;
 
 199     push(@values, '%' . $form->{shippingpoint} . '%');
 
 202   if ($form->{taxzone_id} ne '') { # taxzone_id could be 0
 
 203     $query .= qq| AND tz.id = ?|;
 
 204     push(@values, $form->{taxzone_id});
 
 207   if ($form->{transaction_description}) {
 
 208     $query .= qq| AND o.transaction_description ILIKE ?|;
 
 209     push(@values, '%' . $form->{transaction_description} . '%');
 
 212   if ($form->{periodic_invoices_active} ne $form->{periodic_invoices_inactive}) {
 
 213     my $not  = $form->{periodic_invoices_inactive} ? 'NOT' : '';
 
 214     $query  .= qq| AND ${not} COALESCE(pcfg.active, 'f')|;
 
 217   my $sortdir   = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
 
 218   my $sortorder = join(', ', map { "${_} ${sortdir} " } ("o.id", $form->sort_columns("transdate", $ordnumber, "name")));
 
 219   my %allowed_sort_columns = (
 
 220     "transdate"               => "o.transdate",
 
 221     "reqdate"                 => "o.reqdate",
 
 223     "ordnumber"               => "o.ordnumber",
 
 224     "quonumber"               => "o.quonumber",
 
 226     "employee"                => "e.name",
 
 227     "salesman"                => "s.name",
 
 228     "shipvia"                 => "o.shipvia",
 
 229     "transaction_description" => "o.transaction_description",
 
 230     "shippingpoint"           => "o.shippingpoint",
 
 231     "taxzone"                 => "tz.description",
 
 233   if ($form->{sort} && grep($form->{sort}, keys(%allowed_sort_columns))) {
 
 234     $sortorder = $allowed_sort_columns{$form->{sort}} . " ${sortdir}";
 
 236   $query .= qq| ORDER by | . $sortorder;
 
 238   my $sth = $dbh->prepare($query);
 
 239   $sth->execute(@values) ||
 
 240     $form->dberror($query . " (" . join(", ", @values) . ")");
 
 244   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 245     $ref->{exchangerate} = 1 unless $ref->{exchangerate};
 
 246     push @{ $form->{OE} }, $ref if $ref->{id} != $id{ $ref->{id} };
 
 247     $id{ $ref->{id} } = $ref->{id};
 
 252   $main::lxdebug->leave_sub();
 
 255 sub transactions_for_todo_list {
 
 256   $main::lxdebug->enter_sub();
 
 261   my $myconfig = \%main::myconfig;
 
 262   my $form     = $main::form;
 
 264   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
 
 266   my $query    = qq|SELECT id FROM employee WHERE login = ?|;
 
 267   my ($e_id)   = selectrow_query($form, $dbh, $query, $form->{login});
 
 270     qq|SELECT oe.id, oe.transdate, oe.reqdate, oe.quonumber, oe.transaction_description, oe.amount,
 
 271          CASE WHEN (COALESCE(oe.customer_id, 0) = 0) THEN 'vendor' ELSE 'customer' END AS vc,
 
 276        LEFT JOIN customer c ON (oe.customer_id = c.id)
 
 277        LEFT JOIN vendor v   ON (oe.vendor_id   = v.id)
 
 278        LEFT JOIN employee e ON (oe.employee_id = e.id)
 
 279        WHERE (COALESCE(quotation, FALSE) = TRUE)
 
 280          AND (COALESCE(closed,    FALSE) = FALSE)
 
 281          AND ((oe.employee_id = ?) OR (oe.salesman_id = ?))
 
 282          AND NOT (oe.reqdate ISNULL)
 
 283          AND (oe.reqdate < current_date)
 
 286   my $quotations = selectall_hashref_query($form, $dbh, $query, $e_id, $e_id);
 
 288   $main::lxdebug->leave_sub();
 
 294   $main::lxdebug->enter_sub();
 
 296   my ($self, $myconfig, $form) = @_;
 
 298   # connect to database, turn off autocommit
 
 299   my $dbh = $form->get_standard_dbh;
 
 301   my ($query, @values, $sth, $null);
 
 302   my $exchangerate = 0;
 
 304   my $all_units = AM->retrieve_units($myconfig, $form);
 
 305   $form->{all_units} = $all_units;
 
 307   my $ic_cvar_configs = CVar->get_configs(module => 'IC',
 
 310   $form->{employee_id} = (split /--/, $form->{employee})[1] if !$form->{employee_id};
 
 311   unless ($form->{employee_id}) {
 
 312     $form->get_employee($dbh);
 
 315   my $ml = ($form->{type} eq 'sales_order') ? 1 : -1;
 
 318     $query = qq|DELETE FROM custom_variables
 
 319                 WHERE (config_id IN (SELECT id FROM custom_variable_configs WHERE module = 'IC'))
 
 320                   AND (sub_module = 'orderitems')
 
 321                   AND (trans_id IN (SELECT id FROM orderitems WHERE trans_id = ?))|;
 
 322     do_query($form, $dbh, $query, $form->{id});
 
 324     $query = qq|DELETE FROM orderitems WHERE trans_id = ?|;
 
 325     do_query($form, $dbh, $query, $form->{id});
 
 327     $query = qq|DELETE FROM shipto | .
 
 328              qq|WHERE trans_id = ? AND module = 'OE'|;
 
 329     do_query($form, $dbh, $query, $form->{id});
 
 333     $query = qq|SELECT nextval('id')|;
 
 334     ($form->{id}) = selectrow_query($form, $dbh, $query);
 
 336     $query = qq|INSERT INTO oe (id, ordnumber, employee_id, currency_id) VALUES (?, '', ?, (SELECT currency_id FROM defaults))|;
 
 337     do_query($form, $dbh, $query, $form->{id}, $form->{employee_id});
 
 355   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
 
 356   my %price_factors = map { $_->{id} => $_->{factor} } @{ $form->{ALL_PRICE_FACTORS} };
 
 359   for my $i (1 .. $form->{rowcount}) {
 
 361     map({ $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"}) } qw(qty ship));
 
 363     if ($form->{"id_$i"}) {
 
 366       $query = qq|SELECT unit FROM parts WHERE id = ?|;
 
 367       my ($item_unit) = selectrow_query($form, $dbh, $query, $form->{"id_$i"});
 
 370       if (defined($all_units->{$item_unit}->{factor}) &&
 
 371           (($all_units->{$item_unit}->{factor} * 1) != 0)) {
 
 372         $basefactor = $all_units->{$form->{"unit_$i"}}->{factor} / $all_units->{$item_unit}->{factor};
 
 374       my $baseqty = $form->{"qty_$i"} * $basefactor;
 
 376       $form->{"marge_percent_$i"} = $form->parse_amount($myconfig, $form->{"marge_percent_$i"}) * 1;
 
 377       $form->{"marge_absolut_$i"} = $form->parse_amount($myconfig, $form->{"marge_absolut_$i"}) * 1;
 
 379       $form->{"lastcost_$i"} = $form->parse_amount($myconfig, $form->{"lastcost_$i"});
 
 381       # set values to 0 if nothing entered
 
 382       $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
 
 384       $form->{"sellprice_$i"} = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 385       $fxsellprice = $form->{"sellprice_$i"};
 
 387       my ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
 
 389       my $decimalplaces = ($dec > 2) ? $dec : 2;
 
 391       $discount = $form->round_amount($form->{"sellprice_$i"} * $form->{"discount_$i"}, $decimalplaces);
 
 392       $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} - $discount, $decimalplaces);
 
 394       $form->{"inventory_accno_$i"} *= 1;
 
 395       $form->{"expense_accno_$i"}   *= 1;
 
 397       $price_factor = $price_factors{ $form->{"price_factor_id_$i"} } || 1;
 
 398       $linetotal    = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2);
 
 400       @taxaccounts = split(/ /, $form->{"taxaccounts_$i"});
 
 404       map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;
 
 406       if ($form->{taxincluded}) {
 
 407         $taxamount = $linetotal * $taxrate / (1 + $taxrate);
 
 408         $taxbase   = $linetotal - $taxamount;
 
 410         # we are not keeping a natural price, do not round
 
 411         $form->{"sellprice_$i"} =
 
 412           $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
 
 414         $taxamount = $linetotal * $taxrate;
 
 415         $taxbase   = $linetotal;
 
 418       if ($form->round_amount($taxrate, 7) == 0) {
 
 419         if ($form->{taxincluded}) {
 
 420           foreach my $item (@taxaccounts) {
 
 421             $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2);
 
 422             $taxaccounts{$item} += $taxamount;
 
 423             $taxdiff            += $taxamount;
 
 424             $taxbase{$item}     += $taxbase;
 
 426           $taxaccounts{ $taxaccounts[0] } += $taxdiff;
 
 428           foreach my $item (@taxaccounts) {
 
 429             $taxaccounts{$item} += $linetotal * $form->{"${item}_rate"};
 
 430             $taxbase{$item}     += $taxbase;
 
 434         foreach my $item (@taxaccounts) {
 
 435           $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate;
 
 436           $taxbase{$item} += $taxbase;
 
 440       $netamount += $form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor;
 
 442       $reqdate = ($form->{"reqdate_$i"}) ? $form->{"reqdate_$i"} : undef;
 
 444       # Get pricegroup_id and save it. Unfortunately the interface
 
 445       # also uses ID "0" for signalling that none is selected, but "0"
 
 446       # must not be stored in the database. Therefore we cannot simply
 
 448       ($null, my $pricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
 
 450       $pricegroup_id  = undef if !$pricegroup_id;
 
 452       # save detail record in orderitems table
 
 453       my $orderitems_id = $form->{"orderitems_id_$i"};
 
 454       ($orderitems_id)  = selectfirst_array_query($form, $dbh, qq|SELECT nextval('orderitemsid')|) if (!$orderitems_id);
 
 457       $query = qq|INSERT INTO orderitems (
 
 458                     id, trans_id, parts_id, description, longdescription, qty, base_qty,
 
 459                     sellprice, discount, unit, reqdate, project_id, serialnumber, ship,
 
 460                     pricegroup_id, ordnumber, transdate, cusordnumber, subtotal,
 
 461                     marge_percent, marge_total, lastcost, price_factor_id, price_factor, marge_price_factor)
 
 462                   VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
 
 463                           (SELECT factor FROM price_factors WHERE id = ?), ?)|;
 
 465            conv_i($orderitems_id), conv_i($form->{id}), conv_i($form->{"id_$i"}),
 
 466            $form->{"description_$i"}, $form->{"longdescription_$i"},
 
 467            $form->{"qty_$i"}, $baseqty,
 
 468            $fxsellprice, $form->{"discount_$i"},
 
 469            $form->{"unit_$i"}, conv_date($reqdate), conv_i($form->{"project_id_$i"}),
 
 470            $form->{"serialnumber_$i"}, $form->{"ship_$i"}, $pricegroup_id,
 
 471            $form->{"ordnumber_$i"}, conv_date($form->{"transdate_$i"}),
 
 472            $form->{"cusordnumber_$i"}, $form->{"subtotal_$i"} ? 't' : 'f',
 
 473            $form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
 
 474            $form->{"lastcost_$i"},
 
 475            conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
 
 476            conv_i($form->{"marge_price_factor_$i"}));
 
 477       do_query($form, $dbh, $query, @values);
 
 479       $form->{"sellprice_$i"} = $fxsellprice;
 
 480       $form->{"discount_$i"} *= 100;
 
 482       CVar->save_custom_variables(module       => 'IC',
 
 483                                   sub_module   => 'orderitems',
 
 484                                   trans_id     => $orderitems_id,
 
 485                                   configs      => $ic_cvar_configs,
 
 487                                   name_prefix  => 'ic_',
 
 488                                   name_postfix => "_$i",
 
 493   $reqdate = ($form->{reqdate}) ? $form->{reqdate} : undef;
 
 497   map { $tax += $form->round_amount($taxaccounts{$_}, 2) } keys %taxaccounts;
 
 499   $amount = $form->round_amount($netamount + $tax, 2);
 
 500   $netamount = $form->round_amount($netamount, 2);
 
 502   if ($form->{currency} eq $form->{defaultcurrency}) {
 
 503     $form->{exchangerate} = 1;
 
 505     $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? 'buy' : 'sell');
 
 508   $form->{exchangerate} = $exchangerate || $form->parse_amount($myconfig, $form->{exchangerate});
 
 510   my $quotation = $form->{type} =~ /_order$/ ? 'f' : 't';
 
 512   ($null, $form->{department_id}) = split(/--/, $form->{department}) if $form->{department};
 
 517          ordnumber = ?, quonumber = ?, cusordnumber = ?, transdate = ?, vendor_id = ?,
 
 518          customer_id = ?, amount = ?, netamount = ?, reqdate = ?, taxincluded = ?,
 
 519          shippingpoint = ?, shipvia = ?, notes = ?, intnotes = ?, currency_id = (SELECT id FROM currencies WHERE name=?), closed = ?,
 
 520          delivered = ?, proforma = ?, quotation = ?, department_id = ?, language_id = ?,
 
 521          taxzone_id = ?, shipto_id = ?, payment_id = ?, delivery_vendor_id = ?, delivery_customer_id = ?,
 
 522          globalproject_id = ?, employee_id = ?, salesman_id = ?, cp_id = ?, transaction_description = ?, marge_total = ?, marge_percent = ?
 
 525   @values = ($form->{ordnumber} || '', $form->{quonumber},
 
 526              $form->{cusordnumber}, conv_date($form->{transdate}),
 
 527              conv_i($form->{vendor_id}), conv_i($form->{customer_id}),
 
 528              $amount, $netamount, conv_date($reqdate),
 
 529              $form->{taxincluded} ? 't' : 'f', $form->{shippingpoint},
 
 530              $form->{shipvia}, $form->{notes}, $form->{intnotes},
 
 531              $form->{currency}, $form->{closed} ? 't' : 'f',
 
 532              $form->{delivered} ? "t" : "f", $form->{proforma} ? 't' : 'f',
 
 533              $quotation, conv_i($form->{department_id}),
 
 534              conv_i($form->{language_id}), conv_i($form->{taxzone_id}),
 
 535              conv_i($form->{shipto_id}), conv_i($form->{payment_id}),
 
 536              conv_i($form->{delivery_vendor_id}),
 
 537              conv_i($form->{delivery_customer_id}),
 
 538              conv_i($form->{globalproject_id}), conv_i($form->{employee_id}),
 
 539              conv_i($form->{salesman_id}), conv_i($form->{cp_id}),
 
 540              $form->{transaction_description},
 
 541              $form->{marge_total} * 1, $form->{marge_percent} * 1,
 
 542              conv_i($form->{id}));
 
 543   do_query($form, $dbh, $query, @values);
 
 545   $form->{ordtotal} = $amount;
 
 548   $form->{name} = $form->{ $form->{vc} };
 
 549   $form->{name} =~ s/--\Q$form->{"$form->{vc}_id"}\E//;
 
 551   if (!$form->{shipto_id}) {
 
 552     $form->add_shipto($dbh, $form->{id}, "OE");
 
 555   # save printed, emailed, queued
 
 556   $form->save_status($dbh);
 
 558   # Link this record to the records it was created from.
 
 559   $form->{convert_from_oe_ids} =~ s/^\s+//;
 
 560   $form->{convert_from_oe_ids} =~ s/\s+$//;
 
 561   my @convert_from_oe_ids      =  split m/\s+/, $form->{convert_from_oe_ids};
 
 562   delete $form->{convert_from_oe_ids};
 
 564   if (scalar @convert_from_oe_ids) {
 
 565     RecordLinks->create_links('dbh'        => $dbh,
 
 567                               'from_table' => 'oe',
 
 568                               'from_ids'   => \@convert_from_oe_ids,
 
 570                               'to_id'      => $form->{id},
 
 573     $self->_close_quotations_rfqs('dbh'     => $dbh,
 
 574                                   'from_id' => \@convert_from_oe_ids,
 
 575                                   'to_id'   => $form->{id});
 
 578   if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
 
 579     if ($form->{vc} eq 'customer') {
 
 580       $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, $form->{exchangerate}, 0);
 
 582     if ($form->{vc} eq 'vendor') {
 
 583       $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, 0, $form->{exchangerate});
 
 587   $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ?
 
 588                                        "quonumber" : "ordnumber"};
 
 590   Common::webdav_folder($form);
 
 592   my $rc = $dbh->commit;
 
 594   $self->save_periodic_invoices_config(dbh         => $dbh,
 
 595                                        oe_id       => $form->{id},
 
 596                                        config_yaml => $form->{periodic_invoices_config})
 
 597     if ($form->{type} eq 'sales_order');
 
 599   $main::lxdebug->leave_sub();
 
 604 sub save_periodic_invoices_config {
 
 605   my ($self, %params) = @_;
 
 607   return if !$params{oe_id};
 
 609   my $config = $params{config_yaml} ? YAML::Load($params{config_yaml}) : undef;
 
 610   return if 'HASH' ne ref $config;
 
 612   my $obj  = SL::DB::Manager::PeriodicInvoicesConfig->find_by(oe_id => $params{oe_id})
 
 613           || SL::DB::PeriodicInvoicesConfig->new(oe_id => $params{oe_id});
 
 614   $obj->update_attributes(%{ $config });
 
 617 sub load_periodic_invoice_config {
 
 621   delete $form->{periodic_invoices_config};
 
 624     my $config_obj = SL::DB::Manager::PeriodicInvoicesConfig->find_by(oe_id => $form->{id});
 
 627       my $config = { map { $_ => $config_obj->$_ } qw(active terminated periodicity start_date_as_date end_date_as_date extend_automatically_by ar_chart_id
 
 628                                                       print printer_id copies) };
 
 629       $form->{periodic_invoices_config} = YAML::Dump($config);
 
 634 sub _close_quotations_rfqs {
 
 635   $main::lxdebug->enter_sub();
 
 640   Common::check_params(\%params, qw(from_id to_id));
 
 642   my $myconfig = \%main::myconfig;
 
 643   my $form     = $main::form;
 
 645   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
 
 647   my $query    = qq|SELECT quotation FROM oe WHERE id = ?|;
 
 648   my $sth      = prepare_query($form, $dbh, $query);
 
 650   do_statement($form, $sth, $query, conv_i($params{to_id}));
 
 652   my ($quotation) = $sth->fetchrow_array();
 
 655     $main::lxdebug->leave_sub();
 
 661   foreach my $from_id (@{ $params{from_id} }) {
 
 662     $from_id = conv_i($from_id);
 
 663     do_statement($form, $sth, $query, $from_id);
 
 664     ($quotation) = $sth->fetchrow_array();
 
 665     push @close_ids, $from_id if ($quotation);
 
 670   if (scalar @close_ids) {
 
 671     $query = qq|UPDATE oe SET closed = TRUE WHERE id IN (| . join(', ', ('?') x scalar @close_ids) . qq|)|;
 
 672     do_query($form, $dbh, $query, @close_ids);
 
 674     $dbh->commit() unless ($params{dbh});
 
 677   $main::lxdebug->leave_sub();
 
 681   $main::lxdebug->enter_sub();
 
 683   my ($self, $myconfig, $form) = @_;
 
 685   my $rc = SL::DB::Order->new->db->with_transaction(sub {
 
 686     my @spoolfiles = grep { $_ } map { $_->spoolfile } @{ SL::DB::Manager::Status->get_all(where => [ trans_id => $form->{id} ]) };
 
 688     SL::DB::Order->new(id => $form->{id})->delete;
 
 690     my $spool = $::lx_office_conf{paths}->{spool};
 
 691     unlink map { "$spool/$_" } @spoolfiles if $spool;
 
 696   $main::lxdebug->leave_sub();
 
 702   $main::lxdebug->enter_sub();
 
 704   my ($self, $myconfig, $form) = @_;
 
 706   # connect to database
 
 707   my $dbh = $form->get_standard_dbh;
 
 709   my ($query, $query_add, @values, @ids, $sth);
 
 711   # translate the ids (given by id_# and trans_id_#) into one array of ids, so we can join them later
 
 713     push @ids, $form->{"trans_id_$_"}
 
 714       if ($form->{"multi_id_$_"} and $form->{"trans_id_$_"})
 
 715   } (1 .. $form->{"rowcount"});
 
 717   if ($form->{rowcount} && scalar @ids) {
 
 718     $form->{convert_from_oe_ids} = join ' ', @ids;
 
 721   # if called in multi id mode, and still only got one id, switch back to single id
 
 722   if ($form->{"rowcount"} and $#ids == 0) {
 
 723     $form->{"id"} = $ids[0];
 
 727   # and remember for the rest of the function
 
 728   my $is_collective_order = scalar @ids;
 
 731     my $wday         = (localtime(time))[6];
 
 732     my $next_workday = $wday == 5 ? 3 : $wday == 6 ? 2 : 1;
 
 733     $query_add       = qq|, current_date AS transdate, date(current_date + interval '${next_workday} days') AS reqdate|;
 
 736   # get default accounts
 
 737   $query = qq|SELECT (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
 
 738                      (SELECT c.accno FROM chart c WHERE d.income_accno_id    = c.id) AS income_accno,
 
 739                      (SELECT c.accno FROM chart c WHERE d.expense_accno_id   = c.id) AS expense_accno,
 
 740                      (SELECT c.accno FROM chart c WHERE d.fxgain_accno_id    = c.id) AS fxgain_accno,
 
 741                      (SELECT c.accno FROM chart c WHERE d.fxloss_accno_id    = c.id) AS fxloss_accno
 
 744   my $ref = selectfirst_hashref_query($form, $dbh, $query);
 
 745   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 747   $form->{currency} = $form->get_default_currency($myconfig);
 
 749   # set reqdate if this is an invoice->order conversion. If someone knows a better check to ensure
 
 750   # we come from invoices, feel free.
 
 751   $form->{reqdate} = $form->{deliverydate}
 
 752     if (    $form->{deliverydate}
 
 753         and $form->{callback} =~ /action=ar_transactions/);
 
 755   my $vc = $form->{vc} eq "customer" ? "customer" : "vendor";
 
 757   if ($form->{id} or @ids) {
 
 759     # retrieve order for single id
 
 760     # NOTE: this query is intended to fetch all information only ONCE.
 
 761     # so if any of these infos is important (or even different) for any item,
 
 762     # it will be killed out and then has to be fetched from the item scope query further down
 
 764       qq|SELECT o.cp_id, o.ordnumber, o.transdate, o.reqdate,
 
 765            o.taxincluded, o.shippingpoint, o.shipvia, o.notes, o.intnotes,
 
 766            (SELECT cu.name FROM currencies cu WHERE cu.id=o.currency_id) AS currency, e.name AS employee, o.employee_id, o.salesman_id,
 
 767            o.${vc}_id, cv.name AS ${vc}, o.amount AS invtotal,
 
 768            o.closed, o.reqdate, o.quonumber, o.department_id, o.cusordnumber,
 
 769            d.description AS department, o.payment_id, o.language_id, o.taxzone_id,
 
 770            o.delivery_customer_id, o.delivery_vendor_id, o.proforma, o.shipto_id,
 
 771            o.globalproject_id, o.delivered, o.transaction_description
 
 773          JOIN ${vc} cv ON (o.${vc}_id = cv.id)
 
 774          LEFT JOIN employee e ON (o.employee_id = e.id)
 
 775          LEFT JOIN department d ON (o.department_id = d.id) | .
 
 778          : "WHERE o.id IN (" . join(', ', map("? ", @ids)) . ")"
 
 780     @values = $form->{id} ? ($form->{id}) : @ids;
 
 781     $sth = prepare_execute_query($form, $dbh, $query, @values);
 
 783     $ref = $sth->fetchrow_hashref("NAME_lc");
 
 786       map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 788       $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ? "quonumber" : "ordnumber"};
 
 790       # set all entries for multiple ids blank that yield different information
 
 791       while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 792         map { $form->{$_} = '' if ($ref->{$_} ne $form->{$_}) } keys %$ref;
 
 796     # if not given, fill transdate with current_date
 
 797     $form->{transdate} = $form->current_date($myconfig)
 
 798       unless $form->{transdate};
 
 802     if ($form->{delivery_customer_id}) {
 
 803       $query = qq|SELECT name FROM customer WHERE id = ?|;
 
 804       ($form->{delivery_customer_string}) = selectrow_query($form, $dbh, $query, $form->{delivery_customer_id});
 
 807     if ($form->{delivery_vendor_id}) {
 
 808       $query = qq|SELECT name FROM customer WHERE id = ?|;
 
 809       ($form->{delivery_vendor_string}) = selectrow_query($form, $dbh, $query, $form->{delivery_vendor_id});
 
 812     # shipto and pinted/mailed/queued status makes only sense for single id retrieve
 
 814       $query = qq|SELECT s.* FROM shipto s WHERE s.trans_id = ? AND s.module = 'OE'|;
 
 815       $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
 
 817       $ref = $sth->fetchrow_hashref("NAME_lc");
 
 819       map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 822       # get printed, emailed and queued
 
 823       $query = qq|SELECT s.printed, s.emailed, s.spoolfile, s.formname FROM status s WHERE s.trans_id = ?|;
 
 824       $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
 
 826       while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 827         $form->{printed} .= "$ref->{formname} " if $ref->{printed};
 
 828         $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
 
 829         $form->{queued}  .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
 
 832       map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
 
 835     my $transdate = $form->{transdate} ? $dbh->quote($form->{transdate}) : "current_date";
 
 837     $form->{taxzone_id} = 0 unless ($form->{taxzone_id});
 
 839     # retrieve individual items
 
 840     # this query looks up all information about the items
 
 841     # stuff different from the whole will not be overwritten, but saved with a suffix.
 
 843       qq|SELECT o.id AS orderitems_id,
 
 844            c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from as inventory_valid,
 
 845            c2.accno AS income_accno,    c2.new_chart_id AS income_new_chart,    date($transdate) - c2.valid_from as income_valid,
 
 846            c3.accno AS expense_accno,   c3.new_chart_id AS expense_new_chart,   date($transdate) - c3.valid_from as expense_valid,
 
 847            oe.ordnumber AS ordnumber_oe, oe.transdate AS transdate_oe, oe.cusordnumber AS cusordnumber_oe,
 
 848            p.partnumber, p.assembly, p.listprice, o.description, o.qty,
 
 849            o.sellprice, o.parts_id AS id, o.unit, o.discount, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id,
 
 850            o.reqdate, o.project_id, o.serialnumber, o.ship, o.lastcost,
 
 851            o.ordnumber, o.transdate, o.cusordnumber, o.subtotal, o.longdescription,
 
 852            o.price_factor_id, o.price_factor, o.marge_price_factor,
 
 853            pr.projectnumber, p.formel,
 
 854            pg.partsgroup, o.pricegroup_id, (SELECT pricegroup FROM pricegroup WHERE id=o.pricegroup_id) as pricegroup
 
 856          JOIN parts p ON (o.parts_id = p.id)
 
 857          JOIN oe ON (o.trans_id = oe.id)
 
 858          LEFT JOIN chart c1 ON ((SELECT inventory_accno_id                   FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c1.id)
 
 859          LEFT JOIN chart c2 ON ((SELECT income_accno_id_$form->{taxzone_id}  FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c2.id)
 
 860          LEFT JOIN chart c3 ON ((SELECT expense_accno_id_$form->{taxzone_id} FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c3.id)
 
 861          LEFT JOIN project pr ON (o.project_id = pr.id)
 
 862          LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
 
 864        ? qq|WHERE o.trans_id = ?|
 
 865        : qq|WHERE o.trans_id IN (| . join(", ", map("?", @ids)) . qq|)|) .
 
 868     @ids = $form->{id} ? ($form->{id}) : @ids;
 
 869     $sth = prepare_execute_query($form, $dbh, $query, @values);
 
 871     while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
 
 872       # Retrieve custom variables.
 
 873       my $cvars = CVar->get_custom_variables(dbh        => $dbh,
 
 875                                              sub_module => 'orderitems',
 
 876                                              trans_id   => $ref->{orderitems_id},
 
 878       map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
 
 881       if (!$ref->{"part_inventory_accno_id"}) {
 
 882         map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid));
 
 884       delete($ref->{"part_inventory_accno_id"});
 
 886       # in collective order, copy global ordnumber, transdate, cusordnumber into item scope
 
 887       #   unless already present there
 
 888       # remove _oe entries afterwards
 
 889       map { $ref->{$_} = $ref->{"${_}_oe"} if ($ref->{$_} eq '') }
 
 890         qw|ordnumber transdate cusordnumber|
 
 892       map { delete $ref->{$_} } qw|ordnumber_oe transdate_oe cusordnumber_oe|;
 
 896       while ($ref->{inventory_new_chart} && ($ref->{inventory_valid} >= 0)) {
 
 898           qq|SELECT accno AS inventory_accno, | .
 
 899           qq|  new_chart_id AS inventory_new_chart, | .
 
 900           qq|  date($transdate) - valid_from AS inventory_valid | .
 
 901           qq|FROM chart WHERE id = $ref->{inventory_new_chart}|;
 
 902         ($ref->{inventory_accno}, $ref->{inventory_new_chart},
 
 903          $ref->{inventory_valid}) = selectrow_query($form, $dbh, $query);
 
 906       while ($ref->{income_new_chart} && ($ref->{income_valid} >= 0)) {
 
 908           qq|SELECT accno AS income_accno, | .
 
 909           qq|  new_chart_id AS income_new_chart, | .
 
 910           qq|  date($transdate) - valid_from AS income_valid | .
 
 911           qq|FROM chart WHERE id = $ref->{income_new_chart}|;
 
 912         ($ref->{income_accno}, $ref->{income_new_chart},
 
 913          $ref->{income_valid}) = selectrow_query($form, $dbh, $query);
 
 916       while ($ref->{expense_new_chart} && ($ref->{expense_valid} >= 0)) {
 
 918           qq|SELECT accno AS expense_accno, | .
 
 919           qq|  new_chart_id AS expense_new_chart, | .
 
 920           qq|  date($transdate) - valid_from AS expense_valid | .
 
 921           qq|FROM chart WHERE id = $ref->{expense_new_chart}|;
 
 922         ($ref->{expense_accno}, $ref->{expense_new_chart},
 
 923          $ref->{expense_valid}) = selectrow_query($form, $dbh, $query);
 
 926       # delete orderitems_id in collective orders, so that they get cloned no matter what
 
 927       delete $ref->{orderitems_id} if (@ids);
 
 929       # get tax rates and description
 
 930       my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
 
 932         qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber | .
 
 933         qq|FROM tax t LEFT JOIN chart c on (c.id = t.chart_id) | .
 
 934         qq|WHERE t.id IN (SELECT tk.tax_id FROM taxkeys tk | .
 
 935         qq|               WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?) | .
 
 936         qq|                 AND startdate <= $transdate ORDER BY startdate DESC LIMIT 1) | .
 
 937         qq|ORDER BY c.accno|;
 
 938       my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
 
 939       $ref->{taxaccounts} = "";
 
 941       while (my $ptr = $stw->fetchrow_hashref("NAME_lc")) {
 
 942         if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
 
 946         $ref->{taxaccounts} .= "$ptr->{accno} ";
 
 947         if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
 
 948           $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
 
 949           $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
 
 950           $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
 
 951           $form->{taxaccounts} .= "$ptr->{accno} ";
 
 956       chop $ref->{taxaccounts};
 
 958       push @{ $form->{form_details} }, $ref;
 
 966     $form->lastname_used($dbh, $myconfig, $form->{vc})
 
 967       unless $form->{"$form->{vc}_id"};
 
 971   $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? "buy" : "sell");
 
 973   Common::webdav_folder($form);
 
 975   $self->load_periodic_invoice_config($form);
 
 977   my $rc = $dbh->commit;
 
 979   $main::lxdebug->leave_sub();
 
 984 sub retrieve_simple {
 
 985   $main::lxdebug->enter_sub();
 
 990   Common::check_params(\%params, qw(id));
 
 992   my $myconfig    = \%main::myconfig;
 
 993   my $form        = $main::form;
 
 995   my $dbh         = $params{dbh} || $form->get_standard_dbh($myconfig);
 
 997   my $oe_query    = qq|SELECT * FROM oe         WHERE id = ?|;
 
 998   my $oi_query    = qq|SELECT * FROM orderitems WHERE trans_id = ?|;
 
1000   my $order            = selectfirst_hashref_query($form, $dbh, $oe_query, conv_i($params{id}));
 
1001   $order->{orderitems} = selectall_hashref_query(  $form, $dbh, $oi_query, conv_i($params{id}));
 
1003   $main::lxdebug->leave_sub();
 
1009   $main::lxdebug->enter_sub();
 
1011   my ($self, $myconfig, $form) = @_;
 
1013   # connect to database
 
1014   my $dbh = $form->get_standard_dbh;
 
1020   my $nodiscount_subtotal = 0;
 
1021   my $discount_subtotal = 0;
 
1024   my @partsgroup = ();
 
1027   my $subtotal_header = 0;
 
1028   my $subposition = 0;
 
1034   my (@project_ids, %projectnumbers, %projectdescriptions);
 
1036   push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});
 
1038   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS',
 
1039                    'departments'   => 'ALL_DEPARTMENTS');
 
1042   foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
 
1043     $price_factors{$pfac->{id}}  = $pfac;
 
1044     $pfac->{factor}             *= 1;
 
1045     $pfac->{formatted_factor}    = $form->format_amount($myconfig, $pfac->{factor});
 
1049   foreach my $dept (@{ $form->{ALL_DEPARTMENTS} }) {
 
1050     next unless $dept->{id} eq $form->{department_id};
 
1051     $form->{department} = $dept->{description};
 
1055   # sort items by partsgroup
 
1056   for $i (1 .. $form->{rowcount}) {
 
1058     if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
 
1059       $partsgroup = $form->{"partsgroup_$i"};
 
1061     push @partsgroup, [$i, $partsgroup];
 
1062     push(@project_ids, $form->{"project_id_$i"}) if ($form->{"project_id_$i"});
 
1066     $query = "SELECT id, projectnumber, description FROM project WHERE id IN (" .
 
1067       join(", ", map("?", @project_ids)) . ")";
 
1068     $sth = prepare_execute_query($form, $dbh, $query, @project_ids);
 
1069     while (my $ref = $sth->fetchrow_hashref()) {
 
1070       $projectnumbers{$ref->{id}} = $ref->{projectnumber};
 
1071       $projectdescriptions{$ref->{id}} = $ref->{description};
 
1076   $form->{"globalprojectnumber"} = $projectnumbers{$form->{"globalproject_id"}};
 
1077   $form->{"globalprojectdescription"} = $projectdescriptions{$form->{"globalproject_id"}};
 
1079   $form->{discount} = [];
 
1081   $form->{TEMPLATE_ARRAYS} = { };
 
1082   IC->prepare_parts_for_printing(myconfig => $myconfig, form => $form);
 
1084   my $ic_cvar_configs = CVar->get_configs(module => 'IC');
 
1087     qw(runningnumber number description longdescription qty ship unit bin
 
1088        partnotes serialnumber reqdate sellprice listprice netprice
 
1089        discount p_discount discount_sub nodiscount_sub
 
1090        linetotal  nodiscount_linetotal tax_rate projectnumber projectdescription
 
1091        price_factor price_factor_name partsgroup weight lineweight);
 
1093   push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };
 
1095   my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);
 
1097   map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays);
 
1099   my $totalweight = 0;
 
1101   foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
 
1104     if ($item->[1] ne $sameitem) {
 
1105       push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, qq|$item->[1]|);
 
1106       $sameitem = $item->[1];
 
1108       map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
1111     $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
 
1113     if ($form->{"id_$i"} != 0) {
 
1115       # add number, description and qty to $form->{number}, ....
 
1117       if ($form->{"subtotal_$i"} && !$subtotal_header) {
 
1118         $subtotal_header = $i;
 
1119         $position = int($position);
 
1122       } elsif ($subtotal_header) {
 
1124         $position = int($position);
 
1125         $position = $position.".".$subposition;
 
1127         $position = int($position);
 
1131       my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || { 'factor' => 1 };
 
1133       push @{ $form->{TEMPLATE_ARRAYS}->{runningnumber} },     $position;
 
1134       push @{ $form->{TEMPLATE_ARRAYS}->{number} },            $form->{"partnumber_$i"};
 
1135       push @{ $form->{TEMPLATE_ARRAYS}->{description} },       $form->{"description_$i"};
 
1136       push @{ $form->{TEMPLATE_ARRAYS}->{longdescription} },   $form->{"longdescription_$i"};
 
1137       push @{ $form->{TEMPLATE_ARRAYS}->{qty} },               $form->format_amount($myconfig, $form->{"qty_$i"});
 
1138       push @{ $form->{TEMPLATE_ARRAYS}->{qty_nofmt} },         $form->{"qty_$i"};
 
1139       push @{ $form->{TEMPLATE_ARRAYS}->{ship} },              $form->format_amount($myconfig, $form->{"ship_$i"});
 
1140       push @{ $form->{TEMPLATE_ARRAYS}->{ship_nofmt} },        $form->{"ship_$i"};
 
1141       push @{ $form->{TEMPLATE_ARRAYS}->{unit} },              $form->{"unit_$i"};
 
1142       push @{ $form->{TEMPLATE_ARRAYS}->{bin} },               $form->{"bin_$i"};
 
1143       push @{ $form->{TEMPLATE_ARRAYS}->{partnotes} },         $form->{"partnotes_$i"};
 
1144       push @{ $form->{TEMPLATE_ARRAYS}->{serialnumber} },      $form->{"serialnumber_$i"};
 
1145       push @{ $form->{TEMPLATE_ARRAYS}->{reqdate} },           $form->{"reqdate_$i"};
 
1146       push @{ $form->{TEMPLATE_ARRAYS}->{sellprice} },         $form->{"sellprice_$i"};
 
1147       push @{ $form->{TEMPLATE_ARRAYS}->{sellprice_nofmt} },   $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
1148       push @{ $form->{TEMPLATE_ARRAYS}->{listprice} },         $form->{"listprice_$i"};
 
1149       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor} },      $price_factor->{formatted_factor};
 
1150       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor_name} }, $price_factor->{description};
 
1151       push @{ $form->{TEMPLATE_ARRAYS}->{partsgroup} },        $form->{"partsgroup_$i"};
 
1153       my $sellprice     = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
1154       my ($dec)         = ($sellprice =~ /\.(\d+)/);
 
1155       my $decimalplaces = max 2, length($dec);
 
1157       my $parsed_discount            = $form->parse_amount($myconfig, $form->{"discount_$i"});
 
1159       my $linetotal_exact            = $form->{"qty_$i"} * $sellprice * (100 - $parsed_discount) / 100 / $price_factor->{factor};
 
1160       my $linetotal                  = $form->round_amount($linetotal_exact, 2);
 
1162       my $nodiscount_exact_linetotal = $form->{"qty_$i"} * $sellprice                                  / $price_factor->{factor};
 
1163       my $nodiscount_linetotal       = $form->round_amount($nodiscount_exact_linetotal,2);
 
1165       my $discount                   = $nodiscount_linetotal - $linetotal; # is always rounded because $nodiscount_linetotal and $linetotal are rounded
 
1167       my $discount_round_error       = $discount + ($linetotal_exact - $nodiscount_exact_linetotal); # not used
 
1169       $form->{"netprice_$i"}   = $form->round_amount($form->{"qty_$i"} ? ($linetotal / $form->{"qty_$i"}) : 0, 2);
 
1171       push @{ $form->{TEMPLATE_ARRAYS}->{netprice} },       ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : '';
 
1172       push @{ $form->{TEMPLATE_ARRAYS}->{netprice_nofmt} }, ($form->{"netprice_$i"} != 0) ? $form->{"netprice_$i"} : '';
 
1174       $linetotal = ($linetotal != 0) ? $linetotal : '';
 
1176       push @{ $form->{TEMPLATE_ARRAYS}->{discount} },       ($discount != 0) ? $form->format_amount($myconfig, $discount * -1, 2) : '';
 
1177       push @{ $form->{TEMPLATE_ARRAYS}->{discount_nofmt} }, ($discount != 0) ? $discount * -1 : '';
 
1178       push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} },     $form->{"discount_$i"};
 
1180       $form->{ordtotal}         += $linetotal;
 
1181       $form->{nodiscount_total} += $nodiscount_linetotal;
 
1182       $form->{discount_total}   += $discount;
 
1184       if ($subtotal_header) {
 
1185         $discount_subtotal   += $linetotal;
 
1186         $nodiscount_subtotal += $nodiscount_linetotal;
 
1189       if ($form->{"subtotal_$i"} && $subtotal_header && ($subtotal_header != $i)) {
 
1190         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} },         $form->format_amount($myconfig, $discount_subtotal,   2);
 
1191         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub_nofmt} },   $discount_subtotal;
 
1192         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} },       $form->format_amount($myconfig, $nodiscount_subtotal, 2);
 
1193         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub_nofmt} }, $nodiscount_subtotal;
 
1195         $discount_subtotal   = 0;
 
1196         $nodiscount_subtotal = 0;
 
1197         $subtotal_header     = 0;
 
1200         push @{ $form->{TEMPLATE_ARRAYS}->{$_} }, "" for qw(discount_sub nodiscount_sub discount_sub_nofmt nodiscount_sub_nofmt);
 
1203       if (!$form->{"discount_$i"}) {
 
1204         $nodiscount += $linetotal;
 
1207       push @{ $form->{TEMPLATE_ARRAYS}->{linetotal} },                  $form->format_amount($myconfig, $linetotal, 2);
 
1208       push @{ $form->{TEMPLATE_ARRAYS}->{linetotal_nofmt} },            $linetotal_exact;
 
1209       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} },       $form->format_amount($myconfig, $nodiscount_linetotal, 2);
 
1210       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal_nofmt} }, $nodiscount_linetotal;
 
1211       push(@{ $form->{TEMPLATE_ARRAYS}->{projectnumber} },              $projectnumbers{$form->{"project_id_$i"}});
 
1212       push(@{ $form->{TEMPLATE_ARRAYS}->{projectdescription} },         $projectdescriptions{$form->{"project_id_$i"}});
 
1214       my $lineweight = $form->{"qty_$i"} * $form->{"weight_$i"};
 
1215       $totalweight += $lineweight;
 
1216       push @{ $form->{TEMPLATE_ARRAYS}->{weight} },            $form->format_amount($myconfig, $form->{"weight_$i"}, 3);
 
1217       push @{ $form->{TEMPLATE_ARRAYS}->{weight_nofmt} },      $form->{"weight_$i"};
 
1218       push @{ $form->{TEMPLATE_ARRAYS}->{lineweight} },        $form->format_amount($myconfig, $lineweight, 3);
 
1219       push @{ $form->{TEMPLATE_ARRAYS}->{lineweight_nofmt} },  $lineweight;
 
1221       my ($taxamount, $taxbase);
 
1224       map { $taxrate += $form->{"${_}_rate"} } split(/ /, $form->{"taxaccounts_$i"});
 
1226       if ($form->{taxincluded}) {
 
1229         $taxamount = $linetotal * $taxrate / (1 + $taxrate);
 
1230         $taxbase = $linetotal / (1 + $taxrate);
 
1232         $taxamount = $linetotal * $taxrate;
 
1233         $taxbase   = $linetotal;
 
1236       if ($taxamount != 0) {
 
1237         foreach my $accno (split / /, $form->{"taxaccounts_$i"}) {
 
1238           $taxaccounts{$accno} += $taxamount * $form->{"${accno}_rate"} / $taxrate;
 
1239           $taxbase{$accno}     += $taxbase;
 
1243       $tax_rate = $taxrate * 100;
 
1244       push(@{ $form->{TEMPLATE_ARRAYS}->{tax_rate} }, qq|$tax_rate|);
 
1246       if ($form->{"assembly_$i"}) {
 
1249         # get parts and push them onto the stack
 
1251         if ($form->{groupitems}) {
 
1252           $sortorder = qq|ORDER BY pg.partsgroup, a.oid|;
 
1254           $sortorder = qq|ORDER BY a.oid|;
 
1257         $query = qq|SELECT p.partnumber, p.description, p.unit, a.qty, | .
 
1258                  qq|pg.partsgroup | .
 
1259                  qq|FROM assembly a | .
 
1260                  qq|  JOIN parts p ON (a.parts_id = p.id) | .
 
1261                  qq|    LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
 
1262                  qq|    WHERE a.bom = '1' | .
 
1263                  qq|    AND a.id = ? | . $sortorder;
 
1264         @values = ($form->{"id_$i"});
 
1265         $sth = $dbh->prepare($query);
 
1266         $sth->execute(@values) || $form->dberror($query);
 
1268         while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
 
1269           if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
 
1270             map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
1271             $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
 
1272             push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $sameitem);
 
1275           push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}) . qq|, $ref->{partnumber}, $ref->{description}|);
 
1276           map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
1281       push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} },
 
1282         CVar->format_to_template(CVar->parse($form->{"ic_cvar_$_->{name}_$i"}, $_), $_)
 
1283           for @{ $ic_cvar_configs };
 
1287   $form->{totalweight}       = $form->format_amount($myconfig, $totalweight, 3);
 
1288   $form->{totalweight_nofmt} = $totalweight;
 
1289   my $defaults = AM->get_defaults();
 
1290   $form->{weightunit}        = $defaults->{weightunit};
 
1293   foreach $item (sort keys %taxaccounts) {
 
1294     $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
 
1296     push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase} },        $form->format_amount($myconfig, $taxbase{$item}, 2));
 
1297     push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase_nofmt} },  $taxbase{$item});
 
1298     push(@{ $form->{TEMPLATE_ARRAYS}->{tax} },            $form->format_amount($myconfig, $taxamount,      2));
 
1299     push(@{ $form->{TEMPLATE_ARRAYS}->{tax_nofmt} },      $taxamount);
 
1300     push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate} },        $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
 
1301     push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate_nofmt} },  $form->{"${item}_rate"} * 100);
 
1302     push(@{ $form->{TEMPLATE_ARRAYS}->{taxnumber} },      $form->{"${item}_taxnumber"});
 
1304     my $tax_obj     = SL::DB::Manager::Tax->find_by(taxnumber => $form->{"${item}_taxnumber"});
 
1305     my $description = $tax_obj->translated_attribute('taxdescription',  $form->{language_id}, 0) if $tax_obj;
 
1306     push(@{ $form->{TEMPLATE_ARRAYS}->{taxdescription} }, $description . q{ } . 100 * $form->{"${item}_rate"} . q{%});
 
1309   $form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
 
1310   $form->{discount_total}      = $form->format_amount($myconfig, $form->{discount_total}, 2);
 
1311   $form->{nodiscount}          = $form->format_amount($myconfig, $nodiscount, 2);
 
1312   $form->{yesdiscount}         = $form->format_amount($myconfig, $form->{nodiscount_total} - $nodiscount, 2);
 
1314   if($form->{taxincluded}) {
 
1315     $form->{subtotal}       = $form->format_amount($myconfig, $form->{ordtotal} - $tax, 2);
 
1316     $form->{subtotal_nofmt} = $form->{ordtotal} - $tax;
 
1318     $form->{subtotal}       = $form->format_amount($myconfig, $form->{ordtotal}, 2);
 
1319     $form->{subtotal_nofmt} = $form->{ordtotal};
 
1322   $form->{ordtotal} = ($form->{taxincluded}) ? $form->{ordtotal} : $form->{ordtotal} + $tax;
 
1325   $form->{quototal} = $form->{ordtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
 
1327   if ($form->{type} =~ /_quotation/) {
 
1328     $form->set_payment_options($myconfig, $form->{quodate});
 
1330     $form->set_payment_options($myconfig, $form->{orddate});
 
1333   $form->{username} = $myconfig->{name};
 
1337   $main::lxdebug->leave_sub();
 
1340 sub project_description {
 
1341   $main::lxdebug->enter_sub();
 
1343   my ($self, $dbh, $id) = @_;
 
1345   my $query = qq|SELECT description FROM project WHERE id = ?|;
 
1346   my ($value) = selectrow_query($main::form, $dbh, $query, $id);
 
1348   $main::lxdebug->leave_sub();
 
1359 OE.pm - Order entry module
 
1363 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>.
 
1369 =item retrieve_simple PARAMS
 
1371 simple OE retrieval by id. does not look up customer, vendor, units or any other stuff. only oe and orderitems.
 
1373   my $order = retrieve_simple(id => 2);