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);