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;
52 $main::lxdebug->enter_sub();
54 my ($self, $myconfig, $form) = @_;
57 my $dbh = $form->get_standard_dbh;
60 my $ordnumber = 'ordnumber';
66 my ($periodic_invoices_columns, $periodic_invoices_joins);
68 my $rate = ($form->{vc} eq 'customer') ? 'buy' : 'sell';
70 if ($form->{type} =~ /_quotation$/) {
72 $ordnumber = 'quonumber';
74 } elsif ($form->{type} eq 'sales_order') {
75 $periodic_invoices_columns = qq| , COALESCE(pcfg.active, 'f') AS periodic_invoices |;
76 $periodic_invoices_joins = qq| LEFT JOIN periodic_invoices_configs pcfg ON (o.id = pcfg.oe_id) |;
79 my $vc = $form->{vc} eq "customer" ? "customer" : "vendor";
82 qq|SELECT o.id, o.ordnumber, o.transdate, o.reqdate, | .
83 qq| o.amount, ct.${vc}number, ct.name, o.netamount, o.${vc}_id, o.globalproject_id, | .
84 qq| o.closed, o.delivered, o.quonumber, o.shippingpoint, o.shipvia, | .
85 qq| o.transaction_description, | .
86 qq| o.marge_total, o.marge_percent, | .
87 qq| ex.$rate AS exchangerate, | .
88 qq| pr.projectnumber AS globalprojectnumber, | .
89 qq| e.name AS employee, s.name AS salesman, | .
90 qq| ct.${vc}number AS vcnumber, ct.country, ct.ustid | .
91 $periodic_invoices_columns .
93 qq|JOIN $vc ct ON (o.${vc}_id = ct.id) | .
94 qq|LEFT JOIN employee e ON (o.employee_id = e.id) | .
95 qq|LEFT JOIN employee s ON (o.salesman_id = s.id) | .
96 qq|LEFT JOIN exchangerate ex ON (ex.currency_id = o.currency_id | .
97 qq| AND ex.transdate = o.transdate) | .
98 qq|LEFT JOIN project pr ON (o.globalproject_id = pr.id) | .
99 qq|$periodic_invoices_joins | .
100 qq|WHERE (o.quotation = ?) |;
101 push(@values, $quotation);
103 my ($null, $split_department_id) = split /--/, $form->{department};
104 my $department_id = $form->{department_id} || $split_department_id;
105 if ($department_id) {
106 $query .= qq| AND o.department_id = ?|;
107 push(@values, $department_id);
110 if ($form->{"project_id"}) {
112 qq|AND ((globalproject_id = ?) OR EXISTS | .
113 qq| (SELECT * FROM orderitems oi | .
114 qq| WHERE oi.project_id = ? AND oi.trans_id = o.id))|;
115 push(@values, conv_i($form->{"project_id"}), conv_i($form->{"project_id"}));
118 if ($form->{"projectnumber"}) {
120 AND ((pr.projectnumber ILIKE ?) OR EXISTS (
121 SELECT * FROM orderitems oi
122 LEFT JOIN project proi ON proi.id = oi.project_id
123 WHERE proi.projectnumber ILIKE ? AND oi.trans_id = o.id
126 push @values, "%" . $form->{"projectnumber"} . "%", "%" . $form->{"projectnumber"} . "%" ;
129 if ($form->{"${vc}_id"}) {
130 $query .= " AND o.${vc}_id = ?";
131 push(@values, $form->{"${vc}_id"});
133 } elsif ($form->{$vc}) {
134 $query .= " AND ct.name ILIKE ?";
135 push(@values, '%' . $form->{$vc} . '%');
138 if (!$main::auth->assert('sales_all_edit', 1)) {
139 $query .= " AND o.employee_id = (select id from employee where login= ?)";
140 push @values, $form->{login};
142 if ($form->{employee_id}) {
143 $query .= " AND o.employee_id = ?";
144 push @values, conv_i($form->{employee_id});
147 if ($form->{salesman_id}) {
148 $query .= " AND o.salesman_id = ?";
149 push @values, conv_i($form->{salesman_id});
152 if (!$form->{open} && !$form->{closed}) {
153 $query .= " AND o.id = 0";
154 } elsif (!($form->{open} && $form->{closed})) {
155 $query .= ($form->{open}) ? " AND o.closed = '0'" : " AND o.closed = '1'";
158 if (($form->{"notdelivered"} || $form->{"delivered"}) &&
159 ($form->{"notdelivered"} ne $form->{"delivered"})) {
160 $query .= $form->{"delivered"} ?
161 " AND o.delivered " : " AND NOT o.delivered";
164 if ($form->{$ordnumber}) {
165 $query .= qq| AND o.$ordnumber ILIKE ?|;
166 push(@values, '%' . $form->{$ordnumber} . '%');
169 if($form->{transdatefrom}) {
170 $query .= qq| AND o.transdate >= ?|;
171 push(@values, conv_date($form->{transdatefrom}));
174 if($form->{transdateto}) {
175 $query .= qq| AND o.transdate <= ?|;
176 push(@values, conv_date($form->{transdateto}));
179 if($form->{reqdatefrom}) {
180 $query .= qq| AND o.reqdate >= ?|;
181 push(@values, conv_date($form->{reqdatefrom}));
184 if($form->{reqdateto}) {
185 $query .= qq| AND o.reqdate <= ?|;
186 push(@values, conv_date($form->{reqdateto}));
189 if ($form->{transaction_description}) {
190 $query .= qq| AND o.transaction_description ILIKE ?|;
191 push(@values, '%' . $form->{transaction_description} . '%');
194 if ($form->{periodic_invoices_active} ne $form->{periodic_invoices_inactive}) {
195 my $not = $form->{periodic_invoices_inactive} ? 'NOT' : '';
196 $query .= qq| AND ${not} COALESCE(pcfg.active, 'f')|;
199 my $sortdir = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
200 my $sortorder = join(', ', map { "${_} ${sortdir} " } ("o.id", $form->sort_columns("transdate", $ordnumber, "name")));
201 my %allowed_sort_columns = (
202 "transdate" => "o.transdate",
203 "reqdate" => "o.reqdate",
205 "ordnumber" => "o.ordnumber",
206 "quonumber" => "o.quonumber",
208 "employee" => "e.name",
209 "salesman" => "s.name",
210 "shipvia" => "o.shipvia",
211 "transaction_description" => "o.transaction_description"
213 if ($form->{sort} && grep($form->{sort}, keys(%allowed_sort_columns))) {
214 $sortorder = $allowed_sort_columns{$form->{sort}} . " ${sortdir}";
216 $query .= qq| ORDER by | . $sortorder;
218 my $sth = $dbh->prepare($query);
219 $sth->execute(@values) ||
220 $form->dberror($query . " (" . join(", ", @values) . ")");
224 while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
225 $ref->{exchangerate} = 1 unless $ref->{exchangerate};
226 push @{ $form->{OE} }, $ref if $ref->{id} != $id{ $ref->{id} };
227 $id{ $ref->{id} } = $ref->{id};
232 $main::lxdebug->leave_sub();
235 sub transactions_for_todo_list {
236 $main::lxdebug->enter_sub();
241 my $myconfig = \%main::myconfig;
242 my $form = $main::form;
244 my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
246 my $query = qq|SELECT id FROM employee WHERE login = ?|;
247 my ($e_id) = selectrow_query($form, $dbh, $query, $form->{login});
250 qq|SELECT oe.id, oe.transdate, oe.reqdate, oe.quonumber, oe.transaction_description, oe.amount,
251 CASE WHEN (COALESCE(oe.customer_id, 0) = 0) THEN 'vendor' ELSE 'customer' END AS vc,
256 LEFT JOIN customer c ON (oe.customer_id = c.id)
257 LEFT JOIN vendor v ON (oe.vendor_id = v.id)
258 LEFT JOIN employee e ON (oe.employee_id = e.id)
259 WHERE (COALESCE(quotation, FALSE) = TRUE)
260 AND (COALESCE(closed, FALSE) = FALSE)
261 AND ((oe.employee_id = ?) OR (oe.salesman_id = ?))
262 AND NOT (oe.reqdate ISNULL)
263 AND (oe.reqdate < current_date)
266 my $quotations = selectall_hashref_query($form, $dbh, $query, $e_id, $e_id);
268 $main::lxdebug->leave_sub();
274 $main::lxdebug->enter_sub();
276 my ($self, $myconfig, $form) = @_;
278 # connect to database, turn off autocommit
279 my $dbh = $form->get_standard_dbh;
281 my ($query, @values, $sth, $null);
282 my $exchangerate = 0;
284 my $all_units = AM->retrieve_units($myconfig, $form);
285 $form->{all_units} = $all_units;
287 my $ic_cvar_configs = CVar->get_configs(module => 'IC',
290 $form->{employee_id} = (split /--/, $form->{employee})[1] if !$form->{employee_id};
291 unless ($form->{employee_id}) {
292 $form->get_employee($dbh);
295 my $ml = ($form->{type} eq 'sales_order') ? 1 : -1;
298 $query = qq|DELETE FROM custom_variables
299 WHERE (config_id IN (SELECT id FROM custom_variable_configs WHERE module = 'IC'))
300 AND (sub_module = 'orderitems')
301 AND (trans_id IN (SELECT id FROM orderitems WHERE trans_id = ?))|;
302 do_query($form, $dbh, $query, $form->{id});
304 $query = qq|DELETE FROM orderitems WHERE trans_id = ?|;
305 do_query($form, $dbh, $query, $form->{id});
307 $query = qq|DELETE FROM shipto | .
308 qq|WHERE trans_id = ? AND module = 'OE'|;
309 do_query($form, $dbh, $query, $form->{id});
313 $query = qq|SELECT nextval('id')|;
314 ($form->{id}) = selectrow_query($form, $dbh, $query);
316 $query = qq|INSERT INTO oe (id, ordnumber, employee_id, currency_id) VALUES (?, '', ?, (SELECT currency_id FROM defaults))|;
317 do_query($form, $dbh, $query, $form->{id}, $form->{employee_id});
335 $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
336 my %price_factors = map { $_->{id} => $_->{factor} } @{ $form->{ALL_PRICE_FACTORS} };
339 for my $i (1 .. $form->{rowcount}) {
341 map({ $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"}) } qw(qty ship));
343 if ($form->{"id_$i"}) {
346 $query = qq|SELECT unit FROM parts WHERE id = ?|;
347 my ($item_unit) = selectrow_query($form, $dbh, $query, $form->{"id_$i"});
350 if (defined($all_units->{$item_unit}->{factor}) &&
351 (($all_units->{$item_unit}->{factor} * 1) != 0)) {
352 $basefactor = $all_units->{$form->{"unit_$i"}}->{factor} / $all_units->{$item_unit}->{factor};
354 my $baseqty = $form->{"qty_$i"} * $basefactor;
356 $form->{"marge_percent_$i"} = $form->parse_amount($myconfig, $form->{"marge_percent_$i"}) * 1;
357 $form->{"marge_absolut_$i"} = $form->parse_amount($myconfig, $form->{"marge_absolut_$i"}) * 1;
359 $form->{"lastcost_$i"} = $form->parse_amount($myconfig, $form->{"lastcost_$i"});
361 # set values to 0 if nothing entered
362 $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
364 $form->{"sellprice_$i"} = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
365 $fxsellprice = $form->{"sellprice_$i"};
367 my ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
369 my $decimalplaces = ($dec > 2) ? $dec : 2;
371 $discount = $form->round_amount($form->{"sellprice_$i"} * $form->{"discount_$i"}, $decimalplaces);
372 $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} - $discount, $decimalplaces);
374 $form->{"inventory_accno_$i"} *= 1;
375 $form->{"expense_accno_$i"} *= 1;
377 $price_factor = $price_factors{ $form->{"price_factor_id_$i"} } || 1;
378 $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2);
380 @taxaccounts = split(/ /, $form->{"taxaccounts_$i"});
384 map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;
386 if ($form->{taxincluded}) {
387 $taxamount = $linetotal * $taxrate / (1 + $taxrate);
388 $taxbase = $linetotal - $taxamount;
390 # we are not keeping a natural price, do not round
391 $form->{"sellprice_$i"} =
392 $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
394 $taxamount = $linetotal * $taxrate;
395 $taxbase = $linetotal;
398 if ($form->round_amount($taxrate, 7) == 0) {
399 if ($form->{taxincluded}) {
400 foreach my $item (@taxaccounts) {
401 $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2);
402 $taxaccounts{$item} += $taxamount;
403 $taxdiff += $taxamount;
404 $taxbase{$item} += $taxbase;
406 $taxaccounts{ $taxaccounts[0] } += $taxdiff;
408 foreach my $item (@taxaccounts) {
409 $taxaccounts{$item} += $linetotal * $form->{"${item}_rate"};
410 $taxbase{$item} += $taxbase;
414 foreach my $item (@taxaccounts) {
415 $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate;
416 $taxbase{$item} += $taxbase;
420 $netamount += $form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor;
422 $reqdate = ($form->{"reqdate_$i"}) ? $form->{"reqdate_$i"} : undef;
424 # Get pricegroup_id and save it. Unfortunately the interface
425 # also uses ID "0" for signalling that none is selected, but "0"
426 # must not be stored in the database. Therefore we cannot simply
428 ($null, my $pricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
430 $pricegroup_id = undef if !$pricegroup_id;
432 # save detail record in orderitems table
433 my $orderitems_id = $form->{"orderitems_id_$i"};
434 ($orderitems_id) = selectfirst_array_query($form, $dbh, qq|SELECT nextval('orderitemsid')|) if (!$orderitems_id);
437 $query = qq|INSERT INTO orderitems (
438 id, trans_id, parts_id, description, longdescription, qty, base_qty,
439 sellprice, discount, unit, reqdate, project_id, serialnumber, ship,
440 pricegroup_id, ordnumber, transdate, cusordnumber, subtotal,
441 marge_percent, marge_total, lastcost, price_factor_id, price_factor, marge_price_factor)
442 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
443 (SELECT factor FROM price_factors WHERE id = ?), ?)|;
445 conv_i($orderitems_id), conv_i($form->{id}), conv_i($form->{"id_$i"}),
446 $form->{"description_$i"}, $form->{"longdescription_$i"},
447 $form->{"qty_$i"}, $baseqty,
448 $fxsellprice, $form->{"discount_$i"},
449 $form->{"unit_$i"}, conv_date($reqdate), conv_i($form->{"project_id_$i"}),
450 $form->{"serialnumber_$i"}, $form->{"ship_$i"}, $pricegroup_id,
451 $form->{"ordnumber_$i"}, conv_date($form->{"transdate_$i"}),
452 $form->{"cusordnumber_$i"}, $form->{"subtotal_$i"} ? 't' : 'f',
453 $form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
454 $form->{"lastcost_$i"},
455 conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
456 conv_i($form->{"marge_price_factor_$i"}));
457 do_query($form, $dbh, $query, @values);
459 $form->{"sellprice_$i"} = $fxsellprice;
460 $form->{"discount_$i"} *= 100;
462 CVar->save_custom_variables(module => 'IC',
463 sub_module => 'orderitems',
464 trans_id => $orderitems_id,
465 configs => $ic_cvar_configs,
467 name_prefix => 'ic_',
468 name_postfix => "_$i",
473 $reqdate = ($form->{reqdate}) ? $form->{reqdate} : undef;
477 map { $tax += $form->round_amount($taxaccounts{$_}, 2) } keys %taxaccounts;
479 $amount = $form->round_amount($netamount + $tax, 2);
480 $netamount = $form->round_amount($netamount, 2);
482 if ($form->{currency} eq $form->{defaultcurrency}) {
483 $form->{exchangerate} = 1;
485 $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? 'buy' : 'sell');
488 $form->{exchangerate} = $exchangerate || $form->parse_amount($myconfig, $form->{exchangerate});
490 my $quotation = $form->{type} =~ /_order$/ ? 'f' : 't';
492 ($null, $form->{department_id}) = split(/--/, $form->{department}) if $form->{department};
497 ordnumber = ?, quonumber = ?, cusordnumber = ?, transdate = ?, vendor_id = ?,
498 customer_id = ?, amount = ?, netamount = ?, reqdate = ?, taxincluded = ?,
499 shippingpoint = ?, shipvia = ?, notes = ?, intnotes = ?, currency_id = (SELECT id FROM currencies WHERE name=?), closed = ?,
500 delivered = ?, proforma = ?, quotation = ?, department_id = ?, language_id = ?,
501 taxzone_id = ?, shipto_id = ?, payment_id = ?, delivery_vendor_id = ?, delivery_customer_id = ?,
502 globalproject_id = ?, employee_id = ?, salesman_id = ?, cp_id = ?, transaction_description = ?, marge_total = ?, marge_percent = ?
505 @values = ($form->{ordnumber} || '', $form->{quonumber},
506 $form->{cusordnumber}, conv_date($form->{transdate}),
507 conv_i($form->{vendor_id}), conv_i($form->{customer_id}),
508 $amount, $netamount, conv_date($reqdate),
509 $form->{taxincluded} ? 't' : 'f', $form->{shippingpoint},
510 $form->{shipvia}, $form->{notes}, $form->{intnotes},
511 $form->{currency}, $form->{closed} ? 't' : 'f',
512 $form->{delivered} ? "t" : "f", $form->{proforma} ? 't' : 'f',
513 $quotation, conv_i($form->{department_id}),
514 conv_i($form->{language_id}), conv_i($form->{taxzone_id}),
515 conv_i($form->{shipto_id}), conv_i($form->{payment_id}),
516 conv_i($form->{delivery_vendor_id}),
517 conv_i($form->{delivery_customer_id}),
518 conv_i($form->{globalproject_id}), conv_i($form->{employee_id}),
519 conv_i($form->{salesman_id}), conv_i($form->{cp_id}),
520 $form->{transaction_description},
521 $form->{marge_total} * 1, $form->{marge_percent} * 1,
522 conv_i($form->{id}));
523 do_query($form, $dbh, $query, @values);
525 $form->{ordtotal} = $amount;
528 $form->{name} = $form->{ $form->{vc} };
529 $form->{name} =~ s/--\Q$form->{"$form->{vc}_id"}\E//;
531 if (!$form->{shipto_id}) {
532 $form->add_shipto($dbh, $form->{id}, "OE");
535 # save printed, emailed, queued
536 $form->save_status($dbh);
538 # Link this record to the records it was created from.
539 $form->{convert_from_oe_ids} =~ s/^\s+//;
540 $form->{convert_from_oe_ids} =~ s/\s+$//;
541 my @convert_from_oe_ids = split m/\s+/, $form->{convert_from_oe_ids};
542 delete $form->{convert_from_oe_ids};
544 if (scalar @convert_from_oe_ids) {
545 RecordLinks->create_links('dbh' => $dbh,
547 'from_table' => 'oe',
548 'from_ids' => \@convert_from_oe_ids,
550 'to_id' => $form->{id},
553 $self->_close_quotations_rfqs('dbh' => $dbh,
554 'from_id' => \@convert_from_oe_ids,
555 'to_id' => $form->{id});
558 if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
559 if ($form->{vc} eq 'customer') {
560 $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, $form->{exchangerate}, 0);
562 if ($form->{vc} eq 'vendor') {
563 $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, 0, $form->{exchangerate});
567 $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ?
568 "quonumber" : "ordnumber"};
570 Common::webdav_folder($form);
572 my $rc = $dbh->commit;
574 $self->save_periodic_invoices_config(dbh => $dbh,
575 oe_id => $form->{id},
576 config_yaml => $form->{periodic_invoices_config})
577 if ($form->{type} eq 'sales_order');
579 $main::lxdebug->leave_sub();
584 sub save_periodic_invoices_config {
585 my ($self, %params) = @_;
587 return if !$params{oe_id};
589 my $config = $params{config_yaml} ? YAML::Load($params{config_yaml}) : undef;
590 return if 'HASH' ne ref $config;
592 my $obj = SL::DB::Manager::PeriodicInvoicesConfig->find_by(oe_id => $params{oe_id})
593 || SL::DB::PeriodicInvoicesConfig->new(oe_id => $params{oe_id});
594 $obj->update_attributes(%{ $config });
597 sub load_periodic_invoice_config {
601 delete $form->{periodic_invoices_config};
604 my $config_obj = SL::DB::Manager::PeriodicInvoicesConfig->find_by(oe_id => $form->{id});
607 my $config = { map { $_ => $config_obj->$_ } qw(active terminated periodicity start_date_as_date end_date_as_date extend_automatically_by ar_chart_id
608 print printer_id copies) };
609 $form->{periodic_invoices_config} = YAML::Dump($config);
614 sub _close_quotations_rfqs {
615 $main::lxdebug->enter_sub();
620 Common::check_params(\%params, qw(from_id to_id));
622 my $myconfig = \%main::myconfig;
623 my $form = $main::form;
625 my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
627 my $query = qq|SELECT quotation FROM oe WHERE id = ?|;
628 my $sth = prepare_query($form, $dbh, $query);
630 do_statement($form, $sth, $query, conv_i($params{to_id}));
632 my ($quotation) = $sth->fetchrow_array();
635 $main::lxdebug->leave_sub();
641 foreach my $from_id (@{ $params{from_id} }) {
642 $from_id = conv_i($from_id);
643 do_statement($form, $sth, $query, $from_id);
644 ($quotation) = $sth->fetchrow_array();
645 push @close_ids, $from_id if ($quotation);
650 if (scalar @close_ids) {
651 $query = qq|UPDATE oe SET closed = TRUE WHERE id IN (| . join(', ', ('?') x scalar @close_ids) . qq|)|;
652 do_query($form, $dbh, $query, @close_ids);
654 $dbh->commit() unless ($params{dbh});
657 $main::lxdebug->leave_sub();
661 $main::lxdebug->enter_sub();
663 my ($self, $myconfig, $form) = @_;
665 my $rc = SL::DB::Order->new->db->with_transaction(sub {
666 my @spoolfiles = grep { $_ } map { $_->spoolfile } @{ SL::DB::Manager::Status->get_all(where => [ trans_id => $form->{id} ]) };
668 SL::DB::Order->new(id => $form->{id})->delete;
670 my $spool = $::lx_office_conf{paths}->{spool};
671 unlink map { "$spool/$_" } @spoolfiles if $spool;
676 $main::lxdebug->leave_sub();
682 $main::lxdebug->enter_sub();
684 my ($self, $myconfig, $form) = @_;
686 # connect to database
687 my $dbh = $form->get_standard_dbh;
689 my ($query, $query_add, @values, @ids, $sth);
691 # translate the ids (given by id_# and trans_id_#) into one array of ids, so we can join them later
693 push @ids, $form->{"trans_id_$_"}
694 if ($form->{"multi_id_$_"} and $form->{"trans_id_$_"})
695 } (1 .. $form->{"rowcount"});
697 if ($form->{rowcount} && scalar @ids) {
698 $form->{convert_from_oe_ids} = join ' ', @ids;
701 # if called in multi id mode, and still only got one id, switch back to single id
702 if ($form->{"rowcount"} and $#ids == 0) {
703 $form->{"id"} = $ids[0];
707 # and remember for the rest of the function
708 my $is_collective_order = scalar @ids;
711 my $wday = (localtime(time))[6];
712 my $next_workday = $wday == 5 ? 3 : $wday == 6 ? 2 : 1;
713 $query_add = qq|, current_date AS transdate, date(current_date + interval '${next_workday} days') AS reqdate|;
716 # get default accounts
717 $query = qq|SELECT (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
718 (SELECT c.accno FROM chart c WHERE d.income_accno_id = c.id) AS income_accno,
719 (SELECT c.accno FROM chart c WHERE d.expense_accno_id = c.id) AS expense_accno,
720 (SELECT c.accno FROM chart c WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
721 (SELECT c.accno FROM chart c WHERE d.fxloss_accno_id = c.id) AS fxloss_accno
724 my $ref = selectfirst_hashref_query($form, $dbh, $query);
725 map { $form->{$_} = $ref->{$_} } keys %$ref;
727 $form->{currency} = $form->get_default_currency($myconfig);
729 # set reqdate if this is an invoice->order conversion. If someone knows a better check to ensure
730 # we come from invoices, feel free.
731 $form->{reqdate} = $form->{deliverydate}
732 if ( $form->{deliverydate}
733 and $form->{callback} =~ /action=ar_transactions/);
735 my $vc = $form->{vc} eq "customer" ? "customer" : "vendor";
737 if ($form->{id} or @ids) {
739 # retrieve order for single id
740 # NOTE: this query is intended to fetch all information only ONCE.
741 # so if any of these infos is important (or even different) for any item,
742 # it will be killed out and then has to be fetched from the item scope query further down
744 qq|SELECT o.cp_id, o.ordnumber, o.transdate, o.reqdate,
745 o.taxincluded, o.shippingpoint, o.shipvia, o.notes, o.intnotes,
746 (SELECT cu.name FROM currencies cu WHERE cu.id=o.currency_id) AS currency, e.name AS employee, o.employee_id, o.salesman_id,
747 o.${vc}_id, cv.name AS ${vc}, o.amount AS invtotal,
748 o.closed, o.reqdate, o.quonumber, o.department_id, o.cusordnumber,
749 d.description AS department, o.payment_id, o.language_id, o.taxzone_id,
750 o.delivery_customer_id, o.delivery_vendor_id, o.proforma, o.shipto_id,
751 o.globalproject_id, o.delivered, o.transaction_description
753 JOIN ${vc} cv ON (o.${vc}_id = cv.id)
754 LEFT JOIN employee e ON (o.employee_id = e.id)
755 LEFT JOIN department d ON (o.department_id = d.id) | .
758 : "WHERE o.id IN (" . join(', ', map("? ", @ids)) . ")"
760 @values = $form->{id} ? ($form->{id}) : @ids;
761 $sth = prepare_execute_query($form, $dbh, $query, @values);
763 $ref = $sth->fetchrow_hashref("NAME_lc");
766 map { $form->{$_} = $ref->{$_} } keys %$ref;
768 $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ? "quonumber" : "ordnumber"};
770 # set all entries for multiple ids blank that yield different information
771 while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
772 map { $form->{$_} = '' if ($ref->{$_} ne $form->{$_}) } keys %$ref;
776 # if not given, fill transdate with current_date
777 $form->{transdate} = $form->current_date($myconfig)
778 unless $form->{transdate};
782 if ($form->{delivery_customer_id}) {
783 $query = qq|SELECT name FROM customer WHERE id = ?|;
784 ($form->{delivery_customer_string}) = selectrow_query($form, $dbh, $query, $form->{delivery_customer_id});
787 if ($form->{delivery_vendor_id}) {
788 $query = qq|SELECT name FROM customer WHERE id = ?|;
789 ($form->{delivery_vendor_string}) = selectrow_query($form, $dbh, $query, $form->{delivery_vendor_id});
792 # shipto and pinted/mailed/queued status makes only sense for single id retrieve
794 $query = qq|SELECT s.* FROM shipto s WHERE s.trans_id = ? AND s.module = 'OE'|;
795 $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
797 $ref = $sth->fetchrow_hashref("NAME_lc");
799 map { $form->{$_} = $ref->{$_} } keys %$ref;
802 # get printed, emailed and queued
803 $query = qq|SELECT s.printed, s.emailed, s.spoolfile, s.formname FROM status s WHERE s.trans_id = ?|;
804 $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
806 while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
807 $form->{printed} .= "$ref->{formname} " if $ref->{printed};
808 $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
809 $form->{queued} .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
812 map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
815 my $transdate = $form->{transdate} ? $dbh->quote($form->{transdate}) : "current_date";
817 $form->{taxzone_id} = 0 unless ($form->{taxzone_id});
819 # retrieve individual items
820 # this query looks up all information about the items
821 # stuff different from the whole will not be overwritten, but saved with a suffix.
823 qq|SELECT o.id AS orderitems_id,
824 c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from as inventory_valid,
825 c2.accno AS income_accno, c2.new_chart_id AS income_new_chart, date($transdate) - c2.valid_from as income_valid,
826 c3.accno AS expense_accno, c3.new_chart_id AS expense_new_chart, date($transdate) - c3.valid_from as expense_valid,
827 oe.ordnumber AS ordnumber_oe, oe.transdate AS transdate_oe, oe.cusordnumber AS cusordnumber_oe,
828 p.partnumber, p.assembly, p.listprice, o.description, o.qty,
829 o.sellprice, o.parts_id AS id, o.unit, o.discount, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id,
830 o.reqdate, o.project_id, o.serialnumber, o.ship, o.lastcost,
831 o.ordnumber, o.transdate, o.cusordnumber, o.subtotal, o.longdescription,
832 o.price_factor_id, o.price_factor, o.marge_price_factor,
833 pr.projectnumber, p.formel,
834 pg.partsgroup, o.pricegroup_id, (SELECT pricegroup FROM pricegroup WHERE id=o.pricegroup_id) as pricegroup
836 JOIN parts p ON (o.parts_id = p.id)
837 JOIN oe ON (o.trans_id = oe.id)
838 LEFT JOIN chart c1 ON ((SELECT inventory_accno_id FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c1.id)
839 LEFT JOIN chart c2 ON ((SELECT income_accno_id_$form->{taxzone_id} FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c2.id)
840 LEFT JOIN chart c3 ON ((SELECT expense_accno_id_$form->{taxzone_id} FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c3.id)
841 LEFT JOIN project pr ON (o.project_id = pr.id)
842 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
844 ? qq|WHERE o.trans_id = ?|
845 : qq|WHERE o.trans_id IN (| . join(", ", map("?", @ids)) . qq|)|) .
848 @ids = $form->{id} ? ($form->{id}) : @ids;
849 $sth = prepare_execute_query($form, $dbh, $query, @values);
851 while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
852 # Retrieve custom variables.
853 my $cvars = CVar->get_custom_variables(dbh => $dbh,
855 sub_module => 'orderitems',
856 trans_id => $ref->{orderitems_id},
858 map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
861 if (!$ref->{"part_inventory_accno_id"}) {
862 map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid));
864 delete($ref->{"part_inventory_accno_id"});
866 # in collective order, copy global ordnumber, transdate, cusordnumber into item scope
867 # unless already present there
868 # remove _oe entries afterwards
869 map { $ref->{$_} = $ref->{"${_}_oe"} if ($ref->{$_} eq '') }
870 qw|ordnumber transdate cusordnumber|
872 map { delete $ref->{$_} } qw|ordnumber_oe transdate_oe cusordnumber_oe|;
876 while ($ref->{inventory_new_chart} && ($ref->{inventory_valid} >= 0)) {
878 qq|SELECT accno AS inventory_accno, | .
879 qq| new_chart_id AS inventory_new_chart, | .
880 qq| date($transdate) - valid_from AS inventory_valid | .
881 qq|FROM chart WHERE id = $ref->{inventory_new_chart}|;
882 ($ref->{inventory_accno}, $ref->{inventory_new_chart},
883 $ref->{inventory_valid}) = selectrow_query($form, $dbh, $query);
886 while ($ref->{income_new_chart} && ($ref->{income_valid} >= 0)) {
888 qq|SELECT accno AS income_accno, | .
889 qq| new_chart_id AS income_new_chart, | .
890 qq| date($transdate) - valid_from AS income_valid | .
891 qq|FROM chart WHERE id = $ref->{income_new_chart}|;
892 ($ref->{income_accno}, $ref->{income_new_chart},
893 $ref->{income_valid}) = selectrow_query($form, $dbh, $query);
896 while ($ref->{expense_new_chart} && ($ref->{expense_valid} >= 0)) {
898 qq|SELECT accno AS expense_accno, | .
899 qq| new_chart_id AS expense_new_chart, | .
900 qq| date($transdate) - valid_from AS expense_valid | .
901 qq|FROM chart WHERE id = $ref->{expense_new_chart}|;
902 ($ref->{expense_accno}, $ref->{expense_new_chart},
903 $ref->{expense_valid}) = selectrow_query($form, $dbh, $query);
906 # delete orderitems_id in collective orders, so that they get cloned no matter what
907 delete $ref->{orderitems_id} if (@ids);
909 # get tax rates and description
910 my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
912 qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber | .
913 qq|FROM tax t LEFT JOIN chart c on (c.id = t.chart_id) | .
914 qq|WHERE t.id IN (SELECT tk.tax_id FROM taxkeys tk | .
915 qq| WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?) | .
916 qq| AND startdate <= $transdate ORDER BY startdate DESC LIMIT 1) | .
917 qq|ORDER BY c.accno|;
918 my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
919 $ref->{taxaccounts} = "";
921 while (my $ptr = $stw->fetchrow_hashref("NAME_lc")) {
922 if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
926 $ref->{taxaccounts} .= "$ptr->{accno} ";
927 if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
928 $form->{"$ptr->{accno}_rate"} = $ptr->{rate};
929 $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
930 $form->{"$ptr->{accno}_taxnumber"} = $ptr->{taxnumber};
931 $form->{taxaccounts} .= "$ptr->{accno} ";
936 chop $ref->{taxaccounts};
938 push @{ $form->{form_details} }, $ref;
946 $form->lastname_used($dbh, $myconfig, $form->{vc})
947 unless $form->{"$form->{vc}_id"};
951 $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? "buy" : "sell");
953 Common::webdav_folder($form);
955 $self->load_periodic_invoice_config($form);
957 my $rc = $dbh->commit;
959 $main::lxdebug->leave_sub();
964 sub retrieve_simple {
965 $main::lxdebug->enter_sub();
970 Common::check_params(\%params, qw(id));
972 my $myconfig = \%main::myconfig;
973 my $form = $main::form;
975 my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
977 my $oe_query = qq|SELECT * FROM oe WHERE id = ?|;
978 my $oi_query = qq|SELECT * FROM orderitems WHERE trans_id = ?|;
980 my $order = selectfirst_hashref_query($form, $dbh, $oe_query, conv_i($params{id}));
981 $order->{orderitems} = selectall_hashref_query( $form, $dbh, $oi_query, conv_i($params{id}));
983 $main::lxdebug->leave_sub();
989 $main::lxdebug->enter_sub();
991 my ($self, $myconfig, $form) = @_;
993 # connect to database
994 my $dbh = $form->get_standard_dbh;
1000 my $nodiscount_subtotal = 0;
1001 my $discount_subtotal = 0;
1004 my @partsgroup = ();
1007 my $subtotal_header = 0;
1008 my $subposition = 0;
1014 my (@project_ids, %projectnumbers, %projectdescriptions);
1016 push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});
1018 $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS',
1019 'departments' => 'ALL_DEPARTMENTS');
1022 foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
1023 $price_factors{$pfac->{id}} = $pfac;
1024 $pfac->{factor} *= 1;
1025 $pfac->{formatted_factor} = $form->format_amount($myconfig, $pfac->{factor});
1029 foreach my $dept (@{ $form->{ALL_DEPARTMENTS} }) {
1030 next unless $dept->{id} eq $form->{department_id};
1031 $form->{department} = $dept->{description};
1035 # sort items by partsgroup
1036 for $i (1 .. $form->{rowcount}) {
1038 if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
1039 $partsgroup = $form->{"partsgroup_$i"};
1041 push @partsgroup, [$i, $partsgroup];
1042 push(@project_ids, $form->{"project_id_$i"}) if ($form->{"project_id_$i"});
1046 $query = "SELECT id, projectnumber, description FROM project WHERE id IN (" .
1047 join(", ", map("?", @project_ids)) . ")";
1048 $sth = prepare_execute_query($form, $dbh, $query, @project_ids);
1049 while (my $ref = $sth->fetchrow_hashref()) {
1050 $projectnumbers{$ref->{id}} = $ref->{projectnumber};
1051 $projectdescriptions{$ref->{id}} = $ref->{description};
1056 $form->{"globalprojectnumber"} = $projectnumbers{$form->{"globalproject_id"}};
1057 $form->{"globalprojectdescription"} = $projectdescriptions{$form->{"globalproject_id"}};
1059 $form->{discount} = [];
1061 $form->{TEMPLATE_ARRAYS} = { };
1062 IC->prepare_parts_for_printing(myconfig => $myconfig, form => $form);
1064 my $ic_cvar_configs = CVar->get_configs(module => 'IC');
1067 qw(runningnumber number description longdescription qty ship unit bin
1068 partnotes serialnumber reqdate sellprice listprice netprice
1069 discount p_discount discount_sub nodiscount_sub
1070 linetotal nodiscount_linetotal tax_rate projectnumber projectdescription
1071 price_factor price_factor_name partsgroup weight lineweight);
1073 push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };
1075 my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);
1077 map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays);
1079 my $totalweight = 0;
1081 foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
1084 if ($item->[1] ne $sameitem) {
1085 push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, qq|$item->[1]|);
1086 $sameitem = $item->[1];
1088 map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
1091 $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
1093 if ($form->{"id_$i"} != 0) {
1095 # add number, description and qty to $form->{number}, ....
1097 if ($form->{"subtotal_$i"} && !$subtotal_header) {
1098 $subtotal_header = $i;
1099 $position = int($position);
1102 } elsif ($subtotal_header) {
1104 $position = int($position);
1105 $position = $position.".".$subposition;
1107 $position = int($position);
1111 my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || { 'factor' => 1 };
1113 push @{ $form->{TEMPLATE_ARRAYS}->{runningnumber} }, $position;
1114 push @{ $form->{TEMPLATE_ARRAYS}->{number} }, $form->{"partnumber_$i"};
1115 push @{ $form->{TEMPLATE_ARRAYS}->{description} }, $form->{"description_$i"};
1116 push @{ $form->{TEMPLATE_ARRAYS}->{longdescription} }, $form->{"longdescription_$i"};
1117 push @{ $form->{TEMPLATE_ARRAYS}->{qty} }, $form->format_amount($myconfig, $form->{"qty_$i"});
1118 push @{ $form->{TEMPLATE_ARRAYS}->{qty_nofmt} }, $form->{"qty_$i"};
1119 push @{ $form->{TEMPLATE_ARRAYS}->{ship} }, $form->format_amount($myconfig, $form->{"ship_$i"});
1120 push @{ $form->{TEMPLATE_ARRAYS}->{ship_nofmt} }, $form->{"ship_$i"};
1121 push @{ $form->{TEMPLATE_ARRAYS}->{unit} }, $form->{"unit_$i"};
1122 push @{ $form->{TEMPLATE_ARRAYS}->{bin} }, $form->{"bin_$i"};
1123 push @{ $form->{TEMPLATE_ARRAYS}->{partnotes} }, $form->{"partnotes_$i"};
1124 push @{ $form->{TEMPLATE_ARRAYS}->{serialnumber} }, $form->{"serialnumber_$i"};
1125 push @{ $form->{TEMPLATE_ARRAYS}->{reqdate} }, $form->{"reqdate_$i"};
1126 push @{ $form->{TEMPLATE_ARRAYS}->{sellprice} }, $form->{"sellprice_$i"};
1127 push @{ $form->{TEMPLATE_ARRAYS}->{sellprice_nofmt} }, $form->parse_amount($myconfig, $form->{"sellprice_$i"});
1128 push @{ $form->{TEMPLATE_ARRAYS}->{listprice} }, $form->{"listprice_$i"};
1129 push @{ $form->{TEMPLATE_ARRAYS}->{price_factor} }, $price_factor->{formatted_factor};
1130 push @{ $form->{TEMPLATE_ARRAYS}->{price_factor_name} }, $price_factor->{description};
1131 push @{ $form->{TEMPLATE_ARRAYS}->{partsgroup} }, $form->{"partsgroup_$i"};
1133 my $sellprice = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
1134 my ($dec) = ($sellprice =~ /\.(\d+)/);
1135 my $decimalplaces = max 2, length($dec);
1137 my $parsed_discount = $form->parse_amount($myconfig, $form->{"discount_$i"});
1139 my $linetotal_exact = $form->{"qty_$i"} * $sellprice * (100 - $parsed_discount) / 100 / $price_factor->{factor};
1140 my $linetotal = $form->round_amount($linetotal_exact, 2);
1142 my $nodiscount_exact_linetotal = $form->{"qty_$i"} * $sellprice / $price_factor->{factor};
1143 my $nodiscount_linetotal = $form->round_amount($nodiscount_exact_linetotal,2);
1145 my $discount = $nodiscount_linetotal - $linetotal; # is always rounded because $nodiscount_linetotal and $linetotal are rounded
1147 my $discount_round_error = $discount + ($linetotal_exact - $nodiscount_exact_linetotal); # not used
1149 $form->{"netprice_$i"} = $form->round_amount($form->{"qty_$i"} ? ($linetotal / $form->{"qty_$i"}) : 0, 2);
1151 push @{ $form->{TEMPLATE_ARRAYS}->{netprice} }, ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : '';
1152 push @{ $form->{TEMPLATE_ARRAYS}->{netprice_nofmt} }, ($form->{"netprice_$i"} != 0) ? $form->{"netprice_$i"} : '';
1154 $linetotal = ($linetotal != 0) ? $linetotal : '';
1156 push @{ $form->{TEMPLATE_ARRAYS}->{discount} }, ($discount != 0) ? $form->format_amount($myconfig, $discount * -1, 2) : '';
1157 push @{ $form->{TEMPLATE_ARRAYS}->{discount_nofmt} }, ($discount != 0) ? $discount * -1 : '';
1158 push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} }, $form->{"discount_$i"};
1160 $form->{ordtotal} += $linetotal;
1161 $form->{nodiscount_total} += $nodiscount_linetotal;
1162 $form->{discount_total} += $discount;
1164 if ($subtotal_header) {
1165 $discount_subtotal += $linetotal;
1166 $nodiscount_subtotal += $nodiscount_linetotal;
1169 if ($form->{"subtotal_$i"} && $subtotal_header && ($subtotal_header != $i)) {
1170 push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} }, $form->format_amount($myconfig, $discount_subtotal, 2);
1171 push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub_nofmt} }, $discount_subtotal;
1172 push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, $form->format_amount($myconfig, $nodiscount_subtotal, 2);
1173 push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub_nofmt} }, $nodiscount_subtotal;
1175 $discount_subtotal = 0;
1176 $nodiscount_subtotal = 0;
1177 $subtotal_header = 0;
1180 push @{ $form->{TEMPLATE_ARRAYS}->{$_} }, "" for qw(discount_sub nodiscount_sub discount_sub_nofmt nodiscount_sub_nofmt);
1183 if (!$form->{"discount_$i"}) {
1184 $nodiscount += $linetotal;
1187 push @{ $form->{TEMPLATE_ARRAYS}->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2);
1188 push @{ $form->{TEMPLATE_ARRAYS}->{linetotal_nofmt} }, $linetotal_exact;
1189 push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} }, $form->format_amount($myconfig, $nodiscount_linetotal, 2);
1190 push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal_nofmt} }, $nodiscount_linetotal;
1191 push(@{ $form->{TEMPLATE_ARRAYS}->{projectnumber} }, $projectnumbers{$form->{"project_id_$i"}});
1192 push(@{ $form->{TEMPLATE_ARRAYS}->{projectdescription} }, $projectdescriptions{$form->{"project_id_$i"}});
1194 my $lineweight = $form->{"qty_$i"} * $form->{"weight_$i"};
1195 $totalweight += $lineweight;
1196 push @{ $form->{TEMPLATE_ARRAYS}->{weight} }, $form->format_amount($myconfig, $form->{"weight_$i"}, 3);
1197 push @{ $form->{TEMPLATE_ARRAYS}->{weight_nofmt} }, $form->{"weight_$i"};
1198 push @{ $form->{TEMPLATE_ARRAYS}->{lineweight} }, $form->format_amount($myconfig, $lineweight, 3);
1199 push @{ $form->{TEMPLATE_ARRAYS}->{lineweight_nofmt} }, $lineweight;
1201 my ($taxamount, $taxbase);
1204 map { $taxrate += $form->{"${_}_rate"} } split(/ /, $form->{"taxaccounts_$i"});
1206 if ($form->{taxincluded}) {
1209 $taxamount = $linetotal * $taxrate / (1 + $taxrate);
1210 $taxbase = $linetotal / (1 + $taxrate);
1212 $taxamount = $linetotal * $taxrate;
1213 $taxbase = $linetotal;
1216 if ($taxamount != 0) {
1217 foreach my $accno (split / /, $form->{"taxaccounts_$i"}) {
1218 $taxaccounts{$accno} += $taxamount * $form->{"${accno}_rate"} / $taxrate;
1219 $taxbase{$accno} += $taxbase;
1223 $tax_rate = $taxrate * 100;
1224 push(@{ $form->{TEMPLATE_ARRAYS}->{tax_rate} }, qq|$tax_rate|);
1226 if ($form->{"assembly_$i"}) {
1229 # get parts and push them onto the stack
1231 if ($form->{groupitems}) {
1232 $sortorder = qq|ORDER BY pg.partsgroup, a.oid|;
1234 $sortorder = qq|ORDER BY a.oid|;
1237 $query = qq|SELECT p.partnumber, p.description, p.unit, a.qty, | .
1238 qq|pg.partsgroup | .
1239 qq|FROM assembly a | .
1240 qq| JOIN parts p ON (a.parts_id = p.id) | .
1241 qq| LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
1242 qq| WHERE a.bom = '1' | .
1243 qq| AND a.id = ? | . $sortorder;
1244 @values = ($form->{"id_$i"});
1245 $sth = $dbh->prepare($query);
1246 $sth->execute(@values) || $form->dberror($query);
1248 while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1249 if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
1250 map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
1251 $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
1252 push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $sameitem);
1255 push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}) . qq|, $ref->{partnumber}, $ref->{description}|);
1256 map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
1261 push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} },
1262 CVar->format_to_template(CVar->parse($form->{"ic_cvar_$_->{name}_$i"}, $_), $_)
1263 for @{ $ic_cvar_configs };
1267 $form->{totalweight} = $form->format_amount($myconfig, $totalweight, 3);
1268 $form->{totalweight_nofmt} = $totalweight;
1269 my $defaults = AM->get_defaults();
1270 $form->{weightunit} = $defaults->{weightunit};
1273 foreach $item (sort keys %taxaccounts) {
1274 $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
1276 push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase} }, $form->format_amount($myconfig, $taxbase{$item}, 2));
1277 push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase_nofmt} }, $taxbase{$item});
1278 push(@{ $form->{TEMPLATE_ARRAYS}->{tax} }, $form->format_amount($myconfig, $taxamount, 2));
1279 push(@{ $form->{TEMPLATE_ARRAYS}->{tax_nofmt} }, $taxamount);
1280 push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate} }, $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
1281 push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate_nofmt} }, $form->{"${item}_rate"} * 100);
1282 push(@{ $form->{TEMPLATE_ARRAYS}->{taxdescription} }, $form->{"${item}_description"} . q{ } . 100 * $form->{"${item}_rate"} . q{%});
1283 push(@{ $form->{TEMPLATE_ARRAYS}->{taxnumber} }, $form->{"${item}_taxnumber"});
1286 $form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
1287 $form->{discount_total} = $form->format_amount($myconfig, $form->{discount_total}, 2);
1288 $form->{nodiscount} = $form->format_amount($myconfig, $nodiscount, 2);
1289 $form->{yesdiscount} = $form->format_amount($myconfig, $form->{nodiscount_total} - $nodiscount, 2);
1291 if($form->{taxincluded}) {
1292 $form->{subtotal} = $form->format_amount($myconfig, $form->{ordtotal} - $tax, 2);
1293 $form->{subtotal_nofmt} = $form->{ordtotal} - $tax;
1295 $form->{subtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
1296 $form->{subtotal_nofmt} = $form->{ordtotal};
1299 $form->{ordtotal} = ($form->{taxincluded}) ? $form->{ordtotal} : $form->{ordtotal} + $tax;
1302 $form->{quototal} = $form->{ordtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
1304 if ($form->{type} =~ /_quotation/) {
1305 $form->set_payment_options($myconfig, $form->{quodate});
1307 $form->set_payment_options($myconfig, $form->{orddate});
1310 $form->{username} = $myconfig->{name};
1314 $main::lxdebug->leave_sub();
1317 sub project_description {
1318 $main::lxdebug->enter_sub();
1320 my ($self, $dbh, $id) = @_;
1322 my $query = qq|SELECT description FROM project WHERE id = ?|;
1323 my ($value) = selectrow_query($main::form, $dbh, $query, $id);
1325 $main::lxdebug->leave_sub();
1336 OE.pm - Order entry module
1340 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>.
1346 =item retrieve_simple PARAMS
1348 simple OE retrieval by id. does not look up customer, vendor, units or any other stuff. only oe and orderitems.
1350 my $order = retrieve_simple(id => 2);