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