Merge branch 'karushka'
[kivitendo-erp.git] / SL / IS.pm
1 #=====================================================================
2 # LX-Office ERP
3 # Copyright (C) 2004
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
6 #
7 #=====================================================================
8 # SQL-Ledger Accounting
9 # Copyright (C) 1998-2002
10 #
11 #  Author: Dieter Simader
12 #   Email: dsimader@sql-ledger.org
13 #     Web: http://www.sql-ledger.org
14 #
15 #  Contributors:
16 #
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.
21 #
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 #======================================================================
30 #
31 # Inventory invoicing module
32 #
33 #======================================================================
34
35 package IS;
36
37 #use strict;
38
39 use List::Util qw(max);
40
41 use SL::AM;
42 use SL::ARAP;
43 use SL::CVar;
44 use SL::Common;
45 use SL::DBUtils;
46 use SL::DO;
47 use SL::GenericTranslations;
48 use SL::MoreCommon;
49 use SL::IC;
50 use Data::Dumper;
51
52 sub invoice_details {
53   $main::lxdebug->enter_sub();
54
55   my ($self, $myconfig, $form, $locale) = @_;
56
57   $form->{duedate} ||= $form->{invdate};
58
59   # connect to database
60   my $dbh = $form->dbconnect($myconfig);
61   my $sth;
62
63   my $query = qq|SELECT date | . conv_dateq($form->{duedate}) . qq| - date | . conv_dateq($form->{invdate}) . qq| AS terms|;
64   ($form->{terms}) = selectrow_query($form, $dbh, $query);
65
66   my (@project_ids, %projectnumbers);
67   $form->{TEMPLATE_ARRAYS} = {};
68
69   push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});
70
71   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
72   my %price_factors;
73
74   foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
75     $price_factors{$pfac->{id}}  = $pfac;
76     $pfac->{factor}             *= 1;
77     $pfac->{formatted_factor}    = $form->format_amount($myconfig, $pfac->{factor});
78   }
79
80   # sort items by partsgroup
81   for my $i (1 .. $form->{rowcount}) {
82 #    $partsgroup = "";
83 #    if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
84 #      $partsgroup = $form->{"partsgroup_$i"};
85 #    }
86 #    push @partsgroup, [$i, $partsgroup];
87     push(@project_ids, $form->{"project_id_$i"}) if ($form->{"project_id_$i"});
88   }
89
90   if (@project_ids) {
91     $query = "SELECT id, projectnumber FROM project WHERE id IN (" .
92       join(", ", map({ "?" } @project_ids)) . ")";
93     $sth = $dbh->prepare($query);
94     $sth->execute(@project_ids) ||
95       $form->dberror($query . " (" . join(", ", @project_ids) . ")");
96     while (my $ref = $sth->fetchrow_hashref()) {
97       $projectnumbers{$ref->{id}} = $ref->{projectnumber};
98     }
99     $sth->finish();
100   }
101
102   $form->{"globalprojectnumber"} =
103     $projectnumbers{$form->{"globalproject_id"}};
104
105   my $tax = 0;
106   my $item;
107   my $i;
108   my @partsgroup = ();
109   my $partsgroup;
110   my %oid = ('Pg'     => 'oid',
111              'Oracle' => 'rowid');
112
113   # sort items by partsgroup
114   for $i (1 .. $form->{rowcount}) {
115     $partsgroup = "";
116     if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
117       $partsgroup = $form->{"partsgroup_$i"};
118     }
119     push @partsgroup, [$i, $partsgroup];
120   }
121
122   my $sameitem = "";
123   my @taxaccounts;
124   my %taxaccounts;
125   my %taxbase;
126   my $taxrate;
127   my $taxamount;
128   my $taxbase;
129   my $taxdiff;
130   my $nodiscount;
131   my $yesdiscount;
132   my $nodiscount_subtotal = 0;
133   my $discount_subtotal = 0;
134   my $position = 0;
135   my $subtotal_header = 0;
136   my $subposition = 0;
137
138   $form->{discount} = [];
139
140   IC->prepare_parts_for_printing();
141
142   my $ic_cvar_configs = CVar->get_configs(module => 'IC');
143
144   my @arrays =
145     qw(runningnumber number description longdescription qty ship unit bin
146        deliverydate_oe ordnumber_oe transdate_oe licensenumber validuntil
147        partnotes serialnumber reqdate sellprice listprice netprice
148        discount p_discount discount_sub nodiscount_sub
149        linetotal  nodiscount_linetotal tax_rate projectnumber
150        price_factor price_factor_name partsgroup);
151
152   push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };
153
154   my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);
155
156   my @payment_arrays = qw(payment paymentaccount paymentdate paymentsource paymentmemo);
157
158   map { $form->{TEMPLATE_ARRAYS}{$_} => [] } (@arrays, @tax_arrays, @payment_arrays);
159
160   foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
161     $i = $item->[0];
162
163     if ($item->[1] ne $sameitem) {
164       push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, qq|$item->[1]|);
165       $sameitem = $item->[1];
166
167       map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
168     }
169
170     $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
171
172     if ($form->{"id_$i"} != 0) {
173
174       # add number, description and qty to $form->{number},
175       if ($form->{"subtotal_$i"} && !$subtotal_header) {
176         $subtotal_header = $i;
177         $position = int($position);
178         $subposition = 0;
179         $position++;
180       } elsif ($subtotal_header) {
181         $subposition += 1;
182         $position = int($position);
183         $position = $position.".".$subposition;
184       } else {
185         $position = int($position);
186         $position++;
187       }
188
189       my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || { 'factor' => 1 };
190
191       push @{ $form->{TEMPLATE_ARRAYS}->{runningnumber} },     $position;
192       push @{ $form->{TEMPLATE_ARRAYS}->{number} },            $form->{"partnumber_$i"};
193       push @{ $form->{TEMPLATE_ARRAYS}->{serialnumber} },      $form->{"serialnumber_$i"};
194       push @{ $form->{TEMPLATE_ARRAYS}->{bin} },               $form->{"bin_$i"};
195       push @{ $form->{TEMPLATE_ARRAYS}->{partnotes} },         $form->{"partnotes_$i"};
196       push @{ $form->{TEMPLATE_ARRAYS}->{description} },       $form->{"description_$i"};
197       push @{ $form->{TEMPLATE_ARRAYS}->{longdescription} },   $form->{"longdescription_$i"};
198       push @{ $form->{TEMPLATE_ARRAYS}->{qty} },               $form->format_amount($myconfig, $form->{"qty_$i"});
199       push @{ $form->{TEMPLATE_ARRAYS}->{unit} },              $form->{"unit_$i"};
200       push @{ $form->{TEMPLATE_ARRAYS}->{deliverydate_oe} },   $form->{"deliverydate_$i"};
201       push @{ $form->{TEMPLATE_ARRAYS}->{sellprice} },         $form->{"sellprice_$i"};
202       push @{ $form->{TEMPLATE_ARRAYS}->{ordnumber_oe} },      $form->{"ordnumber_$i"};
203       push @{ $form->{TEMPLATE_ARRAYS}->{transdate_oe} },      $form->{"transdate_$i"};
204       push @{ $form->{TEMPLATE_ARRAYS}->{invnumber} },         $form->{"invnumber"};
205       push @{ $form->{TEMPLATE_ARRAYS}->{invdate} },           $form->{"invdate"};
206       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor} },      $price_factor->{formatted_factor};
207       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor_name} }, $price_factor->{description};
208       push @{ $form->{TEMPLATE_ARRAYS}->{partsgroup} },        $form->{"partsgroup_$i"};
209       push @{ $form->{TEMPLATE_ARRAYS}->{reqdate} },           $form->{"reqdate_$i"};
210
211       if ($form->{lizenzen}) {
212         if ($form->{"licensenumber_$i"}) {
213           $query = qq|SELECT licensenumber, validuntil FROM license WHERE id = ?|;
214           my ($licensenumber, $validuntil) = selectrow_query($form, $dbh, $query, conv_i($form->{"licensenumber_$i"}));
215           push(@{ $form->{TEMPLATE_ARRAYS}->{licensenumber} }, $licensenumber);
216           push(@{ $form->{TEMPLATE_ARRAYS}->{validuntil} }, $locale->date($myconfig, $validuntil, 0));
217
218         } else {
219           push(@{ $form->{TEMPLATE_ARRAYS}->{licensenumber} }, "");
220           push(@{ $form->{TEMPLATE_ARRAYS}->{validuntil} },    "");
221         }
222       }
223
224       # listprice
225       push(@{ $form->{TEMPLATE_ARRAYS}->{listprice} }, $form->{"listprice_$i"});
226
227       my $sellprice     = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
228       my ($dec)         = ($sellprice =~ /\.(\d+)/);
229       my $decimalplaces = max 2, length($dec);
230
231       my $parsed_discount      = $form->parse_amount($myconfig, $form->{"discount_$i"});
232       my $linetotal_exact      =                     $form->{"qty_$i"} * $sellprice * (100 - $parsed_discount) / 100 / $price_factor->{factor};
233       my $linetotal            = $form->round_amount($linetotal_exact, 2);
234       my $discount             = $form->round_amount($form->{"qty_$i"} * $sellprice * $parsed_discount / 100 / $price_factor->{factor} - ($linetotal - $linetotal_exact),
235                                                      $decimalplaces);
236       my $nodiscount_linetotal = $form->round_amount($form->{"qty_$i"} * $sellprice / $price_factor->{factor}, 2);
237       $form->{"netprice_$i"}   = $form->round_amount($form->{"qty_$i"} ? ($linetotal / $form->{"qty_$i"}) : 0, 2);
238
239       push @{ $form->{TEMPLATE_ARRAYS}->{netprice} }, ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : '';
240
241       $linetotal = ($linetotal != 0) ? $linetotal : '';
242
243       push @{ $form->{TEMPLATE_ARRAYS}->{discount} },   ($discount  != 0) ? $form->format_amount($myconfig, $discount * -1, 2) : '';
244       push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} }, $form->{"discount_$i"};
245
246       $form->{total}            += $linetotal;
247       $form->{nodiscount_total} += $nodiscount_linetotal;
248       $form->{discount_total}   += $discount;
249
250       if ($subtotal_header) {
251         $discount_subtotal   += $linetotal;
252         $nodiscount_subtotal += $nodiscount_linetotal;
253       }
254
255       if ($form->{"subtotal_$i"} && $subtotal_header && ($subtotal_header != $i)) {
256         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} },   $form->format_amount($myconfig, $discount_subtotal,   2);
257         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, $form->format_amount($myconfig, $nodiscount_subtotal, 2);
258
259         $discount_subtotal   = 0;
260         $nodiscount_subtotal = 0;
261         $subtotal_header     = 0;
262
263       } else {
264         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} },   "";
265         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, "";
266       }
267
268       if (!$form->{"discount_$i"}) {
269         $nodiscount += $linetotal;
270       }
271
272       push @{ $form->{TEMPLATE_ARRAYS}->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2);
273       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} }, $form->format_amount($myconfig, $nodiscount_linetotal, 2);
274
275       push(@{ $form->{TEMPLATE_ARRAYS}->{projectnumber} }, $projectnumbers{$form->{"project_id_$i"}});
276
277       @taxaccounts = split(/ /, $form->{"taxaccounts_$i"});
278       $taxrate     = 0;
279       $taxdiff     = 0;
280
281       map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;
282
283       if ($form->{taxincluded}) {
284
285         # calculate tax
286         $taxamount = $linetotal * $taxrate / (1 + $taxrate);
287         $taxbase = $linetotal - $taxamount;
288       } else {
289         $taxamount = $linetotal * $taxrate;
290         $taxbase   = $linetotal;
291       }
292
293       if ($form->round_amount($taxrate, 7) == 0) {
294         if ($form->{taxincluded}) {
295           foreach my $accno (@taxaccounts) {
296             $taxamount            = $form->round_amount($linetotal * $form->{"${accno}_rate"} / (1 + abs($form->{"${accno}_rate"})), 2);
297
298             $taxaccounts{$accno} += $taxamount;
299             $taxdiff             += $taxamount;
300
301             $taxbase{$accno}     += $taxbase;
302           }
303           $taxaccounts{ $taxaccounts[0] } += $taxdiff;
304         } else {
305           foreach my $accno (@taxaccounts) {
306             $taxaccounts{$accno} += $linetotal * $form->{"${accno}_rate"};
307             $taxbase{$accno}     += $taxbase;
308           }
309         }
310       } else {
311         foreach my $accno (@taxaccounts) {
312           $taxaccounts{$accno} += $taxamount * $form->{"${accno}_rate"} / $taxrate;
313           $taxbase{$accno}     += $taxbase;
314         }
315       }
316       my $tax_rate = $taxrate * 100;
317       push(@{ $form->{TEMPLATE_ARRAYS}->{tax_rate} }, qq|$tax_rate|);
318       if ($form->{"assembly_$i"}) {
319         $sameitem = "";
320
321         # get parts and push them onto the stack
322         my $sortorder = "";
323         if ($form->{groupitems}) {
324           $sortorder =
325             qq|ORDER BY pg.partsgroup, a.$oid{$myconfig->{dbdriver}}|;
326         } else {
327           $sortorder = qq|ORDER BY a.$oid{$myconfig->{dbdriver}}|;
328         }
329
330         $query =
331           qq|SELECT p.partnumber, p.description, p.unit, a.qty, pg.partsgroup
332              FROM assembly a
333              JOIN parts p ON (a.parts_id = p.id)
334              LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
335              WHERE (a.bom = '1') AND (a.id = ?) $sortorder|;
336         $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id_$i"}));
337
338         while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
339           if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
340             map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
341             $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
342             push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $sameitem);
343           }
344
345           map { $form->{"a_$_"} = $ref->{$_} } qw(partnumber description);
346
347           push(@{ $form->{TEMPLATE_ARRAYS}->{description} },
348                $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}
349                  )
350                  . qq| -- $form->{"a_partnumber"}, $form->{"a_description"}|);
351           map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
352
353         }
354         $sth->finish;
355       }
356
357       map { push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} }, $form->{"ic_cvar_$_->{name}_$i"} } @{ $ic_cvar_configs };
358     }
359   }
360
361   foreach my $item (sort keys %taxaccounts) {
362     $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
363
364     push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase} },        $form->format_amount($myconfig, $taxbase{$item}, 2));
365     push(@{ $form->{TEMPLATE_ARRAYS}->{tax} },            $form->format_amount($myconfig, $taxamount,      2));
366     push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate} },        $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
367     push(@{ $form->{TEMPLATE_ARRAYS}->{taxdescription} }, $form->{"${item}_description"} . q{ } . 100 * $form->{"${item}_rate"} . q{%});
368     push(@{ $form->{TEMPLATE_ARRAYS}->{taxnumber} },      $form->{"${item}_taxnumber"});
369   }
370
371   for my $i (1 .. $form->{paidaccounts}) {
372     if ($form->{"paid_$i"}) {
373       my ($accno, $description) = split(/--/, $form->{"AR_paid_$i"});
374
375       push(@{ $form->{TEMPLATE_ARRAYS}->{payment} },        $form->{"paid_$i"});
376       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentaccount} }, $description);
377       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentdate} },    $form->{"datepaid_$i"});
378       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentsource} },  $form->{"source_$i"});
379       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentmemo} },    $form->{"memo_$i"});
380
381       $form->{paid} += $form->parse_amount($myconfig, $form->{"paid_$i"});
382     }
383   }
384   if($form->{taxincluded}) {
385     $form->{subtotal} = $form->format_amount($myconfig, $form->{total} - $tax, 2);
386   }
387   else {
388     $form->{subtotal} = $form->format_amount($myconfig, $form->{total}, 2);
389   }
390
391   $form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
392   $form->{discount_total}      = $form->format_amount($myconfig, $form->{discount_total}, 2);
393   $form->{nodiscount}          = $form->format_amount($myconfig, $nodiscount, 2);
394   $form->{yesdiscount}         = $form->format_amount($myconfig, $form->{nodiscount_total} - $nodiscount, 2);
395
396   $form->{invtotal} = ($form->{taxincluded}) ? $form->{total} : $form->{total} + $tax;
397   $form->{total}    = $form->format_amount($myconfig, $form->{invtotal} - $form->{paid}, 2);
398
399   $form->{invtotal} = $form->format_amount($myconfig, $form->{invtotal}, 2);
400   $form->{paid}     = $form->format_amount($myconfig, $form->{paid}, 2);
401
402   $form->set_payment_options($myconfig, $form->{invdate});
403
404   $form->{username} = $myconfig->{name};
405
406   $dbh->disconnect;
407
408   $main::lxdebug->leave_sub();
409 }
410
411 sub project_description {
412   $main::lxdebug->enter_sub();
413
414   my ($self, $dbh, $id) = @_;
415   my $form = \%main::form;
416
417   my $query = qq|SELECT description FROM project WHERE id = ?|;
418   my ($description) = selectrow_query($form, $dbh, $query, conv_i($id));
419
420   $main::lxdebug->leave_sub();
421
422   return $_;
423 }
424
425 sub customer_details {
426   $main::lxdebug->enter_sub();
427
428   my ($self, $myconfig, $form, @wanted_vars) = @_;
429
430   # connect to database
431   my $dbh = $form->dbconnect($myconfig);
432
433   my $language_id = $form->{language_id};
434
435   # get contact id, set it if nessessary
436   $form->{cp_id} *= 1;
437
438   my @values =  (conv_i($form->{customer_id}));
439
440   my $where = "";
441   if ($form->{cp_id}) {
442     $where = qq| AND (cp.cp_id = ?) |;
443     push(@values, conv_i($form->{cp_id}));
444   }
445
446   # get rest for the customer
447   my $query =
448     qq|SELECT ct.*, cp.*, ct.notes as customernotes,
449          ct.phone AS customerphone, ct.fax AS customerfax, ct.email AS customeremail
450        FROM customer ct
451        LEFT JOIN contacts cp on ct.id = cp.cp_cv_id
452        WHERE (ct.id = ?) $where
453        ORDER BY cp.cp_id
454        LIMIT 1|;
455   my $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
456
457   # remove id and taxincluded before copy back
458   delete @$ref{qw(id taxincluded)};
459
460   @wanted_vars = grep({ $_ } @wanted_vars);
461   if (scalar(@wanted_vars) > 0) {
462     my %h_wanted_vars;
463     map({ $h_wanted_vars{$_} = 1; } @wanted_vars);
464     map({ delete($ref->{$_}) unless ($h_wanted_vars{$_}); } keys(%{$ref}));
465   }
466
467   map { $form->{$_} = $ref->{$_} } keys %$ref;
468
469   if ($form->{delivery_customer_id}) {
470     $query =
471       qq|SELECT *, notes as customernotes
472          FROM customer
473          WHERE id = ?
474          LIMIT 1|;
475     $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{delivery_customer_id}));
476
477     map { $form->{"dc_$_"} = $ref->{$_} } keys %$ref;
478   }
479
480   if ($form->{delivery_vendor_id}) {
481     $query =
482       qq|SELECT *, notes as customernotes
483          FROM customer
484          WHERE id = ?
485          LIMIT 1|;
486     $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{delivery_vendor_id}));
487
488     map { $form->{"dv_$_"} = $ref->{$_} } keys %$ref;
489   }
490
491   my $custom_variables = CVar->get_custom_variables('dbh'      => $dbh,
492                                                     'module'   => 'CT',
493                                                     'trans_id' => $form->{customer_id});
494   map { $form->{"vc_cvar_$_->{name}"} = $_->{value} } @{ $custom_variables };
495
496   $form->{cp_greeting} = GenericTranslations->get('dbh'              => $dbh,
497                                                   'translation_type' => 'greetings::' . ($form->{cp_gender} eq 'f' ? 'female' : 'male'),
498                                                   'language_id'      => $language_id,
499                                                   'allow_fallback'   => 1);
500
501
502   $dbh->disconnect;
503
504   $main::lxdebug->leave_sub();
505 }
506
507 sub post_invoice {
508   $main::lxdebug->enter_sub();
509
510   my ($self, $myconfig, $form, $provided_dbh, $payments_only) = @_;
511
512   # connect to database, turn off autocommit
513   my $dbh = $provided_dbh ? $provided_dbh : $form->dbconnect_noauto($myconfig);
514
515   my ($query, $sth, $null, $project_id, @values);
516   my $exchangerate = 0;
517
518   my $ic_cvar_configs = CVar->get_configs(module => 'IC',
519                                           dbh    => $dbh);
520
521   if (!$form->{employee_id}) {
522     $form->get_employee($dbh);
523   }
524
525   $form->{defaultcurrency} = $form->get_default_currency($myconfig);
526
527   ($null, $form->{department_id}) = split(/--/, $form->{department});
528
529   my $all_units = AM->retrieve_units($myconfig, $form);
530
531   if (!$payments_only) {
532     if ($form->{id}) {
533       &reverse_invoice($dbh, $form);
534
535     } else {
536       $query = qq|SELECT nextval('glid')|;
537       ($form->{"id"}) = selectrow_query($form, $dbh, $query);
538
539       $query = qq|INSERT INTO ar (id, invnumber) VALUES (?, ?)|;
540       do_query($form, $dbh, $query, $form->{"id"}, $form->{"id"});
541
542       if (!$form->{invnumber}) {
543         $form->{invnumber} =
544           $form->update_defaults($myconfig, $form->{type} eq "credit_note" ?
545                                  "cnnumber" : "invnumber", $dbh);
546       }
547     }
548   }
549
550   my ($netamount, $invoicediff) = (0, 0);
551   my ($amount, $linetotal, $lastincomeaccno);
552
553   my ($currencies)    = selectfirst_array_query($form, $dbh, qq|SELECT curr FROM defaults|);
554   my $defaultcurrency = (split m/:/, $currencies)[0];
555
556   if ($form->{currency} eq $defaultcurrency) {
557     $form->{exchangerate} = 1;
558   } else {
559     $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'buy');
560   }
561
562   $form->{exchangerate} =
563     ($exchangerate)
564     ? $exchangerate
565     : $form->parse_amount($myconfig, $form->{exchangerate});
566
567   $form->{expense_inventory} = "";
568
569   my %baseunits;
570
571   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
572   my %price_factors = map { $_->{id} => $_->{factor} } @{ $form->{ALL_PRICE_FACTORS} };
573   my $price_factor;
574
575   $form->{amount}      = {};
576   $form->{amount_cogs} = {};
577
578   foreach my $i (1 .. $form->{rowcount}) {
579     if ($form->{type} eq "credit_note") {
580       $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}) * -1;
581       $form->{shipped} = 1;
582     } else {
583       $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
584     }
585     my $basefactor;
586     my $baseqty;
587
588     $form->{"marge_percent_$i"} = $form->parse_amount($myconfig, $form->{"marge_percent_$i"}) * 1;
589     $form->{"marge_total_$i"} = $form->parse_amount($myconfig, $form->{"marge_total_$i"}) * 1;
590     $form->{"lastcost_$i"} = $form->{"lastcost_$i"} * 1;
591
592     if ($form->{storno}) {
593       $form->{"qty_$i"} *= -1;
594     }
595
596     if ($form->{"id_$i"}) {
597       my $item_unit;
598
599       if (defined($baseunits{$form->{"id_$i"}})) {
600         $item_unit = $baseunits{$form->{"id_$i"}};
601       } else {
602         # get item baseunit
603         $query = qq|SELECT unit FROM parts WHERE id = ?|;
604         ($item_unit) = selectrow_query($form, $dbh, $query, conv_i($form->{"id_$i"}));
605         $baseunits{$form->{"id_$i"}} = $item_unit;
606       }
607
608       if (defined($all_units->{$item_unit}->{factor})
609           && ($all_units->{$item_unit}->{factor} ne '')
610           && ($all_units->{$item_unit}->{factor} != 0)) {
611         $basefactor = $all_units->{$form->{"unit_$i"}}->{factor} / $all_units->{$item_unit}->{factor};
612       } else {
613         $basefactor = 1;
614       }
615       $baseqty = $form->{"qty_$i"} * $basefactor;
616
617       my ($allocated, $taxrate) = (0, 0);
618       my $taxamount;
619
620       # add tax rates
621       map { $taxrate += $form->{"${_}_rate"} } split(/ /, $form->{"taxaccounts_$i"});
622
623       # keep entered selling price
624       my $fxsellprice =
625         $form->parse_amount($myconfig, $form->{"sellprice_$i"});
626
627       my ($dec) = ($fxsellprice =~ /\.(\d+)/);
628       $dec = length $dec;
629       my $decimalplaces = ($dec > 2) ? $dec : 2;
630
631       # undo discount formatting
632       $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
633
634       # deduct discount
635       $form->{"sellprice_$i"} = $fxsellprice * (1 - $form->{"discount_$i"});
636
637       # round linetotal to 2 decimal places
638       $price_factor = $price_factors{ $form->{"price_factor_id_$i"} } || 1;
639       $linetotal    = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2);
640
641       if ($form->{taxincluded}) {
642         $taxamount = $linetotal * ($taxrate / (1 + $taxrate));
643         $form->{"sellprice_$i"} =
644           $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
645       } else {
646         $taxamount = $linetotal * $taxrate;
647       }
648
649       $netamount += $linetotal;
650
651       if ($taxamount != 0) {
652         map {
653           $form->{amount}{ $form->{id} }{$_} +=
654             $taxamount * $form->{"${_}_rate"} / $taxrate
655         } split(/ /, $form->{"taxaccounts_$i"});
656       }
657
658       # add amount to income, $form->{amount}{trans_id}{accno}
659       $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate} / $price_factor;
660
661       $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2) * $form->{exchangerate};
662       $linetotal = $form->round_amount($linetotal, 2);
663
664       # this is the difference from the inventory
665       $invoicediff += ($amount - $linetotal);
666
667       $form->{amount}{ $form->{id} }{ $form->{"income_accno_$i"} } +=
668         $linetotal;
669
670       $lastincomeaccno = $form->{"income_accno_$i"};
671
672       # adjust and round sellprice
673       $form->{"sellprice_$i"} =
674         $form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate},
675                             $decimalplaces);
676
677       next if $payments_only;
678
679       if ($form->{"inventory_accno_$i"} || $form->{"assembly_$i"}) {
680
681         if ($form->{"assembly_$i"}) {
682           # record assembly item as allocated
683           &process_assembly($dbh, $form, $form->{"id_$i"}, $baseqty);
684
685         } else {
686           $allocated = &cogs($dbh, $form, $form->{"id_$i"}, $baseqty, $basefactor, $i);
687         }
688       }
689
690       # get pricegroup_id and save it
691       ($null, my $pricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
692       $pricegroup_id *= 1;
693
694       my ($invoice_id) = selectfirst_array_query($form, $dbh, qq|SELECT nextval('invoiceid')|);
695
696       # save detail record in invoice table
697       $query =
698         qq|INSERT INTO invoice (id, trans_id, parts_id, description, longdescription, qty,
699                                 sellprice, fxsellprice, discount, allocated, assemblyitem,
700                                 unit, deliverydate, project_id, serialnumber, pricegroup_id,
701                                 ordnumber, transdate, cusordnumber, base_qty, subtotal,
702                                 marge_percent, marge_total, lastcost,
703                                 price_factor_id, price_factor, marge_price_factor)
704            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
705                    (SELECT factor FROM price_factors WHERE id = ?), ?)|;
706
707       @values = ($invoice_id, conv_i($form->{id}), conv_i($form->{"id_$i"}),
708                  $form->{"description_$i"}, $form->{"longdescription_$i"}, $form->{"qty_$i"},
709                  $form->{"sellprice_$i"}, $fxsellprice,
710                  $form->{"discount_$i"}, $allocated, 'f',
711                  $form->{"unit_$i"}, conv_date($form->{"reqdate_$i"}), conv_i($form->{"project_id_$i"}),
712                  $form->{"serialnumber_$i"}, conv_i($pricegroup_id),
713                  $form->{"ordnumber_$i"}, conv_date($form->{"transdate_$i"}),
714                  $form->{"cusordnumber_$i"}, $baseqty, $form->{"subtotal_$i"} ? 't' : 'f',
715                  $form->{"marge_percent_$i"}, $form->{"marge_total_$i"},
716                  $form->{"lastcost_$i"},
717                  conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
718                  conv_i($form->{"marge_price_factor_$i"}));
719       do_query($form, $dbh, $query, @values);
720
721       if ($form->{lizenzen} && $form->{"licensenumber_$i"}) {
722         $query =
723           qq|INSERT INTO licenseinvoice (trans_id, license_id)
724              VALUES ((SELECT id FROM invoice WHERE trans_id = ? ORDER BY oid DESC LIMIT 1), ?)|;
725         @values = (conv_i($form->{"id"}), conv_i($form->{"licensenumber_$i"}));
726         do_query($form, $dbh, $query, @values);
727       }
728
729       CVar->save_custom_variables(module       => 'IC',
730                                   sub_module   => 'invoice',
731                                   trans_id     => $invoice_id,
732                                   configs      => $ic_cvar_configs,
733                                   variables    => $form,
734                                   name_prefix  => 'ic_',
735                                   name_postfix => "_$i",
736                                   dbh          => $dbh);
737     }
738   }
739
740   $form->{datepaid} = $form->{invdate};
741
742   # total payments, don't move we need it here
743   for my $i (1 .. $form->{paidaccounts}) {
744     if ($form->{type} eq "credit_note") {
745       $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"}) * -1;
746     } else {
747       $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
748     }
749     $form->{paid} += $form->{"paid_$i"};
750     $form->{datepaid} = $form->{"datepaid_$i"} if ($form->{"datepaid_$i"});
751   }
752
753   my ($tax, $diff) = (0, 0);
754
755   $netamount = $form->round_amount($netamount, 2);
756
757   # figure out rounding errors for total amount vs netamount + taxes
758   if ($form->{taxincluded}) {
759
760     $amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
761     $diff += $amount - $netamount * $form->{exchangerate};
762     $netamount = $amount;
763
764     foreach my $item (split(/ /, $form->{taxaccounts})) {
765       $amount = $form->{amount}{ $form->{id} }{$item} * $form->{exchangerate};
766       $form->{amount}{ $form->{id} }{$item} = $form->round_amount($amount, 2);
767       $tax += $form->{amount}{ $form->{id} }{$item};
768       $netamount -= $form->{amount}{ $form->{id} }{$item};
769     }
770
771     $invoicediff += $diff;
772     ######## this only applies to tax included
773     if ($lastincomeaccno) {
774       $form->{amount}{ $form->{id} }{$lastincomeaccno} += $invoicediff;
775     }
776
777   } else {
778     $amount    = $form->round_amount($netamount * $form->{exchangerate}, 2);
779     $diff      = $amount - $netamount * $form->{exchangerate};
780     $netamount = $amount;
781     foreach my $item (split(/ /, $form->{taxaccounts})) {
782       $form->{amount}{ $form->{id} }{$item} =
783         $form->round_amount($form->{amount}{ $form->{id} }{$item}, 2);
784       $amount =
785         $form->round_amount(
786                  $form->{amount}{ $form->{id} }{$item} * $form->{exchangerate},
787                  2);
788       $diff +=
789         $amount - $form->{amount}{ $form->{id} }{$item} *
790         $form->{exchangerate};
791       $form->{amount}{ $form->{id} }{$item} = $form->round_amount($amount, 2);
792       $tax += $form->{amount}{ $form->{id} }{$item};
793     }
794   }
795
796   $form->{amount}{ $form->{id} }{ $form->{AR} } = $netamount + $tax;
797   $form->{paid} =
798     $form->round_amount($form->{paid} * $form->{exchangerate} + $diff, 2);
799
800   # reverse AR
801   $form->{amount}{ $form->{id} }{ $form->{AR} } *= -1;
802
803   # update exchangerate
804   if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
805     $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate},
806                                $form->{exchangerate}, 0);
807   }
808
809   $project_id = conv_i($form->{"globalproject_id"});
810
811   foreach my $trans_id (keys %{ $form->{amount_cogs} }) {
812     foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
813       next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
814
815       $form->{amount_cogs}{$trans_id}{$accno} = $form->round_amount($form->{amount_cogs}{$trans_id}{$accno}, 2);
816
817       if (!$payments_only && ($form->{amount_cogs}{$trans_id}{$accno} != 0)) {
818         $query =
819           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
820                VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, 0, ?)|;
821         @values = (conv_i($trans_id), $accno, $form->{amount_cogs}{$trans_id}{$accno}, conv_date($form->{invdate}), conv_i($project_id));
822         do_query($form, $dbh, $query, @values);
823         $form->{amount_cogs}{$trans_id}{$accno} = 0;
824       }
825     }
826
827     foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
828       $form->{amount_cogs}{$trans_id}{$accno} = $form->round_amount($form->{amount_cogs}{$trans_id}{$accno}, 2);
829
830       if (!$payments_only && ($form->{amount_cogs}{$trans_id}{$accno} != 0)) {
831         $query =
832           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
833                VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, 0, ?)|;
834         @values = (conv_i($trans_id), $accno, $form->{amount_cogs}{$trans_id}{$accno}, conv_date($form->{invdate}), conv_i($project_id));
835         do_query($form, $dbh, $query, @values);
836       }
837     }
838   }
839
840   foreach my $trans_id (keys %{ $form->{amount} }) {
841     foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
842       next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
843
844       $form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2);
845
846       if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
847         $query =
848           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
849              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
850                      (SELECT taxkey_id  FROM chart WHERE accno = ?), ?)|;
851         @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_i($project_id));
852         do_query($form, $dbh, $query, @values);
853         $form->{amount}{$trans_id}{$accno} = 0;
854       }
855     }
856
857     foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
858       $form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2);
859
860       if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
861         $query =
862           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
863              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
864                      (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
865         @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_i($project_id));
866         do_query($form, $dbh, $query, @values);
867       }
868     }
869   }
870
871   # deduct payment differences from diff
872   for my $i (1 .. $form->{paidaccounts}) {
873     if ($form->{"paid_$i"} != 0) {
874       $amount =
875         $form->round_amount($form->{"paid_$i"} * $form->{exchangerate}, 2);
876       $diff -= $amount - $form->{"paid_$i"} * $form->{exchangerate};
877     }
878   }
879
880   # record payments and offsetting AR
881   if (!$form->{storno}) {
882     for my $i (1 .. $form->{paidaccounts}) {
883
884       next if ($form->{"paid_$i"} == 0);
885
886       my ($accno) = split(/--/, $form->{"AR_paid_$i"});
887       $form->{"datepaid_$i"} = $form->{invdate}
888       unless ($form->{"datepaid_$i"});
889       $form->{datepaid} = $form->{"datepaid_$i"};
890
891       $exchangerate = 0;
892
893       if ($form->{currency} eq $defaultcurrency) {
894         $form->{"exchangerate_$i"} = 1;
895       } else {
896         $exchangerate              = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy');
897         $form->{"exchangerate_$i"} = $exchangerate || $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
898       }
899
900       # record AR
901       $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $diff, 2);
902
903       if ($form->{amount}{ $form->{id} }{ $form->{AR} } != 0) {
904         $query =
905         qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
906            VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
907                    (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
908         @values = (conv_i($form->{"id"}), $form->{AR}, $amount, $form->{"datepaid_$i"}, $form->{AR}, $project_id);
909         do_query($form, $dbh, $query, @values);
910       }
911
912       # record payment
913       $form->{"paid_$i"} *= -1;
914
915       $query =
916       qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, source, memo, taxkey, project_id)
917          VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, ?, ?,
918                  (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
919       @values = (conv_i($form->{"id"}), $accno, $form->{"paid_$i"}, $form->{"datepaid_$i"},
920                  $form->{"source_$i"}, $form->{"memo_$i"}, $accno, $project_id);
921       do_query($form, $dbh, $query, @values);
922
923       # exchangerate difference
924       $form->{fx}{$accno}{ $form->{"datepaid_$i"} } +=
925       $form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $diff;
926
927       # gain/loss
928       $amount =
929       $form->{"paid_$i"} * $form->{exchangerate} - $form->{"paid_$i"} *
930       $form->{"exchangerate_$i"};
931       if ($amount > 0) {
932         $form->{fx}{ $form->{fxgain_accno} }{ $form->{"datepaid_$i"} } +=
933         $amount;
934       } else {
935         $form->{fx}{ $form->{fxloss_accno} }{ $form->{"datepaid_$i"} } +=
936         $amount;
937       }
938
939       $diff = 0;
940
941       # update exchange rate
942       if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
943         $form->update_exchangerate($dbh, $form->{currency},
944                                    $form->{"datepaid_$i"},
945                                    $form->{"exchangerate_$i"}, 0);
946       }
947     }
948
949   } else {                      # if (!$form->{storno})
950     $form->{marge_total} *= -1;
951   }
952
953   if ($payments_only) {
954     $query = qq|UPDATE ar SET paid = ?, datepaid = ? WHERE id = ?|;
955     do_query($form, $dbh, $query,  $form->{paid}, $form->{paid} ? conv_date($form->{datepaid}) : undef, conv_i($form->{id}));
956
957     if (!$provided_dbh) {
958       $dbh->commit();
959       $dbh->disconnect();
960     }
961
962     $main::lxdebug->leave_sub();
963     return;
964   }
965
966   # record exchange rate differences and gains/losses
967   foreach my $accno (keys %{ $form->{fx} }) {
968     foreach my $transdate (keys %{ $form->{fx}{$accno} }) {
969       if (
970           ($form->{fx}{$accno}{$transdate} =
971            $form->round_amount($form->{fx}{$accno}{$transdate}, 2)
972           ) != 0
973         ) {
974
975         $query =
976           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, cleared, fx_transaction, taxkey, project_id)
977              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, '0', '1',
978              (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
979         @values = (conv_i($form->{"id"}), $accno, $form->{fx}{$accno}{$transdate}, conv_date($transdate), $accno, $project_id);
980         do_query($form, $dbh, $query, @values);
981       }
982     }
983   }
984
985   $amount = $netamount + $tax;
986
987   # save AR record
988   #erweiterung fuer lieferscheinnummer (donumber) 12.02.09 jb
989
990   $query = qq|UPDATE ar set
991                 invnumber   = ?, ordnumber     = ?, quonumber     = ?, cusordnumber  = ?,
992                 transdate   = ?, orddate       = ?, quodate       = ?, customer_id   = ?,
993                 amount      = ?, netamount     = ?, paid          = ?, datepaid      = ?,
994                 duedate     = ?, deliverydate  = ?, invoice       = ?, shippingpoint = ?,
995                 shipvia     = ?, terms         = ?, notes         = ?, intnotes      = ?,
996                 curr        = ?, department_id = ?, payment_id    = ?, taxincluded   = ?,
997                 type        = ?, language_id   = ?, taxzone_id    = ?, shipto_id     = ?,
998                 employee_id = ?, salesman_id   = ?, storno_id     = ?, storno        = ?,
999                 cp_id       = ?, marge_total   = ?, marge_percent = ?,
1000                 globalproject_id               = ?, delivery_customer_id             = ?,
1001                 transaction_description        = ?, delivery_vendor_id               = ?,
1002                 donumber    = ?
1003               WHERE id = ?|;
1004   @values = (          $form->{"invnumber"},           $form->{"ordnumber"},             $form->{"quonumber"},          $form->{"cusordnumber"},
1005              conv_date($form->{"invdate"}),  conv_date($form->{"orddate"}),    conv_date($form->{"quodate"}),    conv_i($form->{"customer_id"}),
1006                        $amount,                        $netamount,                       $form->{"paid"},     conv_date($form->{"datepaid"}),
1007              conv_date($form->{"duedate"}),  conv_date($form->{"deliverydate"}),    '1',                                $form->{"shippingpoint"},
1008                        $form->{"shipvia"},      conv_i($form->{"terms"}),                $form->{"notes"},              $form->{"intnotes"},
1009                        $form->{"currency"},     conv_i($form->{"department_id"}), conv_i($form->{"payment_id"}),        $form->{"taxincluded"} ? 't' : 'f',
1010                        $form->{"type"},         conv_i($form->{"language_id"}),   conv_i($form->{"taxzone_id"}), conv_i($form->{"shipto_id"}),
1011                 conv_i($form->{"employee_id"}), conv_i($form->{"salesman_id"}),   conv_i($form->{storno_id}),           $form->{"storno"} ? 't' : 'f',
1012                 conv_i($form->{"cp_id"}),            1 * $form->{marge_total} ,      1 * $form->{marge_percent},
1013                 conv_i($form->{"globalproject_id"}),                              conv_i($form->{"delivery_customer_id"}),
1014                        $form->{transaction_description},                          conv_i($form->{"delivery_vendor_id"}),
1015                        $form->{"donumber"}, #das entsprechende feld lieferscheinnummer aus der html-form 12.02.09 jb
1016                 conv_i($form->{"id"}));
1017   do_query($form, $dbh, $query, @values);
1018
1019   if($form->{"formname"} eq "credit_note") {
1020     for my $i (1 .. $form->{rowcount}) {
1021       $query = qq|UPDATE parts SET onhand = onhand - ? WHERE id = ?|;
1022       @values = (conv_i($form->{"qty_$i"}), conv_i($form->{"id_$i"}));
1023       do_query($form, $dbh, $query, @values);
1024     }
1025   }
1026
1027   if ($form->{storno}) {
1028     $query =
1029       qq!UPDATE ar SET
1030            paid = paid + amount,
1031            storno = 't',
1032            intnotes = ? || intnotes
1033          WHERE id = ?!;
1034     do_query($form, $dbh, $query, "Rechnung storniert am $form->{invdate} ", conv_i($form->{"storno_id"}));
1035     do_query($form, $dbh, qq|UPDATE ar SET paid = amount WHERE id = ?|, conv_i($form->{"id"}));
1036   }
1037
1038   # add shipto
1039   $form->{name} = $form->{customer};
1040   $form->{name} =~ s/--\Q$form->{customer_id}\E//;
1041
1042   if (!$form->{shipto_id}) {
1043     $form->add_shipto($dbh, $form->{id}, "AR");
1044   }
1045
1046   # save printed, emailed and queued
1047   $form->save_status($dbh);
1048
1049   Common::webdav_folder($form) if ($main::webdav);
1050
1051   # Link this record to the records it was created from.
1052   RecordLinks->create_links('dbh'        => $dbh,
1053                             'mode'       => 'ids',
1054                             'from_table' => 'oe',
1055                             'from_ids'   => $form->{convert_from_oe_ids},
1056                             'to_table'   => 'ar',
1057                             'to_id'      => $form->{id},
1058     );
1059   delete $form->{convert_from_oe_ids};
1060
1061   my @convert_from_do_ids = map { $_ * 1 } grep { $_ } split m/\s+/, $form->{convert_from_do_ids};
1062
1063   if (scalar @convert_from_do_ids) {
1064     DO->close_orders('dbh' => $dbh,
1065                      'ids' => \@convert_from_do_ids);
1066
1067     RecordLinks->create_links('dbh'        => $dbh,
1068                               'mode'       => 'ids',
1069                               'from_table' => 'delivery_orders',
1070                               'from_ids'   => \@convert_from_do_ids,
1071                               'to_table'   => 'ar',
1072                               'to_id'      => $form->{id},
1073       );
1074   }
1075   delete $form->{convert_from_do_ids};
1076
1077   ARAP->close_orders_if_billed('dbh'     => $dbh,
1078                                'arap_id' => $form->{id},
1079                                'table'   => 'ar',);
1080
1081   my $rc = 1;
1082   if (!$provided_dbh) {
1083     $dbh->commit();
1084     $dbh->disconnect();
1085   }
1086
1087   $main::lxdebug->leave_sub();
1088
1089   return $rc;
1090 }
1091
1092 sub _delete_payments {
1093   $main::lxdebug->enter_sub();
1094
1095   my ($self, $form, $dbh) = @_;
1096
1097   my @delete_acc_trans_ids;
1098
1099   # Delete old payment entries from acc_trans.
1100   my $query =
1101     qq|SELECT acc_trans_id
1102        FROM acc_trans
1103        WHERE (trans_id = ?) AND fx_transaction
1104
1105        UNION
1106
1107        SELECT at.acc_trans_id
1108        FROM acc_trans at
1109        LEFT JOIN chart c ON (at.chart_id = c.id)
1110        WHERE (trans_id = ?) AND (c.link LIKE '%AR_paid%')|;
1111   push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}), conv_i($form->{id}));
1112
1113   $query =
1114     qq|SELECT at.acc_trans_id
1115        FROM acc_trans at
1116        LEFT JOIN chart c ON (at.chart_id = c.id)
1117        WHERE (trans_id = ?)
1118          AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
1119        ORDER BY at.acc_trans_id
1120        OFFSET 1|;
1121   push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}));
1122
1123   if (@delete_acc_trans_ids) {
1124     $query = qq|DELETE FROM acc_trans WHERE acc_trans_id IN (| . join(", ", @delete_acc_trans_ids) . qq|)|;
1125     do_query($form, $dbh, $query);
1126   }
1127
1128   $main::lxdebug->leave_sub();
1129 }
1130
1131 sub post_payment {
1132   $main::lxdebug->enter_sub();
1133
1134   my ($self, $myconfig, $form, $locale) = @_;
1135
1136   # connect to database, turn off autocommit
1137   my $dbh = $form->dbconnect_noauto($myconfig);
1138
1139   my (%payments, $old_form, $row, $item, $query, %keep_vars);
1140
1141   $old_form = save_form();
1142
1143   # Delete all entries in acc_trans from prior payments.
1144   $self->_delete_payments($form, $dbh);
1145
1146   # Save the new payments the user made before cleaning up $form.
1147   map { $payments{$_} = $form->{$_} } grep m/^datepaid_\d+$|^memo_\d+$|^source_\d+$|^exchangerate_\d+$|^paid_\d+$|^AR_paid_\d+$|^paidaccounts$/, keys %{ $form };
1148
1149   # Clean up $form so that old content won't tamper the results.
1150   %keep_vars = map { $_, 1 } qw(login password id);
1151   map { delete $form->{$_} unless $keep_vars{$_} } keys %{ $form };
1152
1153   # Retrieve the invoice from the database.
1154   $self->retrieve_invoice($myconfig, $form);
1155
1156   # Set up the content of $form in the way that IS::post_invoice() expects.
1157   $form->{exchangerate} = $form->format_amount($myconfig, $form->{exchangerate});
1158
1159   for $row (1 .. scalar @{ $form->{invoice_details} }) {
1160     $item = $form->{invoice_details}->[$row - 1];
1161
1162     map { $item->{$_} = $form->format_amount($myconfig, $item->{$_}) } qw(qty sellprice discount);
1163
1164     map { $form->{"${_}_${row}"} = $item->{$_} } keys %{ $item };
1165   }
1166
1167   $form->{rowcount} = scalar @{ $form->{invoice_details} };
1168
1169   delete @{$form}{qw(invoice_details paidaccounts storno paid)};
1170
1171   # Restore the payment options from the user input.
1172   map { $form->{$_} = $payments{$_} } keys %payments;
1173
1174   # Get the AR accno (which is normally done by Form::create_links()).
1175   $query =
1176     qq|SELECT c.accno
1177        FROM acc_trans at
1178        LEFT JOIN chart c ON (at.chart_id = c.id)
1179        WHERE (trans_id = ?)
1180          AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
1181        ORDER BY at.acc_trans_id
1182        LIMIT 1|;
1183
1184   ($form->{AR}) = selectfirst_array_query($form, $dbh, $query, conv_i($form->{id}));
1185
1186   # Post the new payments.
1187   $self->post_invoice($myconfig, $form, $dbh, 1);
1188
1189   restore_form($old_form);
1190
1191   my $rc = $dbh->commit();
1192   $dbh->disconnect();
1193
1194   $main::lxdebug->leave_sub();
1195
1196   return $rc;
1197 }
1198
1199 sub process_assembly {
1200   $main::lxdebug->enter_sub();
1201
1202   my ($dbh, $form, $id, $totalqty) = @_;
1203
1204   my $query =
1205     qq|SELECT a.parts_id, a.qty, p.assembly, p.partnumber, p.description, p.unit,
1206          p.inventory_accno_id, p.income_accno_id, p.expense_accno_id
1207        FROM assembly a
1208        JOIN parts p ON (a.parts_id = p.id)
1209        WHERE (a.id = ?)|;
1210   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
1211
1212   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
1213
1214     my $allocated = 0;
1215
1216     $ref->{inventory_accno_id} *= 1;
1217     $ref->{expense_accno_id}   *= 1;
1218
1219     # multiply by number of assemblies
1220     $ref->{qty} *= $totalqty;
1221
1222     if ($ref->{assembly}) {
1223       &process_assembly($dbh, $form, $ref->{parts_id}, $ref->{qty});
1224       next;
1225     } else {
1226       if ($ref->{inventory_accno_id}) {
1227         $allocated = &cogs($dbh, $form, $ref->{parts_id}, $ref->{qty});
1228       }
1229     }
1230
1231     # save detail record for individual assembly item in invoice table
1232     $query =
1233       qq|INSERT INTO invoice (trans_id, description, parts_id, qty, sellprice, fxsellprice, allocated, assemblyitem, unit)
1234          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)|;
1235     my @values = (conv_i($form->{id}), $ref->{description}, conv_i($ref->{parts_id}), $ref->{qty}, 0, 0, $allocated, 't', $ref->{unit});
1236     do_query($form, $dbh, $query, @values);
1237
1238   }
1239
1240   $sth->finish;
1241
1242   $main::lxdebug->leave_sub();
1243 }
1244
1245 sub cogs {
1246   $main::lxdebug->enter_sub();
1247
1248   my ($dbh, $form, $id, $totalqty, $basefactor, $row) = @_;
1249
1250   $basefactor ||= 1;
1251
1252   $form->{taxzone_id} *=1;
1253   my $transdate  = $form->{invdate} ? $dbh->quote($form->{invdate}) : "current_date";
1254   my $taxzone_id = $form->{"taxzone_id"} * 1;
1255   my $query =
1256     qq|SELECT i.id, i.trans_id, i.base_qty, i.allocated, i.sellprice,
1257          c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
1258          c2.accno AS    income_accno, c2.new_chart_id AS    income_new_chart, date($transdate) - c2.valid_from AS    income_valid,
1259          c3.accno AS   expense_accno, c3.new_chart_id AS   expense_new_chart, date($transdate) - c3.valid_from AS   expense_valid
1260        FROM invoice i, parts p
1261        LEFT JOIN chart c1 ON ((SELECT inventory_accno_id FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
1262        LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
1263        LEFT JOIN chart c3 ON ((select expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
1264        WHERE (i.parts_id = p.id)
1265          AND (i.parts_id = ?)
1266          AND ((i.base_qty + i.allocated) < 0)
1267        ORDER BY trans_id|;
1268   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
1269
1270   my $allocated = 0;
1271   my $qty;
1272
1273   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
1274     if (($qty = (($ref->{base_qty} * -1) - $ref->{allocated})) > $totalqty) {
1275       $qty = $totalqty;
1276     }
1277
1278     $form->update_balance($dbh, "invoice", "allocated", qq|id = $ref->{id}|, $qty);
1279
1280     # total expenses and inventory
1281     # sellprice is the cost of the item
1282     my $linetotal = $form->round_amount(($ref->{sellprice} * $qty) / ( $basefactor || 1 ), 2);
1283
1284     if (!$main::eur) {
1285       $ref->{expense_accno} = ($form->{"expense_accno_$row"}) ? $form->{"expense_accno_$row"} : $ref->{expense_accno};
1286       # add to expense
1287       $form->{amount_cogs}{ $form->{id} }{ $ref->{expense_accno} } += -$linetotal;
1288       $form->{expense_inventory} .= " " . $ref->{expense_accno};
1289       $ref->{inventory_accno} = ($form->{"inventory_accno_$row"}) ? $form->{"inventory_accno_$row"} : $ref->{inventory_accno};
1290       # deduct inventory
1291       $form->{amount_cogs}{ $form->{id} }{ $ref->{inventory_accno} } -= -$linetotal;
1292       $form->{expense_inventory} .= " " . $ref->{inventory_accno};
1293     }
1294
1295     # add allocated
1296     $allocated -= $qty;
1297
1298     last if (($totalqty -= $qty) <= 0);
1299   }
1300
1301   $sth->finish;
1302
1303   $main::lxdebug->leave_sub();
1304
1305   return $allocated;
1306 }
1307
1308 sub reverse_invoice {
1309   $main::lxdebug->enter_sub();
1310
1311   my ($dbh, $form) = @_;
1312
1313   # reverse inventory items
1314   my $query =
1315     qq|SELECT i.id, i.parts_id, i.qty, i.assemblyitem, p.assembly, p.inventory_accno_id
1316        FROM invoice i
1317        JOIN parts p ON (i.parts_id = p.id)
1318        WHERE i.trans_id = ?|;
1319   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id"}));
1320
1321   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
1322
1323     if ($ref->{inventory_accno_id}) {
1324       # de-allocated purchases
1325       $query =
1326         qq|SELECT i.id, i.trans_id, i.allocated
1327            FROM invoice i
1328            WHERE (i.parts_id = ?) AND (i.allocated > 0)
1329            ORDER BY i.trans_id DESC|;
1330       my $sth2 = prepare_execute_query($form, $dbh, $query, conv_i($ref->{"parts_id"}));
1331
1332       while (my $inhref = $sth2->fetchrow_hashref('NAME_lc')) {
1333         my $qty = $ref->{qty};
1334         if (($ref->{qty} - $inhref->{allocated}) > 0) {
1335           $qty = $inhref->{allocated};
1336         }
1337
1338         # update invoice
1339         $form->update_balance($dbh, "invoice", "allocated", qq|id = $inhref->{id}|, $qty * -1);
1340
1341         last if (($ref->{qty} -= $qty) <= 0);
1342       }
1343       $sth2->finish;
1344     }
1345   }
1346
1347   $sth->finish;
1348
1349   # delete acc_trans
1350   my @values = (conv_i($form->{id}));
1351   do_query($form, $dbh, qq|DELETE FROM acc_trans WHERE trans_id = ?|, @values);
1352   do_query($form, $dbh, qq|DELETE FROM invoice WHERE trans_id = ?|, @values);
1353
1354   if ($form->{lizenzen}) {
1355     $query =
1356       qq|DELETE FROM licenseinvoice
1357          WHERE trans_id in (SELECT id FROM invoice WHERE trans_id = ?)|;
1358     do_query($form, $dbh, $query, @values);
1359   }
1360
1361   do_query($form, $dbh, qq|DELETE FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|, @values);
1362
1363   $main::lxdebug->leave_sub();
1364 }
1365
1366 sub delete_invoice {
1367   $main::lxdebug->enter_sub();
1368
1369   my ($self, $myconfig, $form, $spool) = @_;
1370
1371   # connect to database
1372   my $dbh = $form->dbconnect_noauto($myconfig);
1373
1374   &reverse_invoice($dbh, $form);
1375
1376   my @values = (conv_i($form->{id}));
1377
1378   # delete AR record
1379   do_query($form, $dbh, qq|DELETE FROM ar WHERE id = ?|, @values);
1380
1381   # delete spool files
1382   my @spoolfiles = selectall_array_query($form, $dbh, qq|SELECT spoolfile FROM status WHERE trans_id = ?|, @values);
1383
1384   # delete status entries
1385   do_query($form, $dbh, qq|DELETE FROM status WHERE trans_id = ?|, @values);
1386
1387   my $rc = $dbh->commit;
1388   $dbh->disconnect;
1389
1390   if ($rc) {
1391     map { unlink "$spool/$_" if -f "$spool/$_"; } @spoolfiles;
1392   }
1393
1394   $main::lxdebug->leave_sub();
1395
1396   return $rc;
1397 }
1398
1399 sub retrieve_invoice {
1400   $main::lxdebug->enter_sub();
1401
1402   my ($self, $myconfig, $form) = @_;
1403
1404   # connect to database
1405   my $dbh = $form->dbconnect_noauto($myconfig);
1406
1407   my ($sth, $ref, $query);
1408
1409   my $query_transdate = ", current_date AS invdate" if !$form->{id};
1410
1411   $query =
1412     qq|SELECT
1413          (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
1414          (SELECT c.accno FROM chart c WHERE d.income_accno_id = c.id)    AS income_accno,
1415          (SELECT c.accno FROM chart c WHERE d.expense_accno_id = c.id)   AS expense_accno,
1416          (SELECT c.accno FROM chart c WHERE d.fxgain_accno_id = c.id)    AS fxgain_accno,
1417          (SELECT c.accno FROM chart c WHERE d.fxloss_accno_id = c.id)    AS fxloss_accno,
1418          d.curr AS currencies
1419          ${query_transdate}
1420        FROM defaults d|;
1421
1422   $ref = selectfirst_hashref_query($form, $dbh, $query);
1423   map { $form->{$_} = $ref->{$_} } keys %{ $ref };
1424
1425   if ($form->{id}) {
1426     my $id = conv_i($form->{id});
1427
1428     # retrieve invoice
1429     #erweiterung um das entsprechende feld lieferscheinnummer (a.donumber) in der html-maske anzuzeigen 12.02.2009 jb
1430
1431     $query =
1432       qq|SELECT
1433            a.invnumber, a.ordnumber, a.quonumber, a.cusordnumber,
1434            a.orddate, a.quodate, a.globalproject_id,
1435            a.transdate AS invdate, a.deliverydate, a.paid, a.storno, a.gldate,
1436            a.shippingpoint, a.shipvia, a.terms, a.notes, a.intnotes, a.taxzone_id,
1437            a.duedate, a.taxincluded, a.curr AS currency, a.shipto_id, a.cp_id,
1438            a.employee_id, a.salesman_id, a.payment_id,
1439            a.language_id, a.delivery_customer_id, a.delivery_vendor_id, a.type,
1440            a.transaction_description,
1441            a.marge_total, a.marge_percent,
1442            e.name AS employee, a.donumber
1443          FROM ar a
1444          LEFT JOIN employee e ON (e.id = a.employee_id)
1445          WHERE a.id = ?|;
1446     $ref = selectfirst_hashref_query($form, $dbh, $query, $id);
1447     map { $form->{$_} = $ref->{$_} } keys %{ $ref };
1448
1449
1450     $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "buy");
1451
1452     # get shipto
1453     $query = qq|SELECT * FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|;
1454     $ref = selectfirst_hashref_query($form, $dbh, $query, $id);
1455     delete $ref->{id};
1456     map { $form->{$_} = $ref->{$_} } keys %{ $ref };
1457
1458     foreach my $vc (qw(customer vendor)) {
1459       next if !$form->{"delivery_${vc}_id"};
1460       ($form->{"delivery_${vc}_string"}) = selectrow_query($form, $dbh, qq|SELECT name FROM customer WHERE id = ?|, $id);
1461     }
1462
1463     # get printed, emailed
1464     $query = qq|SELECT printed, emailed, spoolfile, formname FROM status WHERE trans_id = ?|;
1465     $sth = prepare_execute_query($form, $dbh, $query, $id);
1466
1467     while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
1468       $form->{printed} .= "$ref->{formname} " if $ref->{printed};
1469       $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
1470       $form->{queued} .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
1471     }
1472     $sth->finish;
1473     map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
1474
1475     my $transdate = $form->{deliverydate} ? $dbh->quote($form->{deliverydate})
1476                   : $form->{invdate}      ? $dbh->quote($form->{invdate})
1477                   :                         "current_date";
1478
1479
1480     my $taxzone_id = $form->{taxzone_id} *= 1;
1481     $taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
1482
1483     # retrieve individual items
1484     $query =
1485       qq|SELECT
1486            c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
1487            c2.accno AS income_accno,    c2.new_chart_id AS income_new_chart,    date($transdate) - c2.valid_from as income_valid,
1488            c3.accno AS expense_accno,   c3.new_chart_id AS expense_new_chart,   date($transdate) - c3.valid_from AS expense_valid,
1489
1490            i.id AS invoice_id,
1491            i.description, i.longdescription, i.qty, i.fxsellprice AS sellprice, i.discount, i.parts_id AS id, i.unit, i.deliverydate AS reqdate,
1492            i.project_id, i.serialnumber, i.id AS invoice_pos, i.pricegroup_id, i.ordnumber, i.transdate, i.cusordnumber, i.subtotal, i.lastcost,
1493            i.price_factor_id, i.price_factor, i.marge_price_factor,
1494            p.partnumber, p.assembly, p.bin, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id, p.formel,
1495            pr.projectnumber, pg.partsgroup, prg.pricegroup
1496
1497          FROM invoice i
1498          LEFT JOIN parts p ON (i.parts_id = p.id)
1499          LEFT JOIN project pr ON (i.project_id = pr.id)
1500          LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
1501          LEFT JOIN pricegroup prg ON (i.pricegroup_id = prg.id)
1502
1503          LEFT JOIN chart c1 ON ((SELECT inventory_accno_id             FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
1504          LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id}  FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
1505          LEFT JOIN chart c3 ON ((SELECT expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
1506
1507          WHERE (i.trans_id = ?) AND NOT (i.assemblyitem = '1') ORDER BY i.id|;
1508
1509     $sth = prepare_execute_query($form, $dbh, $query, $id);
1510
1511     while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
1512       # Retrieve custom variables.
1513       my $cvars = CVar->get_custom_variables(dbh        => $dbh,
1514                                              module     => 'IC',
1515                                              sub_module => 'invoice',
1516                                              trans_id   => $ref->{invoice_id},
1517                                             );
1518       map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
1519       delete $ref->{invoice_id};
1520
1521       map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid)) if !$ref->{"part_inventory_accno_id"};
1522       delete($ref->{"part_inventory_accno_id"});
1523
1524       foreach my $type (qw(inventory income expense)) {
1525         while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
1526           my $query = qq|SELECT accno, new_chart_id, date($transdate) - valid_from FROM chart WHERE id = ?|;
1527           @$ref{ map $type.$_, qw(_accno _new_chart _valid) } = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
1528         }
1529       }
1530
1531       # get tax rates and description
1532       my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
1533       $query =
1534         qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber FROM tax t
1535            LEFT JOIN chart c ON (c.id = t.chart_id)
1536            WHERE t.id IN
1537              (SELECT tk.tax_id FROM taxkeys tk
1538               WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?)
1539                 AND startdate <= date($transdate)
1540               ORDER BY startdate DESC LIMIT 1)
1541            ORDER BY c.accno|;
1542       my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
1543       $ref->{taxaccounts} = "";
1544       my $i=0;
1545       while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
1546
1547         if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
1548           $i++;
1549           $ptr->{accno} = $i;
1550         }
1551         $ref->{taxaccounts} .= "$ptr->{accno} ";
1552
1553         if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
1554           $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
1555           $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
1556           $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
1557           $form->{taxaccounts} .= "$ptr->{accno} ";
1558         }
1559
1560       }
1561
1562       if ($form->{lizenzen}) {
1563         $query = qq|SELECT l.licensenumber, l.id AS licenseid FROM license l, licenseinvoice li WHERE l.id = li.license_id AND li.trans_id = ?|;
1564         my ($licensenumber, $licenseid) = selectrow_query($form, $dbh, $query, conv_i($ref->{invoice_pos}));
1565         $ref->{lizenzen} = "<option value=\"$licenseid\">$licensenumber</option>";
1566       }
1567
1568       $ref->{qty} *= -1 if $form->{type} eq "credit_note";
1569
1570       chop $ref->{taxaccounts};
1571       push @{ $form->{invoice_details} }, $ref;
1572       $stw->finish;
1573     }
1574     $sth->finish;
1575
1576     Common::webdav_folder($form) if ($main::webdav);
1577   }
1578
1579   my $rc = $dbh->commit;
1580   $dbh->disconnect;
1581
1582   $main::lxdebug->leave_sub();
1583
1584   return $rc;
1585 }
1586
1587 sub get_customer {
1588   $main::lxdebug->enter_sub();
1589
1590   my ($self, $myconfig, $form) = @_;
1591
1592   # connect to database
1593   my $dbh = $form->dbconnect($myconfig);
1594
1595   my $dateformat = $myconfig->{dateformat};
1596   $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/;
1597
1598   my (@values, $duedate, $ref, $query);
1599
1600   if ($form->{invdate}) {
1601     $duedate = "to_date(?, '$dateformat')";
1602     push @values, $form->{invdate};
1603   } else {
1604     $duedate = "current_date";
1605   }
1606
1607   my $cid = conv_i($form->{customer_id});
1608   my $payment_id;
1609
1610   if ($form->{payment_id}) {
1611     $payment_id = "(pt.id = ?) OR";
1612     push @values, conv_i($form->{payment_id});
1613   }
1614
1615   # get customer
1616   $query =
1617     qq|SELECT
1618          c.id AS customer_id, c.name AS customer, c.discount as customer_discount, c.creditlimit, c.terms,
1619          c.email, c.cc, c.bcc, c.language_id, c.payment_id,
1620          c.street, c.zipcode, c.city, c.country,
1621          c.notes AS intnotes, c.klass as customer_klass, c.taxzone_id, c.salesman_id,
1622          $duedate + COALESCE(pt.terms_netto, 0) AS duedate,
1623          b.discount AS tradediscount, b.description AS business
1624        FROM customer c
1625        LEFT JOIN business b ON (b.id = c.business_id)
1626        LEFT JOIN payment_terms pt ON ($payment_id (c.payment_id = pt.id))
1627        WHERE c.id = ?|;
1628   push @values, $cid;
1629   $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
1630
1631   delete $ref->{salesman_id} if !$ref->{salesman_id};
1632
1633   map { $form->{$_} = $ref->{$_} } keys %$ref;
1634
1635   $query =
1636     qq|SELECT sum(amount - paid) AS dunning_amount
1637        FROM ar
1638        WHERE (paid < amount)
1639          AND (customer_id = ?)
1640          AND (dunning_config_id IS NOT NULL)|;
1641   $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
1642   map { $form->{$_} = $ref->{$_} } keys %$ref;
1643
1644   $query =
1645     qq|SELECT dnn.dunning_description AS max_dunning_level
1646        FROM dunning_config dnn
1647        WHERE id IN (SELECT dunning_config_id
1648                     FROM ar
1649                     WHERE (paid < amount) AND (customer_id = ?) AND (dunning_config_id IS NOT NULL))
1650        ORDER BY dunning_level DESC LIMIT 1|;
1651   $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
1652   map { $form->{$_} = $ref->{$_} } keys %$ref;
1653
1654   $form->{creditremaining} = $form->{creditlimit};
1655   $query = qq|SELECT SUM(amount - paid) FROM ar WHERE customer_id = ?|;
1656   my ($value) = selectrow_query($form, $dbh, $query, $cid);
1657   $form->{creditremaining} -= $value;
1658
1659   $query =
1660     qq|SELECT o.amount,
1661          (SELECT e.buy FROM exchangerate e
1662           WHERE e.curr = o.curr
1663             AND e.transdate = o.transdate)
1664        FROM oe o
1665        WHERE o.customer_id = ?
1666          AND o.quotation = '0'
1667          AND o.closed = '0'|;
1668   my $sth = prepare_execute_query($form, $dbh, $query, $cid);
1669
1670   while (my ($amount, $exch) = $sth->fetchrow_array) {
1671     $exch = 1 unless $exch;
1672     $form->{creditremaining} -= $amount * $exch;
1673   }
1674   $sth->finish;
1675
1676   # get shipto if we did not converted an order or invoice
1677   if (!$form->{shipto}) {
1678     map { delete $form->{$_} }
1679       qw(shiptoname shiptodepartment_1 shiptodepartment_2
1680          shiptostreet shiptozipcode shiptocity shiptocountry
1681          shiptocontact shiptophone shiptofax shiptoemail);
1682
1683     $query = qq|SELECT * FROM shipto WHERE trans_id = ? AND module = 'CT'|;
1684     $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
1685     delete $ref->{id};
1686     map { $form->{$_} = $ref->{$_} } keys %$ref;
1687   }
1688
1689   # setup last accounts used for this customer
1690   if (!$form->{id} && $form->{type} !~ /_(order|quotation)/) {
1691     $query =
1692       qq|SELECT c.id, c.accno, c.description, c.link, c.category
1693          FROM chart c
1694          JOIN acc_trans ac ON (ac.chart_id = c.id)
1695          JOIN ar a ON (a.id = ac.trans_id)
1696          WHERE a.customer_id = ?
1697            AND NOT (c.link LIKE '%_tax%' OR c.link LIKE '%_paid%')
1698            AND a.id IN (SELECT max(a2.id) FROM ar a2 WHERE a2.customer_id = ?)|;
1699     $sth = prepare_execute_query($form, $dbh, $query, $cid, $cid);
1700
1701     my $i = 0;
1702     while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
1703       if ($ref->{category} eq 'I') {
1704         $i++;
1705         $form->{"AR_amount_$i"} = "$ref->{accno}--$ref->{description}";
1706
1707         if ($form->{initial_transdate}) {
1708           my $tax_query =
1709             qq|SELECT tk.tax_id, t.rate
1710                FROM taxkeys tk
1711                LEFT JOIN tax t ON tk.tax_id = t.id
1712                WHERE (tk.chart_id = ?) AND (startdate <= date(?))
1713                ORDER BY tk.startdate DESC
1714                LIMIT 1|;
1715           my ($tax_id, $rate) =
1716             selectrow_query($form, $dbh, $tax_query, $ref->{id},
1717                             $form->{initial_transdate});
1718           $form->{"taxchart_$i"} = "${tax_id}--${rate}";
1719         }
1720       }
1721       if ($ref->{category} eq 'A') {
1722         $form->{ARselected} = $form->{AR_1} = $ref->{accno};
1723       }
1724     }
1725     $sth->finish;
1726     $form->{rowcount} = $i if ($i && !$form->{type});
1727   }
1728
1729   $dbh->disconnect;
1730
1731   $main::lxdebug->leave_sub();
1732 }
1733
1734 sub retrieve_item {
1735   $main::lxdebug->enter_sub();
1736
1737   my ($self, $myconfig, $form) = @_;
1738
1739   # connect to database
1740   my $dbh = $form->dbconnect($myconfig);
1741
1742   my $i = $form->{rowcount};
1743
1744   my $where = qq|NOT p.obsolete = '1'|;
1745   my @values;
1746
1747   foreach my $column (qw(p.partnumber p.description pgpartsgroup )) {
1748     my ($table, $field) = split m/\./, $column;
1749     next if !$form->{"${field}_${i}"};
1750     $where .= qq| AND lower(${column}) ILIKE ?|;
1751     push @values, '%' . $form->{"${field}_${i}"} . '%';
1752   }
1753
1754   #Es soll auch nach EAN gesucht werden, ohne Einschränkung durch Beschreibung
1755   if ($form->{"partnumber_$i"} && !$form->{"description_$i"}) {
1756         $where .= qq| OR (NOT p.obsolete = '1' AND p.ean = ? )|;
1757         push @values, $form->{"partnumber_$i"};
1758   }
1759
1760   if ($form->{"description_$i"}) {
1761     $where .= qq| ORDER BY p.description|;
1762   } else {
1763     $where .= qq| ORDER BY p.partnumber|;
1764   }
1765
1766   my $transdate;
1767   if ($form->{type} eq "invoice") {
1768     $transdate =
1769       $form->{deliverydate} ? $dbh->quote($form->{deliverydate}) :
1770       $form->{invdate}      ? $dbh->quote($form->{invdate}) :
1771                               "current_date";
1772   } else {
1773     $transdate =
1774       $form->{transdate}    ? $dbh->quote($form->{transdate}) :
1775                               "current_date";
1776   }
1777
1778   my $taxzone_id = $form->{taxzone_id} * 1;
1779   $taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
1780
1781   my $query =
1782     qq|SELECT
1783          p.id, p.partnumber, p.description, p.sellprice,
1784          p.listprice, p.inventory_accno_id, p.lastcost,
1785
1786          c1.accno AS inventory_accno,
1787          c1.new_chart_id AS inventory_new_chart,
1788          date($transdate) - c1.valid_from AS inventory_valid,
1789
1790          c2.accno AS income_accno,
1791          c2.new_chart_id AS income_new_chart,
1792          date($transdate)  - c2.valid_from AS income_valid,
1793
1794          c3.accno AS expense_accno,
1795          c3.new_chart_id AS expense_new_chart,
1796          date($transdate) - c3.valid_from AS expense_valid,
1797
1798          p.unit, p.assembly, p.bin, p.onhand,
1799          p.notes AS partnotes, p.notes AS longdescription,
1800          p.not_discountable, p.formel, p.payment_id AS part_payment_id,
1801          p.price_factor_id,
1802
1803          pfac.factor AS price_factor,
1804
1805          pg.partsgroup
1806
1807        FROM parts p
1808        LEFT JOIN chart c1 ON
1809          ((SELECT inventory_accno_id
1810            FROM buchungsgruppen
1811            WHERE id = p.buchungsgruppen_id) = c1.id)
1812        LEFT JOIN chart c2 ON
1813          ((SELECT income_accno_id_${taxzone_id}
1814            FROM buchungsgruppen
1815            WHERE id = p.buchungsgruppen_id) = c2.id)
1816        LEFT JOIN chart c3 ON
1817          ((SELECT expense_accno_id_${taxzone_id}
1818            FROM buchungsgruppen
1819            WHERE id = p.buchungsgruppen_id) = c3.id)
1820        LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
1821        LEFT JOIN price_factors pfac ON (pfac.id = p.price_factor_id)
1822        WHERE $where|;
1823   my $sth = prepare_execute_query($form, $dbh, $query, @values);
1824
1825   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
1826
1827     # In der Buchungsgruppe ist immer ein Bestandskonto verknuepft, auch wenn
1828     # es sich um eine Dienstleistung handelt. Bei Dienstleistungen muss das
1829     # Buchungskonto also aus dem Ergebnis rausgenommen werden.
1830     if (!$ref->{inventory_accno_id}) {
1831       map({ delete($ref->{"inventory_${_}"}); } qw(accno new_chart valid));
1832     }
1833     delete($ref->{inventory_accno_id});
1834
1835     foreach my $type (qw(inventory income expense)) {
1836       while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
1837         my $query =
1838           qq|SELECT accno, new_chart_id, date($transdate) - valid_from
1839              FROM chart
1840              WHERE id = ?|;
1841         ($ref->{"${type}_accno"},
1842          $ref->{"${type}_new_chart"},
1843          $ref->{"${type}_valid"})
1844           = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
1845       }
1846     }
1847
1848     if ($form->{payment_id} eq "") {
1849       $form->{payment_id} = $form->{part_payment_id};
1850     }
1851
1852     # get tax rates and description
1853     my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
1854     $query =
1855       qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber
1856          FROM tax t
1857          LEFT JOIN chart c ON (c.id = t.chart_id)
1858          WHERE t.id in
1859            (SELECT tk.tax_id
1860             FROM taxkeys tk
1861             WHERE tk.chart_id = (SELECT id from chart WHERE accno = ?)
1862               AND startdate <= ?
1863             ORDER BY startdate DESC
1864             LIMIT 1)
1865          ORDER BY c.accno|;
1866     @values = ($accno_id, $transdate eq "current_date" ? "now" : $transdate);
1867     my $stw = $dbh->prepare($query);
1868     $stw->execute(@values) || $form->dberror($query);
1869
1870     $ref->{taxaccounts} = "";
1871     my $i = 0;
1872     while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
1873
1874       #    if ($customertax{$ref->{accno}})
1875       if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
1876         $i++;
1877         $ptr->{accno} = $i;
1878       }
1879       $ref->{taxaccounts} .= "$ptr->{accno} ";
1880
1881       if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
1882         $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
1883         $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
1884         $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
1885         $form->{taxaccounts} .= "$ptr->{accno} ";
1886       }
1887
1888     }
1889
1890     $stw->finish;
1891     chop $ref->{taxaccounts};
1892     if ($form->{language_id}) {
1893       $query =
1894         qq|SELECT tr.translation, tr.longdescription
1895            FROM translation tr
1896            WHERE tr.language_id = ? AND tr.parts_id = ?|;
1897       @values = (conv_i($form->{language_id}), conv_i($ref->{id}));
1898       my ($translation, $longdescription) = selectrow_query($form, $dbh, $query, @values);
1899       if ($translation ne "") {
1900         $ref->{description} = $translation;
1901         $ref->{longdescription} = $longdescription;
1902
1903       } else {
1904         $query =
1905           qq|SELECT tr.translation, tr.longdescription
1906              FROM translation tr
1907              WHERE tr.language_id IN
1908                (SELECT id
1909                 FROM language
1910                 WHERE article_code = (SELECT article_code FROM language WHERE id = ?))
1911                AND tr.parts_id = ?
1912              LIMIT 1|;
1913         @values = (conv_i($form->{language_id}), conv_i($ref->{id}));
1914         my ($translation, $longdescription) = selectrow_query($form, $dbh, $query, @values);
1915         if ($translation ne "") {
1916           $ref->{description} = $translation;
1917           $ref->{longdescription} = $longdescription;
1918         }
1919       }
1920     }
1921
1922     $ref->{onhand} *= 1;
1923
1924     push @{ $form->{item_list} }, $ref;
1925
1926     if ($form->{lizenzen}) {
1927       if ($ref->{inventory_accno} > 0) {
1928         $query =
1929           qq|SELECT l.*
1930              FROM license l
1931              WHERE l.parts_id = ? AND NOT l.id IN (SELECT li.license_id FROM licenseinvoice li)|;
1932         my $stw = prepare_execute_query($form, $dbh, $query, conv_i($ref->{id}));
1933         while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
1934           push @{ $form->{LIZENZEN}{ $ref->{id} } }, $ptr;
1935         }
1936         $stw->finish;
1937       }
1938     }
1939   }
1940   $sth->finish;
1941
1942   foreach my $item (@{ $form->{item_list} }) {
1943     my $custom_variables = CVar->get_custom_variables(module   => 'IC',
1944                                                       trans_id => $item->{id},
1945                                                       dbh      => $dbh,
1946                                                      );
1947
1948     map { $item->{"ic_cvar_" . $_->{name} } = $_->{value} } @{ $custom_variables };
1949   }
1950
1951   $dbh->disconnect;
1952
1953   $main::lxdebug->leave_sub();
1954 }
1955
1956 ##########################
1957 # get pricegroups from database
1958 # build up selected pricegroup
1959 # if an exchange rate - change price
1960 # for each part
1961 #
1962 sub get_pricegroups_for_parts {
1963
1964   $main::lxdebug->enter_sub();
1965
1966   my ($self, $myconfig, $form) = @_;
1967
1968   my $dbh = $form->dbconnect($myconfig);
1969
1970   $form->{"PRICES"} = {};
1971
1972   my $i  = 1;
1973   my $id = 0;
1974   my $all_units = AM->retrieve_units($myconfig, $form);
1975   while (($form->{"id_$i"}) or ($form->{"new_id_$i"})) {
1976     $form->{"PRICES"}{$i} = [];
1977
1978     $id = $form->{"id_$i"};
1979
1980     if (!($form->{"id_$i"}) and $form->{"new_id_$i"}) {
1981
1982       $id = $form->{"new_id_$i"};
1983     }
1984
1985     my ($price, $selectedpricegroup_id) = split(/--/,
1986       $form->{"sellprice_pg_$i"});
1987
1988     my $pricegroup_old = $form->{"pricegroup_old_$i"};
1989     $form->{"new_pricegroup_$i"} = $selectedpricegroup_id;
1990     $form->{"old_pricegroup_$i"} = $pricegroup_old;
1991
1992     my $price_new = $form->{"price_new_$i"};
1993     my $price_old = $form->{"price_old_$i"};
1994
1995     if (!$form->{"unit_old_$i"}) {
1996       # Neue Ware aus der Datenbank. In diesem Fall ist unit_$i die
1997       # Einheit, wie sie in den Stammdaten hinterlegt wurde.
1998       # Es sollte also angenommen werden, dass diese ausgewaehlt war.
1999       $form->{"unit_old_$i"} = $form->{"unit_$i"};
2000     }
2001
2002     # Die zuletzt ausgewaehlte mit der aktuell ausgewaehlten Einheit
2003     # vergleichen und bei Unterschied den Preis entsprechend umrechnen.
2004     $form->{"selected_unit_$i"} = $form->{"unit_$i"} unless ($form->{"selected_unit_$i"});
2005
2006     if (!$all_units->{$form->{"selected_unit_$i"}} ||
2007         ($all_units->{$form->{"selected_unit_$i"}}->{"base_unit"} ne
2008          $all_units->{$form->{"unit_old_$i"}}->{"base_unit"})) {
2009       # Die ausgewaehlte Einheit ist fuer diesen Artikel nicht gueltig
2010       # (z.B. Dimensionseinheit war ausgewaehlt, es handelt sich aber
2011       # um eine Dienstleistung). Dann keinerlei Umrechnung vornehmen.
2012       $form->{"unit_old_$i"} = $form->{"selected_unit_$i"} = $form->{"unit_$i"};
2013     }
2014
2015     my $basefactor = 1;
2016
2017     if ($form->{"unit_old_$i"} ne $form->{"selected_unit_$i"}) {
2018       if (defined($all_units->{$form->{"unit_old_$i"}}->{"factor"}) &&
2019           $all_units->{$form->{"unit_old_$i"}}->{"factor"}) {
2020         $basefactor = $all_units->{$form->{"selected_unit_$i"}}->{"factor"} /
2021           $all_units->{$form->{"unit_old_$i"}}->{"factor"};
2022       }
2023     }
2024
2025     if (!$form->{"basefactor_$i"}) {
2026       $form->{"basefactor_$i"} = 1;
2027     }
2028
2029     my $query =
2030       qq|SELECT
2031            pricegroup_id,
2032            (SELECT p.sellprice FROM parts p WHERE p.id = ?) AS default_sellprice,
2033            (SELECT pg.pricegroup FROM pricegroup pg WHERE id = pricegroup_id) AS pricegroup,
2034            price,
2035            '' AS selected
2036           FROM prices
2037           WHERE parts_id = ?
2038
2039           UNION
2040
2041           SELECT
2042             0 as pricegroup_id,
2043             (SELECT sellprice FROM parts WHERE id = ?) AS default_sellprice,
2044             '' AS pricegroup,
2045             (SELECT DISTINCT sellprice FROM parts where id = ?) AS price,
2046             'selected' AS selected
2047           FROM prices
2048
2049           ORDER BY pricegroup|;
2050     my @values = (conv_i($id), conv_i($id), conv_i($id), conv_i($id));
2051     my $pkq = prepare_execute_query($form, $dbh, $query, @values);
2052
2053     while (my $pkr = $pkq->fetchrow_hashref('NAME_lc')) {
2054       $pkr->{id}       = $id;
2055       $pkr->{selected} = '';
2056
2057       # if there is an exchange rate change price
2058       if (($form->{exchangerate} * 1) != 0) {
2059
2060         $pkr->{price} /= $form->{exchangerate};
2061       }
2062
2063       $pkr->{price} *= $form->{"basefactor_$i"};
2064
2065       $pkr->{price} *= $basefactor;
2066
2067       $pkr->{price} = $form->format_amount($myconfig, $pkr->{price}, 5);
2068
2069       if ($selectedpricegroup_id eq undef) {
2070         if ($pkr->{pricegroup_id} eq $form->{customer_klass}) {
2071
2072           $pkr->{selected}  = ' selected';
2073
2074           # no customer pricesgroup set
2075           if ($pkr->{price} == $pkr->{default_sellprice}) {
2076
2077             $pkr->{price} = $form->{"sellprice_$i"};
2078
2079           } else {
2080
2081 # this sub should not set anything and only return. --sschoeling, 20090506
2082 #            $form->{"sellprice_$i"} = $pkr->{price};
2083           }
2084
2085         } elsif ($pkr->{price} == $pkr->{default_sellprice}) {
2086           $pkr->{price}    = $form->{"sellprice_$i"};
2087           $pkr->{selected} = ' selected';
2088         }
2089       }
2090
2091       if ($selectedpricegroup_id or $selectedpricegroup_id == 0) {
2092         if ($selectedpricegroup_id ne $pricegroup_old) {
2093           if ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
2094             $pkr->{selected}  = ' selected';
2095           }
2096         } elsif (($price_new != $form->{"sellprice_$i"}) and ($price_new ne 0)) {
2097           if ($pkr->{pricegroup_id} == 0) {
2098             $pkr->{price}     = $form->{"sellprice_$i"};
2099             $pkr->{selected}  = ' selected';
2100           }
2101         } elsif ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
2102           $pkr->{selected}  = ' selected';
2103           if (    ($pkr->{pricegroup_id} == 0)
2104               and ($pkr->{price} == $form->{"sellprice_$i"})) {
2105             # $pkr->{price}                         = $form->{"sellprice_$i"};
2106           } else {
2107             $pkr->{price} = $form->{"sellprice_$i"};
2108           }
2109         }
2110       }
2111       push @{ $form->{PRICES}{$i} }, $pkr;
2112
2113     }
2114     $form->{"basefactor_$i"} *= $basefactor;
2115
2116     $i++;
2117
2118     $pkq->finish;
2119   }
2120
2121   $dbh->disconnect;
2122
2123   $main::lxdebug->leave_sub();
2124 }
2125
2126 sub has_storno {
2127   $main::lxdebug->enter_sub();
2128
2129   my ($self, $myconfig, $form, $table) = @_;
2130
2131   $main::lxdebug->leave_sub() and return 0 unless ($form->{id});
2132
2133   # make sure there's no funny stuff in $table
2134   # ToDO: die when this happens and throw an error
2135   $main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);
2136
2137   my $dbh = $form->dbconnect($myconfig);
2138
2139   my $query = qq|SELECT storno FROM $table WHERE storno_id = ?|;
2140   my ($result) = selectrow_query($form, $dbh, $query, $form->{id});
2141
2142   $dbh->disconnect();
2143
2144   $main::lxdebug->leave_sub();
2145
2146   return $result;
2147 }
2148
2149 sub is_storno {
2150   $main::lxdebug->enter_sub();
2151
2152   my ($self, $myconfig, $form, $table, $id) = @_;
2153
2154   $main::lxdebug->leave_sub() and return 0 unless ($id);
2155
2156   # make sure there's no funny stuff in $table
2157   # ToDO: die when this happens and throw an error
2158   $main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);
2159
2160   my $dbh = $form->dbconnect($myconfig);
2161
2162   my $query = qq|SELECT storno FROM $table WHERE id = ?|;
2163   my ($result) = selectrow_query($form, $dbh, $query, $id);
2164
2165   $dbh->disconnect();
2166
2167   $main::lxdebug->leave_sub();
2168
2169   return $result;
2170 }
2171
2172 1;