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., 51 Franklin Street, Fifth Floor, Boston,
30 #======================================================================
34 #======================================================================
38 use List::Util qw(max first);
44 use SL::DB::PeriodicInvoicesConfig;
46 use SL::DB::ProjectType;
47 use SL::DB::RequirementSpecOrder;
51 use SL::HTML::Restrict;
54 use SL::Util qw(trim);
62 $main::lxdebug->enter_sub();
64 my ($self, $myconfig, $form) = @_;
67 my $dbh = $form->get_standard_dbh;
70 my $ordnumber = 'ordnumber';
76 my ($periodic_invoices_columns, $periodic_invoices_joins);
78 my $rate = ($form->{vc} eq 'customer') ? 'buy' : 'sell';
80 if ($form->{type} =~ /_quotation$/) {
82 $ordnumber = 'quonumber';
84 } elsif ($form->{type} eq 'sales_order') {
85 $periodic_invoices_columns = qq| , COALESCE(pcfg.active, 'f') AS periodic_invoices |;
86 $periodic_invoices_joins = qq| LEFT JOIN periodic_invoices_configs pcfg ON (o.id = pcfg.oe_id) |;
89 my $vc = $form->{vc} eq "customer" ? "customer" : "vendor";
93 if ($form->{l_remaining_amount} || $form->{l_remaining_netamount}) {
95 SELECT from_id, ar.amount, ar.netamount FROM (
98 WHERE from_table = 'oe' AND to_table = 'ar'
100 SELECT rl1.from_id, rl2.to_id
101 FROM record_links rl1
102 LEFT JOIN record_links rl2 ON (rl1.to_table = rl2.from_table AND rl1.to_id = rl2.from_id)
103 WHERE rl1.from_table = 'oe' AND rl2.to_table = 'ar'
105 SELECT rl1.from_id, rl3.to_id
106 FROM record_links rl1
107 JOIN record_links rl2 ON (rl1.to_table = rl2.from_table AND rl1.to_id = rl2.from_id)
108 JOIN record_links rl3 ON (rl2.to_table = rl3.from_table AND rl2.to_id = rl3.from_id)
109 WHERE rl1.from_table = 'oe' AND rl2.to_table = 'ar' AND rl3.to_table = 'ar'
111 LEFT JOIN ar ON ar.id = rl.to_id
113 for my $ref (@{ selectall_hashref_query($form, $dbh, $query) }) {
114 $billed_amount{ $ref->{from_id}} += $ref->{amount};
115 $billed_netamount{$ref->{from_id}} += $ref->{netamount};
120 qq|SELECT o.id, o.ordnumber, o.transdate, o.reqdate, | .
121 qq| o.amount, ct.${vc}number, ct.name, o.netamount, o.${vc}_id, o.globalproject_id, | .
122 qq| o.closed, o.delivered, o.quonumber, o.cusordnumber, o.shippingpoint, o.shipvia, | .
123 qq| o.transaction_description, | .
124 qq| o.marge_total, o.marge_percent, | .
125 qq| o.exchangerate, | .
126 qq| o.itime::DATE AS insertdate, | .
128 qq| department.description as department, | .
129 qq| ex.$rate AS daily_exchangerate, | .
130 qq| pt.description AS payment_terms, | .
131 qq| pr.projectnumber AS globalprojectnumber, | .
132 qq| e.name AS employee, s.name AS salesman, | .
133 qq| ct.${vc}number AS vcnumber, ct.country, ct.ustid, ct.business_id, | .
134 qq| tz.description AS taxzone | .
135 $periodic_invoices_columns .
136 qq| , o.order_probability, o.expected_billing_date, (o.netamount * o.order_probability / 100) AS expected_netamount | .
138 qq|JOIN $vc ct ON (o.${vc}_id = ct.id) | .
139 qq|LEFT JOIN contacts cp ON (o.cp_id = cp.cp_id) | .
140 qq|LEFT JOIN employee e ON (o.employee_id = e.id) | .
141 qq|LEFT JOIN employee s ON (o.salesman_id = s.id) | .
142 qq|LEFT JOIN exchangerate ex ON (ex.currency_id = o.currency_id | .
143 qq| AND ex.transdate = o.transdate) | .
144 qq|LEFT JOIN project pr ON (o.globalproject_id = pr.id) | .
145 qq|LEFT JOIN payment_terms pt ON (pt.id = o.payment_id)| .
146 qq|LEFT JOIN tax_zones tz ON (o.taxzone_id = tz.id) | .
147 qq|LEFT JOIN department ON (o.department_id = department.id) | .
148 qq|$periodic_invoices_joins | .
149 qq|WHERE (o.quotation = ?) |;
150 push(@values, $quotation);
152 if ($form->{department_id}) {
153 $query .= qq| AND o.department_id = ?|;
154 push(@values, $form->{department_id});
157 if ($form->{"project_id"}) {
159 qq|AND ((globalproject_id = ?) OR EXISTS | .
160 qq| (SELECT * FROM orderitems oi | .
161 qq| WHERE oi.project_id = ? AND oi.trans_id = o.id))|;
162 push(@values, conv_i($form->{"project_id"}), conv_i($form->{"project_id"}));
165 if ($form->{"projectnumber"}) {
167 AND ((pr.projectnumber ILIKE ?) OR EXISTS (
168 SELECT * FROM orderitems oi
169 LEFT JOIN project proi ON proi.id = oi.project_id
170 WHERE proi.projectnumber ILIKE ? AND oi.trans_id = o.id
173 push @values, like($form->{"projectnumber"}), like($form->{"projectnumber"});
176 if ($form->{"business_id"}) {
177 $query .= " AND ct.business_id = ?";
178 push(@values, $form->{"business_id"});
181 if ($form->{"${vc}_id"}) {
182 $query .= " AND o.${vc}_id = ?";
183 push(@values, $form->{"${vc}_id"});
185 } elsif ($form->{$vc}) {
186 $query .= " AND ct.name ILIKE ?";
187 push(@values, like($form->{$vc}));
190 if ($form->{"cp_name"}) {
191 $query .= " AND (cp.cp_name ILIKE ? OR cp.cp_givenname ILIKE ?)";
192 push(@values, (like($form->{"cp_name"}))x2);
195 if ( !( ($vc eq 'customer' && ($main::auth->assert('sales_all_edit', 1) || $main::auth->assert('sales_order_view', 1)))
196 || ($vc eq 'vendor' && ($main::auth->assert('purchase_all_edit', 1) || $main::auth->assert('purchase_order_view', 1))) ) ) {
197 $query .= " AND o.employee_id = (select id from employee where login= ?)";
198 push @values, $::myconfig{login};
200 if ($form->{employee_id}) {
201 $query .= " AND o.employee_id = ?";
202 push @values, conv_i($form->{employee_id});
205 if ($form->{salesman_id}) {
206 $query .= " AND o.salesman_id = ?";
207 push @values, conv_i($form->{salesman_id});
210 if (!$form->{open} && !$form->{closed}) {
211 $query .= " AND o.id = 0";
212 } elsif (!($form->{open} && $form->{closed})) {
213 $query .= ($form->{open}) ? " AND o.closed = '0'" : " AND o.closed = '1'";
216 if (($form->{"notdelivered"} || $form->{"delivered"}) &&
217 ($form->{"notdelivered"} ne $form->{"delivered"})) {
218 $query .= $form->{"delivered"} ?
219 " AND o.delivered " : " AND NOT o.delivered";
222 if ($form->{$ordnumber}) {
223 $query .= qq| AND o.$ordnumber ILIKE ?|;
224 push(@values, like($form->{$ordnumber}));
227 if ($form->{cusordnumber}) {
228 $query .= qq| AND o.cusordnumber ILIKE ?|;
229 push(@values, like($form->{cusordnumber}));
232 if($form->{transdatefrom}) {
233 $query .= qq| AND o.transdate >= ?|;
234 push(@values, conv_date($form->{transdatefrom}));
237 if($form->{transdateto}) {
238 $query .= qq| AND o.transdate <= ?|;
239 push(@values, conv_date($form->{transdateto}));
242 if($form->{reqdatefrom}) {
243 $query .= qq| AND o.reqdate >= ?|;
244 push(@values, conv_date($form->{reqdatefrom}));
247 if($form->{reqdateto}) {
248 $query .= qq| AND o.reqdate <= ?|;
249 push(@values, conv_date($form->{reqdateto}));
252 if($form->{insertdatefrom}) {
253 $query .= qq| AND o.itime::DATE >= ?|;
254 push(@values, conv_date($form->{insertdatefrom}));
257 if($form->{insertdateto}) {
258 $query .= qq| AND o.itime::DATE <= ?|;
259 push(@values, conv_date($form->{insertdateto}));
262 if ($form->{shippingpoint}) {
263 $query .= qq| AND o.shippingpoint ILIKE ?|;
264 push(@values, like($form->{shippingpoint}));
267 if ($form->{taxzone_id} ne '') { # taxzone_id could be 0
268 $query .= qq| AND tz.id = ?|;
269 push(@values, $form->{taxzone_id});
272 if ($form->{transaction_description}) {
273 $query .= qq| AND o.transaction_description ILIKE ?|;
274 push(@values, like($form->{transaction_description}));
277 if ($form->{periodic_invoices_active} ne $form->{periodic_invoices_inactive}) {
278 my $not = $form->{periodic_invoices_inactive} ? 'NOT' : '';
279 $query .= qq| AND ${not} COALESCE(pcfg.active, 'f')|;
282 if ($form->{reqdate_unset_or_old}) {
283 $query .= qq| AND ((o.reqdate IS NULL) OR (o.reqdate < date_trunc('month', current_date)))|;
286 if (($form->{order_probability_value} || '') ne '') {
287 my $op = $form->{order_probability_value} eq 'le' ? '<=' : '>=';
288 $query .= qq| AND (o.order_probability ${op} ?)|;
289 push @values, trim($form->{order_probability_value});
292 if ($form->{expected_billing_date_from}) {
293 $query .= qq| AND (o.expected_billing_date >= ?)|;
294 push @values, conv_date($form->{expected_billing_date_from});
297 if ($form->{expected_billing_date_to}) {
298 $query .= qq| AND (o.expected_billing_date <= ?)|;
299 push @values, conv_date($form->{expected_billing_date_to});
302 if ($form->{intnotes}) {
303 $query .= qq| AND o.intnotes ILIKE ?|;
304 push(@values, like($form->{intnotes}));
307 if ($form->{parts_partnumber}) {
310 SELECT orderitems.trans_id
312 LEFT JOIN parts ON (orderitems.parts_id = parts.id)
313 WHERE (orderitems.trans_id = o.id)
314 AND (parts.partnumber ILIKE ?)
318 push @values, like($form->{parts_partnumber});
321 if ($form->{parts_description}) {
324 SELECT orderitems.trans_id
326 WHERE (orderitems.trans_id = o.id)
327 AND (orderitems.description ILIKE ?)
331 push @values, like($form->{parts_description});
335 my @tokens = parse_line('\s+', 0, $form->{all});
336 # ordnumber quonumber customer.name vendor.name transaction_description
338 o.ordnumber ILIKE ? OR
339 o.quonumber ILIKE ? OR
341 o.transaction_description ILIKE ?
343 push @values, (like($_))x4 for @tokens;
346 my ($cvar_where, @cvar_values) = CVar->build_filter_query('module' => 'CT',
347 'trans_id_field' => 'ct.id',
351 $query .= qq| AND ($cvar_where)|;
352 push @values, @cvar_values;
355 my $sortdir = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
356 my $sortorder = join(', ', map { "${_} ${sortdir} " } ("o.id", $form->sort_columns("transdate", $ordnumber, "name"), "o.itime"));
357 my %allowed_sort_columns = (
358 "transdate" => "o.transdate",
359 "reqdate" => "o.reqdate",
361 "ordnumber" => "o.ordnumber",
362 "cusordnumber" => "o.cusordnumber",
363 "quonumber" => "o.quonumber",
365 "employee" => "e.name",
366 "salesman" => "s.name",
367 "shipvia" => "o.shipvia",
368 "transaction_description" => "o.transaction_description",
369 "shippingpoint" => "o.shippingpoint",
370 "insertdate" => "o.itime",
371 "taxzone" => "tz.description",
372 "payment_terms" => "pt.description",
373 "department" => "department.description",
374 "intnotes" => "o.intnotes",
376 if ($form->{sort} && grep($form->{sort}, keys(%allowed_sort_columns))) {
377 $sortorder = $allowed_sort_columns{$form->{sort}} . " ${sortdir}" . ", o.itime ${sortdir}";
379 $query .= qq| ORDER by | . $sortorder;
381 my $sth = $dbh->prepare($query);
382 $sth->execute(@values) ||
383 $form->dberror($query . " (" . join(", ", @values) . ")");
387 while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
388 $ref->{billed_amount} = $billed_amount{$ref->{id}};
389 $ref->{billed_netamount} = $billed_netamount{$ref->{id}};
390 if ($ref->{billed_amount} < 0) { # case: credit note(s) higher than invoices
391 $ref->{remaining_amount} = $ref->{amount} + $ref->{billed_amount};
392 $ref->{remaining_netamount} = $ref->{netamount} + $ref->{billed_netamount};
394 $ref->{remaining_amount} = $ref->{amount} - $ref->{billed_amount};
395 $ref->{remaining_netamount} = $ref->{netamount} - $ref->{billed_netamount};
397 $ref->{exchangerate} ||= $ref->{daily_exchangerate};
398 $ref->{exchangerate} ||= 1;
399 push @{ $form->{OE} }, $ref if $ref->{id} != $id{ $ref->{id} };
400 $id{ $ref->{id} } = $ref->{id};
405 $main::lxdebug->leave_sub();
408 sub transactions_for_todo_list {
409 $main::lxdebug->enter_sub();
414 my $myconfig = \%main::myconfig;
415 my $form = $main::form;
417 my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
419 my $query = qq|SELECT id FROM employee WHERE login = ?|;
420 my ($e_id) = selectrow_query($form, $dbh, $query, $::myconfig{login});
423 qq|SELECT oe.id, oe.transdate, oe.reqdate, oe.quonumber, oe.transaction_description, oe.amount,
424 CASE WHEN (COALESCE(oe.customer_id, 0) = 0) THEN 'vendor' ELSE 'customer' END AS vc,
429 LEFT JOIN customer c ON (oe.customer_id = c.id)
430 LEFT JOIN vendor v ON (oe.vendor_id = v.id)
431 LEFT JOIN employee e ON (oe.employee_id = e.id)
432 WHERE (COALESCE(quotation, FALSE) = TRUE)
433 AND (COALESCE(closed, FALSE) = FALSE)
434 AND ((oe.employee_id = ?) OR (oe.salesman_id = ?))
435 AND NOT (oe.reqdate ISNULL)
436 AND (oe.reqdate < current_date)
439 my $quotations = selectall_hashref_query($form, $dbh, $query, $e_id, $e_id);
441 $main::lxdebug->leave_sub();
447 my ($self, $myconfig, $form) = @_;
448 $main::lxdebug->enter_sub();
450 my $rc = SL::DB->client->with_transaction(\&_save, $self, $myconfig, $form);
452 $::lxdebug->leave_sub;
458 $main::lxdebug->enter_sub();
460 my ($self, $myconfig, $form) = @_;
462 my $dbh = SL::DB->client->dbh;
463 my $restricter = SL::HTML::Restrict->create;
465 my ($query, @values, $sth, $null);
466 my $exchangerate = 0;
468 my $all_units = AM->retrieve_units($myconfig, $form);
469 $form->{all_units} = $all_units;
471 my $ic_cvar_configs = CVar->get_configs(module => 'IC',
474 $form->{employee_id} = (split /--/, $form->{employee})[1] if !$form->{employee_id};
475 unless ($form->{employee_id}) {
476 $form->get_employee($dbh);
479 my $ml = ($form->{type} eq 'sales_order') ? 1 : -1;
481 my $number_field = $form->{type} =~ m{order} ? 'ordnumber' : 'quonumber';
482 my $trans_number = SL::TransNumber->new(type => $form->{type}, dbh => $dbh, number => $form->{$number_field}, id => $form->{id});
483 $form->{$number_field} ||= $trans_number->create_unique; # set $form->{ordnumber} or $form->{quonumber}
484 my $is_new = !$form->{id};
487 $query = qq|DELETE FROM custom_variables
488 WHERE (config_id IN (SELECT id FROM custom_variable_configs WHERE (module = 'ShipTo')))
489 AND (trans_id IN (SELECT shipto_id FROM shipto WHERE (module = 'OE') AND (trans_id = ?)))|;
490 do_query($form, $dbh, $query, $form->{id});
492 $query = qq|DELETE FROM shipto | .
493 qq|WHERE trans_id = ? AND module = 'OE'|;
494 do_query($form, $dbh, $query, $form->{id});
498 $query = qq|SELECT nextval('id')|;
499 ($form->{id}) = selectrow_query($form, $dbh, $query);
501 $query = qq|INSERT INTO oe (id, ordnumber, employee_id, currency_id, taxzone_id) VALUES (?, '', ?, (SELECT currency_id FROM defaults), ?)|;
502 do_query($form, $dbh, $query, $form->{id}, $form->{employee_id}, $form->{taxzone_id});
519 my @processed_orderitems;
521 $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
522 my %price_factors = map { $_->{id} => $_->{factor} } @{ $form->{ALL_PRICE_FACTORS} };
525 for my $i (1 .. $form->{rowcount}) {
527 map({ $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"}) } qw(qty ship));
529 if ($form->{"id_$i"}) {
532 $query = qq|SELECT unit FROM parts WHERE id = ?|;
533 my ($item_unit) = selectrow_query($form, $dbh, $query, $form->{"id_$i"});
536 if (defined($all_units->{$item_unit}->{factor}) &&
537 (($all_units->{$item_unit}->{factor} * 1) != 0)) {
538 $basefactor = $all_units->{$form->{"unit_$i"}}->{factor} / $all_units->{$item_unit}->{factor};
540 my $baseqty = $form->{"qty_$i"} * $basefactor;
542 $form->{"marge_percent_$i"} = $form->parse_amount($myconfig, $form->{"marge_percent_$i"}) * 1;
543 $form->{"marge_absolut_$i"} = $form->parse_amount($myconfig, $form->{"marge_absolut_$i"}) * 1;
545 $form->{"lastcost_$i"} = $form->parse_amount($myconfig, $form->{"lastcost_$i"});
547 # keep entered selling price
549 $form->parse_amount($myconfig, $form->{"sellprice_$i"});
551 my ($dec) = ($fxsellprice =~ /\.(\d+)/);
553 my $decimalplaces = ($dec > 2) ? $dec : 2;
555 # undo discount formatting
556 $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
559 $form->{"sellprice_$i"} = $fxsellprice * (1 - $form->{"discount_$i"});
561 # round linetotal at least to 2 decimal places
562 $price_factor = $price_factors{ $form->{"price_factor_id_$i"} } || 1;
563 $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2);
565 $form->{"inventory_accno_$i"} *= 1;
566 $form->{"expense_accno_$i"} *= 1;
568 @taxaccounts = split(/ /, $form->{"taxaccounts_$i"});
572 map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;
574 if ($form->{taxincluded}) {
575 $taxamount = $linetotal * $taxrate / (1 + $taxrate);
576 $taxbase = $linetotal - $taxamount;
578 # we are not keeping a natural price, do not round
579 $form->{"sellprice_$i"} =
580 $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
582 $taxamount = $linetotal * $taxrate;
583 $taxbase = $linetotal;
586 if ($form->round_amount($taxrate, 7) == 0) {
587 if ($form->{taxincluded}) {
588 foreach my $item (@taxaccounts) {
589 $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2);
590 $taxaccounts{$item} += $taxamount;
591 $taxdiff += $taxamount;
592 $taxbase{$item} += $taxbase;
594 $taxaccounts{ $taxaccounts[0] } += $taxdiff;
596 foreach my $item (@taxaccounts) {
597 $taxaccounts{$item} += $linetotal * $form->{"${item}_rate"};
598 $taxbase{$item} += $taxbase;
602 foreach my $item (@taxaccounts) {
603 $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate;
604 $taxbase{$item} += $taxbase;
608 $netamount += $form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor;
610 $reqdate = ($form->{"reqdate_$i"}) ? $form->{"reqdate_$i"} : undef;
612 # Get pricegroup_id and save it. Unfortunately the interface
613 # also uses ID "0" for signalling that none is selected, but "0"
614 # must not be stored in the database. Therefore we cannot simply
616 ($null, my $pricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
618 $pricegroup_id = undef if !$pricegroup_id;
620 # force new project, if not set yet
621 if ($::instance_conf->get_order_always_project && !$form->{"globalproject_id"} && ($form->{type} eq 'sales_order')) {
622 require SL::DB::Customer;
623 my $customer = SL::DB::Manager::Customer->find_by(id => $form->{customer_id});
624 die "Can't find customer" unless $customer;
625 die $main::locale->text("Error while creating project with project number of new order number, project number #1 already exists!", $form->{ordnumber})
626 if SL::DB::Manager::Project->find_by(projectnumber => $form->{ordnumber});
628 my $new_project = SL::DB::Project->new(
629 projectnumber => $form->{ordnumber},
630 description => $customer->name,
631 customer_id => $customer->id,
633 project_type_id => $::instance_conf->get_project_type_id,
634 project_status_id => $::instance_conf->get_project_status_id,
637 $form->{"globalproject_id"} = $new_project->id;
640 CVar->get_non_editable_ic_cvars(form => $form,
643 sub_module => 'orderitems',
644 may_converted_from => ['orderitems', 'invoice']);
648 # save detail record in orderitems table
649 if (! $form->{"orderitems_id_$i"}) {
650 $query = qq|SELECT nextval('orderitemsid')|;
651 ($form->{"orderitems_id_$i"}) = selectrow_query($form, $dbh, $query);
653 $query = qq|INSERT INTO orderitems (id, position) VALUES (?, ?)|;
654 do_query($form, $dbh, $query, $form->{"orderitems_id_$i"}, conv_i($position));
657 my $orderitems_id = $form->{"orderitems_id_$i"};
658 push @processed_orderitems, $orderitems_id;
661 UPDATE orderitems SET
662 trans_id = ?, position = ?, parts_id = ?, description = ?, longdescription = ?, qty = ?, base_qty = ?,
663 sellprice = ?, discount = ?, unit = ?, reqdate = ?, project_id = ?, serialnumber = ?, ship = ?,
664 pricegroup_id = ?, subtotal = ?,
665 marge_percent = ?, marge_total = ?, lastcost = ?, price_factor_id = ?,
666 active_price_source = ?, active_discount_source = ?,
667 price_factor = (SELECT factor FROM price_factors WHERE id = ?), marge_price_factor = ?
671 conv_i($form->{id}), conv_i($position), conv_i($form->{"id_$i"}),
672 $form->{"description_$i"}, $restricter->process($form->{"longdescription_$i"}),
673 $form->{"qty_$i"}, $baseqty,
674 $fxsellprice, $form->{"discount_$i"},
675 $form->{"unit_$i"}, conv_date($reqdate), conv_i($form->{"project_id_$i"}),
676 $form->{"serialnumber_$i"}, $form->{"ship_$i"},
677 $pricegroup_id, $form->{"subtotal_$i"} ? 't' : 'f',
678 $form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
679 $form->{"lastcost_$i"}, conv_i($form->{"price_factor_id_$i"}),
680 $form->{"active_price_source_$i"}, $form->{"active_discount_source_$i"},
681 conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"marge_price_factor_$i"}),
682 conv_i($orderitems_id),
685 do_query($form, $dbh, $query, @values);
687 $form->{"sellprice_$i"} = $fxsellprice;
688 $form->{"discount_$i"} *= 100;
690 CVar->save_custom_variables(module => 'IC',
691 sub_module => 'orderitems',
692 trans_id => $orderitems_id,
693 configs => $ic_cvar_configs,
695 name_prefix => 'ic_',
696 name_postfix => "_$i",
699 # link previous items with orderitems
700 # assume we have a new workflow if we link from invoice or order to quotation
701 # unluckily orderitems are used for quotation and orders - therefore one more
702 # check to be sure NOT to link from order to quotation
703 foreach (qw(orderitems)) {
704 if (!$form->{saveasnew} && !$form->{useasnew} && $form->{"converted_from_${_}_id_$i"}
705 && $form->{type} !~ 'quotation') {
706 RecordLinks->create_links('dbh' => $dbh,
709 'from_ids' => $form->{"converted_from_${_}_id_$i"},
710 'to_table' => 'orderitems',
711 'to_id' => $orderitems_id,
714 delete $form->{"converted_from_${_}_id_$i"};
719 # search for orphaned ids
720 $query = sprintf 'SELECT id FROM orderitems WHERE trans_id = ? AND NOT id IN (%s)', join ', ', ("?") x scalar @processed_orderitems;
721 @values = (conv_i($form->{id}), map { conv_i($_) } @processed_orderitems);
722 my @orphaned_ids = map { $_->{id} } selectall_hashref_query($form, $dbh, $query, @values);
724 if (scalar @orphaned_ids) {
725 # clean up orderitems
726 $query = sprintf 'DELETE FROM orderitems WHERE id IN (%s)', join ', ', ("?") x scalar @orphaned_ids;
727 do_query($form, $dbh, $query, @orphaned_ids);
730 $reqdate = ($form->{reqdate}) ? $form->{reqdate} : undef;
734 map { $tax += $form->round_amount($taxaccounts{$_}, 2) } keys %taxaccounts;
736 $amount = $form->round_amount($netamount + $tax, 2, 1);
737 $netamount = $form->round_amount($netamount, 2);
739 if ($form->{currency} eq $form->{defaultcurrency}) {
740 $form->{exchangerate} = 1;
742 $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? 'buy' : 'sell');
745 # from inputfield (exchangerate) or hidden (forex)
746 my $exchangerate_from_form = $form->{forex} || $form->parse_amount($myconfig, $form->{exchangerate});
748 $form->{exchangerate} = $exchangerate || $exchangerate_from_form;
750 my $quotation = $form->{type} =~ /_order$/ ? 'f' : 't';
755 ordnumber = ?, quonumber = ?, cusordnumber = ?, transdate = ?, vendor_id = ?,
756 customer_id = ?, amount = ?, netamount = ?, reqdate = ?, tax_point = ?, taxincluded = ?,
757 shippingpoint = ?, shipvia = ?, notes = ?, intnotes = ?, currency_id = (SELECT id FROM currencies WHERE name=?), closed = ?,
758 delivered = ?, proforma = ?, quotation = ?, department_id = ?, language_id = ?,
759 taxzone_id = ?, shipto_id = ?, billing_address_id = ?, payment_id = ?, delivery_vendor_id = ?, delivery_customer_id = ?,delivery_term_id = ?,
760 globalproject_id = ?, employee_id = ?, salesman_id = ?, cp_id = ?, transaction_description = ?, marge_total = ?, marge_percent = ?
761 , order_probability = ?, expected_billing_date = ?
764 @values = ($form->{ordnumber} || '', $form->{quonumber},
765 $form->{cusordnumber}, conv_date($form->{transdate}),
766 conv_i($form->{vendor_id}), conv_i($form->{customer_id}),
767 $amount, $netamount, conv_date($reqdate), conv_date($form->{tax_point}),
768 $form->{taxincluded} ? 't' : 'f', $form->{shippingpoint},
769 $form->{shipvia}, $restricter->process($form->{notes}), $form->{intnotes},
770 $form->{currency}, $form->{closed} ? 't' : 'f',
771 $form->{delivered} ? "t" : "f", $form->{proforma} ? 't' : 'f',
772 $quotation, conv_i($form->{department_id}),
773 conv_i($form->{language_id}), conv_i($form->{taxzone_id}),
774 conv_i($form->{shipto_id}), conv_i($form->{billing_address_id}), conv_i($form->{payment_id}),
775 conv_i($form->{delivery_vendor_id}),
776 conv_i($form->{delivery_customer_id}),
777 conv_i($form->{delivery_term_id}),
778 conv_i($form->{globalproject_id}), conv_i($form->{employee_id}),
779 conv_i($form->{salesman_id}), conv_i($form->{cp_id}),
780 $form->{transaction_description},
781 $form->{marge_total} * 1, $form->{marge_percent} * 1,
782 $form->{order_probability} * 1, conv_date($form->{expected_billing_date}),
783 conv_i($form->{id}));
784 do_query($form, $dbh, $query, @values);
786 $form->new_lastmtime('oe');
788 $form->{ordtotal} = $amount;
790 $form->{name} = $form->{ $form->{vc} };
791 $form->{name} =~ s/--\Q$form->{"$form->{vc}_id"}\E//;
794 if (!$form->{shipto_id}) {
795 $form->add_shipto($dbh, $form->{id}, "OE");
798 # save printed, emailed, queued
799 $form->save_status($dbh);
801 # Link this record to the records it was created from.
802 $form->{convert_from_oe_ids} =~ s/^\s+//;
803 $form->{convert_from_oe_ids} =~ s/\s+$//;
804 my @convert_from_oe_ids = split m/\s+/, $form->{convert_from_oe_ids};
805 delete $form->{convert_from_oe_ids};
806 if (!$form->{useasnew} && scalar @convert_from_oe_ids) {
807 RecordLinks->create_links('dbh' => $dbh,
809 'from_table' => 'oe',
810 'from_ids' => \@convert_from_oe_ids,
812 'to_id' => $form->{id},
814 $self->_close_quotations_rfqs('dbh' => $dbh,
815 'from_id' => \@convert_from_oe_ids,
816 'to_id' => $form->{id});
819 if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
820 if ($form->{vc} eq 'customer') {
821 $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, $form->{exchangerate}, 0);
823 if ($form->{vc} eq 'vendor') {
824 $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, 0, $form->{exchangerate});
828 $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ?
829 "quonumber" : "ordnumber"};
831 Common::webdav_folder($form);
833 $self->save_periodic_invoices_config(dbh => $dbh,
834 oe_id => $form->{id},
835 config_yaml => $form->{periodic_invoices_config})
836 if ($form->{type} eq 'sales_order');
838 $self->_link_created_sales_order_to_requirement_specs_for_sales_quotations(
839 type => $form->{type},
840 converted_from_ids => \@convert_from_oe_ids,
841 sales_order_id => $form->{id},
845 $self->_set_project_in_linked_requirement_spec(
846 type => $form->{type},
847 project_id => $form->{globalproject_id},
848 sales_order_id => $form->{id},
851 $main::lxdebug->leave_sub();
856 sub _link_created_sales_order_to_requirement_specs_for_sales_quotations {
857 my ($self, %params) = @_;
859 # If this is a sales order created from a sales quotation and if
860 # that sales quotation was created from a requirement spec document
861 # then link the newly created sales order to the requirement spec
864 return if !$params{is_new};
865 return if $params{type} ne 'sales_order';
866 return if !@{ $params{converted_from_ids} };
868 my $oe_objects = SL::DB::Manager::Order->get_all(where => [ id => $params{converted_from_ids} ]);
869 my @sales_quotations = grep { $_->is_type('sales_quotation') } @{ $oe_objects };
871 return if !@sales_quotations;
873 my $rs_orders = SL::DB::Manager::RequirementSpecOrder->get_all(where => [ order_id => [ map { $_->id } @sales_quotations ] ]);
875 return if !@{ $rs_orders };
877 $rs_orders->[0]->db->with_transaction(sub {
878 foreach my $rs_order (@{ $rs_orders }) {
879 SL::DB::RequirementSpecOrder->new(
880 order_id => $params{sales_order_id},
881 requirement_spec_id => $rs_order->requirement_spec_id,
882 version_id => $rs_order->version_id,
890 sub _set_project_in_linked_requirement_spec {
891 my ($self, %params) = @_;
893 return if $params{type} ne 'sales_order';
894 return if !$params{project_id} || !$params{sales_order_id};
897 UPDATE requirement_specs
900 SELECT so.requirement_spec_id
901 FROM requirement_spec_orders so
902 WHERE so.order_id = ?
906 do_query($::form, $::form->get_standard_dbh, $query, $params{project_id}, $params{sales_order_id});
909 sub save_periodic_invoices_config {
910 my ($self, %params) = @_;
912 return if !$params{oe_id};
914 my $config = $params{config_yaml} ? SL::YAML::Load($params{config_yaml}) : undef;
915 return if 'HASH' ne ref $config;
917 my $obj = SL::DB::Manager::PeriodicInvoicesConfig->find_by(oe_id => $params{oe_id})
918 || SL::DB::PeriodicInvoicesConfig->new(oe_id => $params{oe_id});
919 $obj->update_attributes(%{ $config });
922 sub load_periodic_invoice_config {
926 delete $form->{periodic_invoices_config};
929 my $config_obj = SL::DB::Manager::PeriodicInvoicesConfig->find_by(oe_id => $form->{id});
932 my $config = { map { $_ => $config_obj->$_ } qw(active terminated periodicity order_value_periodicity start_date_as_date end_date_as_date first_billing_date_as_date extend_automatically_by ar_chart_id
933 print printer_id copies direct_debit send_email email_recipient_contact_id email_recipient_address email_sender email_subject email_body) };
934 $form->{periodic_invoices_config} = SL::YAML::Dump($config);
939 sub _close_quotations_rfqs {
940 $main::lxdebug->enter_sub();
945 Common::check_params(\%params, qw(from_id to_id));
947 my $myconfig = \%main::myconfig;
948 my $form = $main::form;
950 my $dbh = $params{dbh} || SL::DB->client->dbh;
952 SL::DB->client->with_transaction(sub {
954 my $query = qq|SELECT quotation FROM oe WHERE id = ?|;
955 my $sth = prepare_query($form, $dbh, $query);
957 do_statement($form, $sth, $query, conv_i($params{to_id}));
959 my ($quotation) = $sth->fetchrow_array();
967 foreach my $from_id (@{ $params{from_id} }) {
968 $from_id = conv_i($from_id);
969 do_statement($form, $sth, $query, $from_id);
970 ($quotation) = $sth->fetchrow_array();
971 push @close_ids, $from_id if ($quotation);
976 if (scalar @close_ids) {
977 $query = qq|UPDATE oe SET closed = TRUE WHERE id IN (| . join(', ', ('?') x scalar @close_ids) . qq|)|;
978 do_query($form, $dbh, $query, @close_ids);
981 }) or do { die SL::DB->client->error };
983 $main::lxdebug->leave_sub();
987 $main::lxdebug->enter_sub();
989 my ($self, $myconfig, $form) = @_;
991 my $rc = SL::DB::Order->new->db->with_transaction(sub {
992 my @spoolfiles = grep { $_ } map { $_->spoolfile } @{ SL::DB::Manager::Status->get_all(where => [ trans_id => $form->{id} ]) };
994 SL::DB::Order->new(id => $form->{id})->delete;
996 my $spool = $::lx_office_conf{paths}->{spool};
997 unlink map { "$spool/$_" } @spoolfiles if $spool;
1000 }) or do { die SL::DB->client->error };
1002 $main::lxdebug->leave_sub();
1008 my ($self, $myconfig, $form) = @_;
1009 $main::lxdebug->enter_sub();
1011 my $rc = SL::DB->client->with_transaction(\&_retrieve, $self, $myconfig, $form);
1013 $::lxdebug->leave_sub;
1018 my ($self, $myconfig, $form) = @_;
1020 # connect to database
1021 my $dbh = SL::DB->client->dbh;
1023 my ($query, $query_add, @values, @ids, $sth);
1025 # translate the ids (given by id_# and trans_id_#) into one array of ids, so we can join them later
1027 push @ids, $form->{"trans_id_$_"}
1028 if ($form->{"multi_id_$_"} and $form->{"trans_id_$_"})
1029 } (1 .. $form->{"rowcount"});
1031 if ($form->{rowcount} && scalar @ids) {
1032 $form->{convert_from_oe_ids} = join ' ', @ids;
1035 # if called in multi id mode, and still only got one id, switch back to single id
1036 if ($form->{"rowcount"} and $#ids == 0) {
1037 $form->{"id"} = $ids[0];
1039 delete $form->{convert_from_oe_ids};
1042 # and remember for the rest of the function
1043 my $is_collective_order = scalar @ids;
1045 # If collective order was created from exactly 1 order, we assume the same
1046 # behaviour as a "save as new" from within an order is actually desired, i.e.
1047 # the original order isn't part of a workflow where we want to remember
1048 # record_links, but simply a quick way of generating a new order from an old
1049 # one without having to enter everything again.
1050 # Setting useasnew will prevent the creation of record_links for the items
1051 # when saving the new order.
1052 # This form variable is probably not necessary, could just set saveasnew instead
1053 $form->{useasnew} = 1 if $is_collective_order == 1;
1056 my $extra_days = $form->{type} eq 'sales_quotation' ? $::instance_conf->get_reqdate_interval :
1057 $form->{type} eq 'sales_order' ? $::instance_conf->get_delivery_date_interval : 1;
1058 if ( ($form->{type} eq 'sales_order' && !$::instance_conf->get_deliverydate_on)
1059 || ($form->{type} eq 'sales_quotation' && !$::instance_conf->get_reqdate_on)) {
1060 $form->{reqdate} = '';
1062 $form->{reqdate} = DateTime->today_local->next_workday(extra_days => $extra_days)->to_kivitendo;
1064 $form->{transdate} = DateTime->today_local->to_kivitendo;
1067 # get default accounts
1068 $query = qq|SELECT (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
1069 (SELECT c.accno FROM chart c WHERE d.income_accno_id = c.id) AS income_accno,
1070 (SELECT c.accno FROM chart c WHERE d.expense_accno_id = c.id) AS expense_accno,
1071 (SELECT c.accno FROM chart c WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
1072 (SELECT c.accno FROM chart c WHERE d.fxloss_accno_id = c.id) AS fxloss_accno,
1073 (SELECT c.accno FROM chart c WHERE d.rndgain_accno_id = c.id) AS rndgain_accno,
1074 (SELECT c.accno FROM chart c WHERE d.rndloss_accno_id = c.id) AS rndloss_accno
1077 my $ref = selectfirst_hashref_query($form, $dbh, $query);
1078 map { $form->{$_} = $ref->{$_} } keys %$ref;
1080 $form->{currency} = $form->get_default_currency($myconfig);
1082 # set reqdate if this is an invoice->order conversion. If someone knows a better check to ensure
1083 # we come from invoices, feel free.
1084 $form->{reqdate} = $form->{deliverydate}
1085 if ( $form->{deliverydate}
1086 and $form->{callback} =~ /action=ar_transactions/);
1088 my $vc = $form->{vc} eq "customer" ? "customer" : "vendor";
1090 if ($form->{id} or @ids) {
1092 # retrieve order for single id
1093 # NOTE: this query is intended to fetch all information only ONCE.
1094 # so if any of these infos is important (or even different) for any item,
1095 # it will be killed out and then has to be fetched from the item scope query further down
1097 qq|SELECT o.cp_id, o.ordnumber, o.transdate, o.reqdate,
1098 o.taxincluded, o.shippingpoint, o.shipvia, o.notes, o.intnotes,
1099 (SELECT cu.name FROM currencies cu WHERE cu.id=o.currency_id) AS currency, e.name AS employee, o.employee_id, o.salesman_id,
1100 o.${vc}_id, cv.name AS ${vc}, o.amount AS invtotal,
1101 o.closed, o.reqdate, o.tax_point, o.quonumber, o.department_id, o.cusordnumber,
1103 d.description AS department, o.payment_id, o.language_id, o.taxzone_id,
1104 o.delivery_customer_id, o.delivery_vendor_id, o.proforma, o.shipto_id, o.billing_address_id,
1105 o.globalproject_id, o.delivered, o.transaction_description, o.delivery_term_id,
1106 o.itime::DATE AS insertdate, o.order_probability, o.expected_billing_date
1108 JOIN ${vc} cv ON (o.${vc}_id = cv.id)
1109 LEFT JOIN employee e ON (o.employee_id = e.id)
1110 LEFT JOIN department d ON (o.department_id = d.id) | .
1113 : "WHERE o.id IN (" . join(', ', map("? ", @ids)) . ")"
1115 @values = $form->{id} ? ($form->{id}) : @ids;
1116 $sth = prepare_execute_query($form, $dbh, $query, @values);
1118 $ref = $sth->fetchrow_hashref("NAME_lc");
1121 map { $form->{$_} = $ref->{$_} } keys %$ref;
1123 $form->{saved_xyznumber} = $form->{$form->{type} =~ /_quotation$/ ? "quonumber" : "ordnumber"};
1125 # set all entries for multiple ids blank that yield different information
1126 while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
1127 map { $form->{$_} = '' if ($ref->{$_} ne $form->{$_}) } keys %$ref;
1130 $form->{mtime} ||= $form->{itime};
1131 $form->{lastmtime} = $form->{mtime};
1133 # if not given, fill transdate with current_date
1134 $form->{transdate} = $form->current_date($myconfig)
1135 unless $form->{transdate};
1139 if ($form->{delivery_customer_id}) {
1140 $query = qq|SELECT name FROM customer WHERE id = ?|;
1141 ($form->{delivery_customer_string}) = selectrow_query($form, $dbh, $query, $form->{delivery_customer_id});
1144 if ($form->{delivery_vendor_id}) {
1145 $query = qq|SELECT name FROM customer WHERE id = ?|;
1146 ($form->{delivery_vendor_string}) = selectrow_query($form, $dbh, $query, $form->{delivery_vendor_id});
1149 # shipto and pinted/mailed/queued status makes only sense for single id retrieve
1151 $query = qq|SELECT s.* FROM shipto s WHERE s.trans_id = ? AND s.module = 'OE'|;
1152 $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
1154 $ref = $sth->fetchrow_hashref("NAME_lc");
1155 $form->{$_} = $ref->{$_} for grep { m{^shipto(?!_id$)} } keys %$ref;
1158 if ($ref->{shipto_id}) {
1159 my $cvars = CVar->get_custom_variables(
1162 trans_id => $ref->{shipto_id},
1164 $form->{"shiptocvar_$_->{name}"} = $_->{value} for @{ $cvars };
1167 # get printed, emailed and queued
1168 $query = qq|SELECT s.printed, s.emailed, s.spoolfile, s.formname FROM status s WHERE s.trans_id = ?|;
1169 $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
1171 while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
1172 $form->{printed} .= "$ref->{formname} " if $ref->{printed};
1173 $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
1174 $form->{queued} .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
1177 map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
1180 my $transdate = $form->{tax_point} ? $dbh->quote($form->{tax_point}) : $form->{transdate} ? $dbh->quote($form->{transdate}) : "current_date";
1182 $form->{taxzone_id} = 0 unless ($form->{taxzone_id});
1183 unshift @values, ($form->{taxzone_id}) x 2;
1185 # retrieve individual items
1186 # this query looks up all information about the items
1187 # stuff different from the whole will not be overwritten, but saved with a suffix.
1189 qq|SELECT o.id AS orderitems_id,
1190 c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from as inventory_valid,
1191 c2.accno AS income_accno, c2.new_chart_id AS income_new_chart, date($transdate) - c2.valid_from as income_valid,
1192 c3.accno AS expense_accno, c3.new_chart_id AS expense_new_chart, date($transdate) - c3.valid_from as expense_valid,
1193 oe.ordnumber AS ordnumber_oe, oe.transdate AS transdate_oe, oe.cusordnumber AS cusordnumber_oe,
1194 p.partnumber, p.part_type, p.listprice, o.description, o.qty,
1195 p.classification_id,
1196 o.sellprice, o.parts_id AS id, o.unit, o.discount, p.notes AS partnotes, p.part_type,
1197 o.reqdate, o.project_id, o.serialnumber, o.ship, o.lastcost,
1198 o.ordnumber, o.transdate, o.cusordnumber, o.subtotal, o.longdescription,
1199 o.price_factor_id, o.price_factor, o.marge_price_factor, o.active_price_source, o.active_discount_source,
1200 pr.projectnumber, p.formel,
1201 pg.partsgroup, o.pricegroup_id, (SELECT pricegroup FROM pricegroup WHERE id=o.pricegroup_id) as pricegroup
1203 JOIN parts p ON (o.parts_id = p.id)
1204 JOIN oe ON (o.trans_id = oe.id)
1205 LEFT JOIN chart c1 ON ((SELECT inventory_accno_id FROM buchungsgruppen WHERE id=p.buchungsgruppen_id) = c1.id)
1206 LEFT JOIN chart c2 ON ((SELECT tc.income_accno_id FROM taxzone_charts tc WHERE tc.taxzone_id = ? and tc.buchungsgruppen_id = p.buchungsgruppen_id) = c2.id)
1207 LEFT JOIN chart c3 ON ((SELECT tc.expense_accno_id FROM taxzone_charts tc WHERE tc.taxzone_id = ? and tc.buchungsgruppen_id = p.buchungsgruppen_id) = c3.id)
1208 LEFT JOIN project pr ON (o.project_id = pr.id)
1209 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
1211 ? qq|WHERE o.trans_id = ?|
1212 : qq|WHERE o.trans_id IN (| . join(", ", map("?", @ids)) . qq|)|) .
1213 qq|ORDER BY o.trans_id, o.position|;
1215 @ids = $form->{id} ? ($form->{id}) : @ids;
1216 $sth = prepare_execute_query($form, $dbh, $query, @values);
1218 while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
1219 # Retrieve custom variables.
1220 my $cvars = CVar->get_custom_variables(dbh => $dbh,
1222 sub_module => 'orderitems',
1223 trans_id => $ref->{orderitems_id},
1225 map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
1228 if (!$ref->{"part_type"} eq 'part') {
1229 map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid));
1231 # delete($ref->{"part_inventory_accno_id"});
1233 # in collective order, copy global ordnumber, transdate, cusordnumber into item scope
1234 # unless already present there
1235 # remove _oe entries afterwards
1236 map { $ref->{$_} = $ref->{"${_}_oe"} if ($ref->{$_} eq '') }
1237 qw|ordnumber transdate cusordnumber|
1239 map { delete $ref->{$_} } qw|ordnumber_oe transdate_oe cusordnumber_oe|;
1243 while ($ref->{inventory_new_chart} && ($ref->{inventory_valid} >= 0)) {
1245 qq|SELECT accno AS inventory_accno, | .
1246 qq| new_chart_id AS inventory_new_chart, | .
1247 qq| date($transdate) - valid_from AS inventory_valid | .
1248 qq|FROM chart WHERE id = $ref->{inventory_new_chart}|;
1249 ($ref->{inventory_accno}, $ref->{inventory_new_chart},
1250 $ref->{inventory_valid}) = selectrow_query($form, $dbh, $query);
1253 while ($ref->{income_new_chart} && ($ref->{income_valid} >= 0)) {
1255 qq|SELECT accno AS income_accno, | .
1256 qq| new_chart_id AS income_new_chart, | .
1257 qq| date($transdate) - valid_from AS income_valid | .
1258 qq|FROM chart WHERE id = $ref->{income_new_chart}|;
1259 ($ref->{income_accno}, $ref->{income_new_chart},
1260 $ref->{income_valid}) = selectrow_query($form, $dbh, $query);
1263 while ($ref->{expense_new_chart} && ($ref->{expense_valid} >= 0)) {
1265 qq|SELECT accno AS expense_accno, | .
1266 qq| new_chart_id AS expense_new_chart, | .
1267 qq| date($transdate) - valid_from AS expense_valid | .
1268 qq|FROM chart WHERE id = $ref->{expense_new_chart}|;
1269 ($ref->{expense_accno}, $ref->{expense_new_chart},
1270 $ref->{expense_valid}) = selectrow_query($form, $dbh, $query);
1273 # delete orderitems_id in collective orders, so that they get cloned no matter what
1274 # is this correct? or is the following meant?
1275 # remember orderitems_ids in converted_from_orderitems_ids, so that they may be linked
1276 $ref->{converted_from_orderitems_id} = delete $ref->{orderitems_id} if $is_collective_order;
1278 # get tax rates and description
1279 my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
1281 qq|SELECT c.accno, t.taxdescription, t.rate, t.id as tax_id, c.accno as taxnumber | .
1283 qq|LEFT JOIN chart c on (c.id = t.chart_id) | .
1284 qq|WHERE t.id IN (SELECT tk.tax_id FROM taxkeys tk | .
1285 qq| WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?) | .
1286 qq| AND startdate <= $transdate ORDER BY startdate DESC LIMIT 1) | .
1287 qq|ORDER BY c.accno|;
1288 my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
1289 $ref->{taxaccounts} = "";
1291 while (my $ptr = $stw->fetchrow_hashref("NAME_lc")) {
1292 if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
1296 $ref->{taxaccounts} .= "$ptr->{accno} ";
1297 if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
1298 $form->{"$ptr->{accno}_rate"} = $ptr->{rate};
1299 $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
1300 $form->{"$ptr->{accno}_taxnumber"} = $ptr->{taxnumber};
1301 $form->{"$ptr->{accno}_tax_id"} = $ptr->{tax_id};
1302 $form->{taxaccounts} .= "$ptr->{accno} ";
1307 chop $ref->{taxaccounts};
1309 push @{ $form->{form_details} }, $ref;
1316 # get last name used
1317 $form->lastname_used($dbh, $myconfig, $form->{vc})
1318 unless $form->{"$form->{vc}_id"};
1322 $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? "buy" : "sell");
1324 Common::webdav_folder($form);
1326 $self->load_periodic_invoice_config($form);
1331 sub retrieve_simple {
1332 $main::lxdebug->enter_sub();
1337 Common::check_params(\%params, qw(id));
1339 my $myconfig = \%main::myconfig;
1340 my $form = $main::form;
1342 my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
1344 my $oe_query = qq|SELECT * FROM oe WHERE id = ?|;
1345 my $oi_query = qq|SELECT * FROM orderitems WHERE trans_id = ? ORDER BY position|;
1347 my $order = selectfirst_hashref_query($form, $dbh, $oe_query, conv_i($params{id}));
1348 $order->{orderitems} = selectall_hashref_query( $form, $dbh, $oi_query, conv_i($params{id}));
1350 $main::lxdebug->leave_sub();
1356 $main::lxdebug->enter_sub();
1358 my ($self, $myconfig, $form) = @_;
1360 # connect to database
1361 my $dbh = SL::DB->client->dbh;
1367 my $nodiscount_subtotal = 0;
1368 my $discount_subtotal = 0;
1371 my @partsgroup = ();
1374 my $subtotal_header = 0;
1375 my $subposition = 0;
1383 push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});
1385 $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
1388 foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
1389 $price_factors{$pfac->{id}} = $pfac;
1390 $pfac->{factor} *= 1;
1391 $pfac->{formatted_factor} = $form->format_amount($myconfig, $pfac->{factor});
1394 # sort items by partsgroup
1395 for $i (1 .. $form->{rowcount}) {
1397 if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
1398 $partsgroup = $form->{"partsgroup_$i"};
1400 push @partsgroup, [$i, $partsgroup];
1401 push(@project_ids, $form->{"project_id_$i"}) if ($form->{"project_id_$i"});
1407 $projects = SL::DB::Manager::Project->get_all(query => [ id => \@project_ids ]);
1408 %projects_by_id = map { $_->id => $_ } @$projects;
1411 if ($projects_by_id{$form->{"globalproject_id"}}) {
1412 $form->{globalprojectnumber} = $projects_by_id{$form->{"globalproject_id"}}->projectnumber;
1413 $form->{globalprojectdescription} = $projects_by_id{$form->{"globalproject_id"}}->description;
1415 for (@{ $projects_by_id{$form->{"globalproject_id"}}->cvars_by_config }) {
1416 $form->{"project_cvar_" . $_->config->name} = $_->value_as_text;
1420 $form->{discount} = [];
1422 # get some values of parts from db on store them in extra array,
1423 # so that they can be sorted in later
1424 my %prepared_template_arrays = IC->prepare_parts_for_printing(myconfig => $myconfig, form => $form);
1425 my @prepared_arrays = keys %prepared_template_arrays;
1426 my @separate_totals = qw(non_separate_subtotal);
1428 $form->{TEMPLATE_ARRAYS} = { };
1430 my $ic_cvar_configs = CVar->get_configs(module => 'IC');
1431 my $project_cvar_configs = CVar->get_configs(module => 'Projects');
1434 qw(runningnumber number description longdescription qty qty_nofmt ship ship_nofmt unit bin
1435 partnotes serialnumber reqdate sellprice sellprice_nofmt listprice listprice_nofmt netprice netprice_nofmt
1436 discount discount_nofmt p_discount discount_sub discount_sub_nofmt nodiscount_sub nodiscount_sub_nofmt
1437 linetotal linetotal_nofmt nodiscount_linetotal nodiscount_linetotal_nofmt tax_rate projectnumber projectdescription
1438 price_factor price_factor_name partsgroup weight weight_nofmt lineweight lineweight_nofmt optional);
1440 push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };
1441 push @arrays, map { "project_cvar_$_->{name}" } @{ $project_cvar_configs };
1443 my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);
1445 map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays, @prepared_arrays);
1447 my $totalweight = 0;
1449 foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
1452 if ($item->[1] ne $sameitem) {
1453 push(@{ $form->{TEMPLATE_ARRAYS}->{entry_type} }, 'partsgroup');
1454 push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, qq|$item->[1]|);
1455 $sameitem = $item->[1];
1457 map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } (@arrays, @prepared_arrays)));
1460 $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
1462 if ($form->{"id_$i"} != 0) {
1464 # add number, description and qty to $form->{number}, ....
1466 if ($form->{"subtotal_$i"} && !$subtotal_header) {
1467 $subtotal_header = $i;
1468 $position = int($position);
1471 } elsif ($subtotal_header) {
1473 $position = int($position);
1474 $position = $position.".".$subposition;
1476 $position = int($position);
1480 my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || { 'factor' => 1 };
1482 push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, $prepared_template_arrays{$_}[$i - 1]) for @prepared_arrays;
1484 push @{ $form->{TEMPLATE_ARRAYS}->{entry_type} }, 'normal';
1485 push @{ $form->{TEMPLATE_ARRAYS}->{runningnumber} }, $position;
1486 push @{ $form->{TEMPLATE_ARRAYS}->{number} }, $form->{"partnumber_$i"};
1487 push @{ $form->{TEMPLATE_ARRAYS}->{description} }, $form->{"description_$i"};
1488 push @{ $form->{TEMPLATE_ARRAYS}->{longdescription} }, $form->{"longdescription_$i"};
1489 push @{ $form->{TEMPLATE_ARRAYS}->{qty} }, $form->format_amount($myconfig, $form->{"qty_$i"});
1490 push @{ $form->{TEMPLATE_ARRAYS}->{qty_nofmt} }, $form->{"qty_$i"};
1491 push @{ $form->{TEMPLATE_ARRAYS}->{ship} }, $form->format_amount($myconfig, $form->{"ship_$i"});
1492 push @{ $form->{TEMPLATE_ARRAYS}->{ship_nofmt} }, $form->{"ship_$i"};
1493 push @{ $form->{TEMPLATE_ARRAYS}->{unit} }, $form->{"unit_$i"};
1494 push @{ $form->{TEMPLATE_ARRAYS}->{bin} }, $form->{"bin_$i"};
1495 push @{ $form->{TEMPLATE_ARRAYS}->{partnotes} }, $form->{"partnotes_$i"};
1496 push @{ $form->{TEMPLATE_ARRAYS}->{serialnumber} }, $form->{"serialnumber_$i"};
1497 push @{ $form->{TEMPLATE_ARRAYS}->{reqdate} }, $form->{"reqdate_$i"};
1498 push @{ $form->{TEMPLATE_ARRAYS}->{sellprice} }, $form->{"sellprice_$i"};
1499 push @{ $form->{TEMPLATE_ARRAYS}->{sellprice_nofmt} }, $form->parse_amount($myconfig, $form->{"sellprice_$i"});
1500 push @{ $form->{TEMPLATE_ARRAYS}->{listprice} }, $form->format_amount($myconfig, $form->{"listprice_$i"}, 2);
1501 push @{ $form->{TEMPLATE_ARRAYS}->{listprice_nofmt} }, $form->{"listprice_$i"};
1502 push @{ $form->{TEMPLATE_ARRAYS}->{price_factor} }, $price_factor->{formatted_factor};
1503 push @{ $form->{TEMPLATE_ARRAYS}->{price_factor_name} }, $price_factor->{description};
1504 push @{ $form->{TEMPLATE_ARRAYS}->{partsgroup} }, $form->{"partsgroup_$i"};
1505 push @{ $form->{TEMPLATE_ARRAYS}->{optional} }, $form->{"optional_$i"};
1507 my $sellprice = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
1508 my ($dec) = ($sellprice =~ /\.(\d+)/);
1509 my $decimalplaces = max 2, length($dec);
1511 my $parsed_discount = $form->parse_amount($myconfig, $form->{"discount_$i"});
1513 my $linetotal_exact = $form->{"qty_$i"} * $sellprice * (100 - $parsed_discount) / 100 / $price_factor->{factor};
1514 my $linetotal = $form->round_amount($linetotal_exact, 2);
1516 my $nodiscount_exact_linetotal = $form->{"qty_$i"} * $sellprice / $price_factor->{factor};
1517 my $nodiscount_linetotal = $form->round_amount($nodiscount_exact_linetotal,2);
1519 my $discount = $nodiscount_linetotal - $linetotal; # is always rounded because $nodiscount_linetotal and $linetotal are rounded
1521 my $discount_round_error = $discount + ($linetotal_exact - $nodiscount_exact_linetotal); # not used
1523 $form->{"netprice_$i"} = $form->round_amount($form->{"qty_$i"} ? ($linetotal / $form->{"qty_$i"}) : 0, $decimalplaces);
1525 push @{ $form->{TEMPLATE_ARRAYS}->{netprice} }, ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : '';
1526 push @{ $form->{TEMPLATE_ARRAYS}->{netprice_nofmt} }, ($form->{"netprice_$i"} != 0) ? $form->{"netprice_$i"} : '';
1528 $linetotal = ($linetotal != 0) ? $linetotal : '';
1530 push @{ $form->{TEMPLATE_ARRAYS}->{discount} }, ($discount != 0) ? $form->format_amount($myconfig, $discount * -1, 2) : '';
1531 push @{ $form->{TEMPLATE_ARRAYS}->{discount_nofmt} }, ($discount != 0) ? $discount * -1 : '';
1532 push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} }, $form->{"discount_$i"};
1534 if ( $prepared_template_arrays{separate}[$i - 1] ) {
1535 my $pabbr = $prepared_template_arrays{separate}[$i - 1];
1536 if ( ! $form->{"separate_${pabbr}_subtotal"} ) {
1537 push @separate_totals , "separate_${pabbr}_subtotal";
1538 $form->{"separate_${pabbr}_subtotal"} = 0;
1540 $form->{"separate_${pabbr}_subtotal"} += $linetotal;
1542 $form->{non_separate_subtotal} += $linetotal;
1545 $form->{ordtotal} += $linetotal unless $form->{"optional_$i"};
1546 $form->{nodiscount_total} += $nodiscount_linetotal;
1547 $form->{discount_total} += $discount;
1549 if ($subtotal_header) {
1550 $discount_subtotal += $linetotal;
1551 $nodiscount_subtotal += $nodiscount_linetotal;
1554 if ($form->{"subtotal_$i"} && $subtotal_header && ($subtotal_header != $i)) {
1555 push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} }, $form->format_amount($myconfig, $discount_subtotal, 2);
1556 push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub_nofmt} }, $discount_subtotal;
1557 push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, $form->format_amount($myconfig, $nodiscount_subtotal, 2);
1558 push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub_nofmt} }, $nodiscount_subtotal;
1560 $discount_subtotal = 0;
1561 $nodiscount_subtotal = 0;
1562 $subtotal_header = 0;
1565 push @{ $form->{TEMPLATE_ARRAYS}->{$_} }, "" for qw(discount_sub nodiscount_sub discount_sub_nofmt nodiscount_sub_nofmt);
1568 if (!$form->{"discount_$i"}) {
1569 $nodiscount += $linetotal;
1572 my $project = $projects_by_id{$form->{"project_id_$i"}} || SL::DB::Project->new;
1574 push @{ $form->{TEMPLATE_ARRAYS}->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2);
1575 push @{ $form->{TEMPLATE_ARRAYS}->{linetotal_nofmt} }, $linetotal_exact;
1576 push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} }, $form->format_amount($myconfig, $nodiscount_linetotal, 2);
1577 push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal_nofmt} }, $nodiscount_linetotal;
1578 push @{ $form->{TEMPLATE_ARRAYS}->{projectnumber} }, $project->projectnumber;
1579 push @{ $form->{TEMPLATE_ARRAYS}->{projectdescription} }, $project->description;
1581 my $lineweight = $form->{"qty_$i"} * $form->{"weight_$i"};
1582 $totalweight += $lineweight;
1583 push @{ $form->{TEMPLATE_ARRAYS}->{weight} }, $form->format_amount($myconfig, $form->{"weight_$i"}, 3);
1584 push @{ $form->{TEMPLATE_ARRAYS}->{weight_nofmt} }, $form->{"weight_$i"};
1585 push @{ $form->{TEMPLATE_ARRAYS}->{lineweight} }, $form->format_amount($myconfig, $lineweight, 3);
1586 push @{ $form->{TEMPLATE_ARRAYS}->{lineweight_nofmt} }, $lineweight;
1588 my ($taxamount, $taxbase);
1591 map { $taxrate += $form->{"${_}_rate"} } split(/ /, $form->{"taxaccounts_$i"});
1593 unless ($form->{"optional_$i"}) {
1594 if ($form->{taxincluded}) {
1597 $taxamount = $linetotal * $taxrate / (1 + $taxrate);
1598 $taxbase = $linetotal / (1 + $taxrate);
1600 $taxamount = $linetotal * $taxrate;
1601 $taxbase = $linetotal;
1605 if ($taxamount != 0) {
1606 foreach my $accno (split / /, $form->{"taxaccounts_$i"}) {
1607 $taxaccounts{$accno} += $taxamount * $form->{"${accno}_rate"} / $taxrate;
1608 $taxbase{$accno} += $taxbase;
1612 $tax_rate = $taxrate * 100;
1613 push(@{ $form->{TEMPLATE_ARRAYS}->{tax_rate} }, qq|$tax_rate|);
1615 if ($form->{"part_type_$i"} eq 'assembly') {
1618 # get parts and push them onto the stack
1620 if ($form->{groupitems}) {
1621 $sortorder = qq|ORDER BY pg.partsgroup, a.position|;
1623 $sortorder = qq|ORDER BY a.position|;
1626 $query = qq|SELECT p.partnumber, p.description, p.unit, a.qty, | .
1627 qq|pg.partsgroup | .
1628 qq|FROM assembly a | .
1629 qq| JOIN parts p ON (a.parts_id = p.id) | .
1630 qq| LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) | .
1631 qq| WHERE a.bom = '1' | .
1632 qq| AND a.id = ? | . $sortorder;
1633 @values = ($form->{"id_$i"});
1634 $sth = $dbh->prepare($query);
1635 $sth->execute(@values) || $form->dberror($query);
1637 while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1638 if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
1639 map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } (@arrays, @prepared_arrays)));
1640 $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
1641 push(@{ $form->{TEMPLATE_ARRAYS}->{entry_type} }, 'assembly-item-partsgroup');
1642 push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $sameitem);
1645 push(@{ $form->{TEMPLATE_ARRAYS}->{entry_type} }, 'assembly-item');
1646 push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}) . qq|, $ref->{partnumber}, $ref->{description}|);
1647 map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } (@arrays, @prepared_arrays)));
1652 CVar->get_non_editable_ic_cvars(form => $form,
1655 sub_module => 'orderitems',
1656 may_converted_from => ['orderitems', 'invoice']);
1658 push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} },
1659 CVar->format_to_template(CVar->parse($form->{"ic_cvar_$_->{name}_$i"}, $_), $_)
1660 for @{ $ic_cvar_configs };
1662 push @{ $form->{TEMPLATE_ARRAYS}->{"project_cvar_" . $_->config->name} }, $_->value_as_text for @{ $project->cvars_by_config };
1666 $form->{totalweight} = $form->format_amount($myconfig, $totalweight, 3);
1667 $form->{totalweight_nofmt} = $totalweight;
1668 my $defaults = AM->get_defaults();
1669 $form->{weightunit} = $defaults->{weightunit};
1672 foreach $item (sort keys %taxaccounts) {
1673 $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
1675 push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase} }, $form->format_amount($myconfig, $taxbase{$item}, 2));
1676 push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase_nofmt} }, $taxbase{$item});
1677 push(@{ $form->{TEMPLATE_ARRAYS}->{tax} }, $form->format_amount($myconfig, $taxamount, 2));
1678 push(@{ $form->{TEMPLATE_ARRAYS}->{tax_nofmt} }, $taxamount);
1679 push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate} }, $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
1680 push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate_nofmt} }, $form->{"${item}_rate"} * 100);
1681 push(@{ $form->{TEMPLATE_ARRAYS}->{taxnumber} }, $form->{"${item}_taxnumber"});
1682 push(@{ $form->{TEMPLATE_ARRAYS}->{tax_id} }, $form->{"${item}_tax_id"});
1684 if ( $form->{"${item}_tax_id"} ) {
1685 my $tax_obj = SL::DB::Manager::Tax->find_by(id => $form->{"${item}_tax_id"}) or die "Can't find tax with id " . $form->{"${item}_tax_id"};
1686 my $description = $tax_obj ? $tax_obj->translated_attribute('taxdescription', $form->{language_id}, 0) : '';
1687 push(@{ $form->{TEMPLATE_ARRAYS}->{taxdescription} }, $description . q{ } . 100 * $form->{"${item}_rate"} . q{%});
1691 $form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
1692 $form->{discount_total} = $form->format_amount($myconfig, $form->{discount_total}, 2);
1693 $form->{nodiscount} = $form->format_amount($myconfig, $nodiscount, 2);
1694 $form->{yesdiscount} = $form->format_amount($myconfig, $form->{nodiscount_total} - $nodiscount, 2);
1696 if($form->{taxincluded}) {
1697 $form->{subtotal} = $form->format_amount($myconfig, $form->{ordtotal} - $tax, 2);
1698 $form->{subtotal_nofmt} = $form->{ordtotal} - $tax;
1700 $form->{subtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
1701 $form->{subtotal_nofmt} = $form->{ordtotal};
1704 my $grossamount = ($form->{taxincluded}) ? $form->{ordtotal} : $form->{ordtotal} + $tax;
1705 $form->{ordtotal} = $form->round_amount( $grossamount, 2, 1);
1706 $form->{rounding} = $form->round_amount(
1707 $form->{ordtotal} - $form->round_amount($grossamount, 2),
1712 $form->{rounding} = $form->format_amount($myconfig, $form->{rounding}, 2);
1713 $form->{quototal} = $form->{ordtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
1715 $form->set_payment_options($myconfig, $form->{$form->{type} =~ /_quotation/ ? 'quodate' : 'orddate'}, $form->{type});
1717 $form->{username} = $myconfig->{name};
1719 $form->{department} = SL::DB::Manager::Department->find_by(id => $form->{department_id})->description if $form->{department_id};
1720 $form->{delivery_term} = SL::DB::Manager::DeliveryTerm->find_by(id => $form->{delivery_term_id} || undef);
1721 $form->{delivery_term}->description_long($form->{delivery_term}->translated_attribute('description_long', $form->{language_id})) if $form->{delivery_term} && $form->{language_id};
1723 $form->{order} = SL::DB::Manager::Order->find_by(id => $form->{id}) if $form->{id};
1724 $form->{$_} = $form->format_amount($myconfig, $form->{$_}, 2) for @separate_totals;
1726 $main::lxdebug->leave_sub();
1735 OE.pm - Order entry module
1739 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>.
1745 =item retrieve_simple PARAMS
1747 simple OE retrieval by id. does not look up customer, vendor, units or any other stuff. only oe and orderitems.
1749 my $order = retrieve_simple(id => 2);