3b031bd96f33c5ca3ea225715452eb7691324097
[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     if (!$provided_dbh) {
967       $dbh->commit();
968       $dbh->disconnect();
969     }
970
971     $main::lxdebug->leave_sub();
972     return;
973   }
974
975   # record exchange rate differences and gains/losses
976   foreach my $accno (keys %{ $form->{fx} }) {
977     foreach my $transdate (keys %{ $form->{fx}{$accno} }) {
978       if (
979           ($form->{fx}{$accno}{$transdate} =
980            $form->round_amount($form->{fx}{$accno}{$transdate}, 2)
981           ) != 0
982         ) {
983
984         $query =
985           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, cleared, fx_transaction, taxkey, project_id)
986              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, '0', '1',
987              (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
988         @values = (conv_i($form->{"id"}), $accno, $form->{fx}{$accno}{$transdate}, conv_date($transdate), $accno, $project_id);
989         do_query($form, $dbh, $query, @values);
990       }
991     }
992   }
993
994   $amount = $netamount + $tax;
995
996   # save AR record
997   #erweiterung fuer lieferscheinnummer (donumber) 12.02.09 jb
998
999   $query = qq|UPDATE ar set
1000                 invnumber   = ?, ordnumber     = ?, quonumber     = ?, cusordnumber  = ?,
1001                 transdate   = ?, orddate       = ?, quodate       = ?, customer_id   = ?,
1002                 amount      = ?, netamount     = ?, paid          = ?,
1003                 duedate     = ?, deliverydate  = ?, invoice       = ?, shippingpoint = ?,
1004                 shipvia     = ?, terms         = ?, notes         = ?, intnotes      = ?,
1005                 curr        = ?, department_id = ?, payment_id    = ?, taxincluded   = ?,
1006                 type        = ?, language_id   = ?, taxzone_id    = ?, shipto_id     = ?,
1007                 employee_id = ?, salesman_id   = ?, storno_id     = ?, storno        = ?,
1008                 cp_id       = ?, marge_total   = ?, marge_percent = ?,
1009                 globalproject_id               = ?, delivery_customer_id             = ?,
1010                 transaction_description        = ?, delivery_vendor_id               = ?,
1011                 donumber    = ?
1012               WHERE id = ?|;
1013   @values = (          $form->{"invnumber"},           $form->{"ordnumber"},             $form->{"quonumber"},          $form->{"cusordnumber"},
1014              conv_date($form->{"invdate"}),  conv_date($form->{"orddate"}),    conv_date($form->{"quodate"}),    conv_i($form->{"customer_id"}),
1015                        $amount,                        $netamount,                       $form->{"paid"},
1016              conv_date($form->{"duedate"}),  conv_date($form->{"deliverydate"}),    '1',                                $form->{"shippingpoint"},
1017                        $form->{"shipvia"},      conv_i($form->{"terms"}),                $form->{"notes"},              $form->{"intnotes"},
1018                        $form->{"currency"},     conv_i($form->{"department_id"}), conv_i($form->{"payment_id"}),        $form->{"taxincluded"} ? 't' : 'f',
1019                        $form->{"type"},         conv_i($form->{"language_id"}),   conv_i($form->{"taxzone_id"}), conv_i($form->{"shipto_id"}),
1020                 conv_i($form->{"employee_id"}), conv_i($form->{"salesman_id"}),   conv_i($form->{storno_id}),           $form->{"storno"} ? 't' : 'f',
1021                 conv_i($form->{"cp_id"}),            1 * $form->{marge_total} ,      1 * $form->{marge_percent},
1022                 conv_i($form->{"globalproject_id"}),                              conv_i($form->{"delivery_customer_id"}),
1023                        $form->{transaction_description},                          conv_i($form->{"delivery_vendor_id"}),
1024                        $form->{"donumber"}, #das entsprechende feld lieferscheinnummer aus der html-form 12.02.09 jb
1025                 conv_i($form->{"id"}));
1026   do_query($form, $dbh, $query, @values);
1027
1028
1029   if ($form->{storno}) {
1030     $query =
1031       qq!UPDATE ar SET
1032            paid = paid + amount,
1033            storno = 't',
1034            intnotes = ? || intnotes
1035          WHERE id = ?!;
1036     do_query($form, $dbh, $query, "Rechnung storniert am $form->{invdate} ", conv_i($form->{"storno_id"}));
1037     do_query($form, $dbh, qq|UPDATE ar SET paid = amount WHERE id = ?|, conv_i($form->{"id"}));
1038   }
1039
1040   # add shipto
1041   $form->{name} = $form->{customer};
1042   $form->{name} =~ s/--\Q$form->{customer_id}\E//;
1043
1044   if (!$form->{shipto_id}) {
1045     $form->add_shipto($dbh, $form->{id}, "AR");
1046   }
1047
1048   # save printed, emailed and queued
1049   $form->save_status($dbh);
1050
1051   Common::webdav_folder($form) if ($main::webdav);
1052
1053   # Link this record to the records it was created from.
1054   RecordLinks->create_links('dbh'        => $dbh,
1055                             'mode'       => 'ids',
1056                             'from_table' => 'oe',
1057                             'from_ids'   => $form->{convert_from_oe_ids},
1058                             'to_table'   => 'ar',
1059                             'to_id'      => $form->{id},
1060     );
1061   delete $form->{convert_from_oe_ids};
1062
1063   my @convert_from_do_ids = map { $_ * 1 } grep { $_ } split m/\s+/, $form->{convert_from_do_ids};
1064
1065   if (scalar @convert_from_do_ids) {
1066     DO->close_orders('dbh' => $dbh,
1067                      'ids' => \@convert_from_do_ids);
1068
1069     RecordLinks->create_links('dbh'        => $dbh,
1070                               'mode'       => 'ids',
1071                               'from_table' => 'delivery_orders',
1072                               'from_ids'   => \@convert_from_do_ids,
1073                               'to_table'   => 'ar',
1074                               'to_id'      => $form->{id},
1075       );
1076   }
1077   delete $form->{convert_from_do_ids};
1078
1079   ARAP->close_orders_if_billed('dbh'     => $dbh,
1080                                'arap_id' => $form->{id},
1081                                'table'   => 'ar',);
1082
1083   my $rc = 1;
1084   if (!$provided_dbh) {
1085     $dbh->commit();
1086     $dbh->disconnect();
1087   }
1088
1089   $main::lxdebug->leave_sub();
1090
1091   return $rc;
1092 }
1093
1094 sub _delete_payments {
1095   $main::lxdebug->enter_sub();
1096
1097   my ($self, $form, $dbh) = @_;
1098
1099   my @delete_acc_trans_ids;
1100
1101   # Delete old payment entries from acc_trans.
1102   my $query =
1103     qq|SELECT acc_trans_id
1104        FROM acc_trans
1105        WHERE (trans_id = ?) AND fx_transaction
1106
1107        UNION
1108
1109        SELECT at.acc_trans_id
1110        FROM acc_trans at
1111        LEFT JOIN chart c ON (at.chart_id = c.id)
1112        WHERE (trans_id = ?) AND (c.link LIKE '%AR_paid%')|;
1113   push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}), conv_i($form->{id}));
1114
1115   $query =
1116     qq|SELECT at.acc_trans_id
1117        FROM acc_trans at
1118        LEFT JOIN chart c ON (at.chart_id = c.id)
1119        WHERE (trans_id = ?)
1120          AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
1121        ORDER BY at.acc_trans_id
1122        OFFSET 1|;
1123   push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}));
1124
1125   if (@delete_acc_trans_ids) {
1126     $query = qq|DELETE FROM acc_trans WHERE acc_trans_id IN (| . join(", ", @delete_acc_trans_ids) . qq|)|;
1127     do_query($form, $dbh, $query);
1128   }
1129
1130   $main::lxdebug->leave_sub();
1131 }
1132
1133 sub post_payment {
1134   $main::lxdebug->enter_sub();
1135
1136   my ($self, $myconfig, $form, $locale) = @_;
1137
1138   # connect to database, turn off autocommit
1139   my $dbh = $form->dbconnect_noauto($myconfig);
1140
1141   my (%payments, $old_form, $row, $item, $query, %keep_vars);
1142
1143   $old_form = save_form();
1144
1145   # Delete all entries in acc_trans from prior payments.
1146   $self->_delete_payments($form, $dbh);
1147
1148   # Save the new payments the user made before cleaning up $form.
1149   map { $payments{$_} = $form->{$_} } grep m/^datepaid_\d+$|^memo_\d+$|^source_\d+$|^exchangerate_\d+$|^paid_\d+$|^AR_paid_\d+$|^paidaccounts$/, keys %{ $form };
1150
1151   # Clean up $form so that old content won't tamper the results.
1152   %keep_vars = map { $_, 1 } qw(login password id);
1153   map { delete $form->{$_} unless $keep_vars{$_} } keys %{ $form };
1154
1155   # Retrieve the invoice from the database.
1156   $self->retrieve_invoice($myconfig, $form);
1157
1158   # Set up the content of $form in the way that IS::post_invoice() expects.
1159   $form->{exchangerate} = $form->format_amount($myconfig, $form->{exchangerate});
1160
1161   for $row (1 .. scalar @{ $form->{invoice_details} }) {
1162     $item = $form->{invoice_details}->[$row - 1];
1163
1164     map { $item->{$_} = $form->format_amount($myconfig, $item->{$_}) } qw(qty sellprice discount);
1165
1166     map { $form->{"${_}_${row}"} = $item->{$_} } keys %{ $item };
1167   }
1168
1169   $form->{rowcount} = scalar @{ $form->{invoice_details} };
1170
1171   delete @{$form}{qw(invoice_details paidaccounts storno paid)};
1172
1173   # Restore the payment options from the user input.
1174   map { $form->{$_} = $payments{$_} } keys %payments;
1175
1176   # Get the AR accno (which is normally done by Form::create_links()).
1177   $query =
1178     qq|SELECT c.accno
1179        FROM acc_trans at
1180        LEFT JOIN chart c ON (at.chart_id = c.id)
1181        WHERE (trans_id = ?)
1182          AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
1183        ORDER BY at.acc_trans_id
1184        LIMIT 1|;
1185
1186   ($form->{AR}) = selectfirst_array_query($form, $dbh, $query, conv_i($form->{id}));
1187
1188   # Post the new payments.
1189   $self->post_invoice($myconfig, $form, $dbh, 1);
1190
1191   restore_form($old_form);
1192
1193   my $rc = $dbh->commit();
1194   $dbh->disconnect();
1195
1196   $main::lxdebug->leave_sub();
1197
1198   return $rc;
1199 }
1200
1201 sub process_assembly {
1202   $main::lxdebug->enter_sub();
1203
1204   my ($dbh, $form, $id, $totalqty) = @_;
1205
1206   my $query =
1207     qq|SELECT a.parts_id, a.qty, p.assembly, p.partnumber, p.description, p.unit,
1208          p.inventory_accno_id, p.income_accno_id, p.expense_accno_id
1209        FROM assembly a
1210        JOIN parts p ON (a.parts_id = p.id)
1211        WHERE (a.id = ?)|;
1212   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
1213
1214   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
1215
1216     my $allocated = 0;
1217
1218     $ref->{inventory_accno_id} *= 1;
1219     $ref->{expense_accno_id}   *= 1;
1220
1221     # multiply by number of assemblies
1222     $ref->{qty} *= $totalqty;
1223
1224     if ($ref->{assembly}) {
1225       &process_assembly($dbh, $form, $ref->{parts_id}, $ref->{qty});
1226       next;
1227     } else {
1228       if ($ref->{inventory_accno_id}) {
1229         $allocated = &cogs($dbh, $form, $ref->{parts_id}, $ref->{qty});
1230       }
1231     }
1232
1233     # save detail record for individual assembly item in invoice table
1234     $query =
1235       qq|INSERT INTO invoice (trans_id, description, parts_id, qty, sellprice, fxsellprice, allocated, assemblyitem, unit)
1236          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)|;
1237     my @values = (conv_i($form->{id}), $ref->{description}, conv_i($ref->{parts_id}), $ref->{qty}, 0, 0, $allocated, 't', $ref->{unit});
1238     do_query($form, $dbh, $query, @values);
1239
1240   }
1241
1242   $sth->finish;
1243
1244   $main::lxdebug->leave_sub();
1245 }
1246
1247 sub cogs {
1248   $main::lxdebug->enter_sub();
1249
1250   my ($dbh, $form, $id, $totalqty, $basefactor, $row) = @_;
1251
1252   $basefactor ||= 1;
1253
1254   $form->{taxzone_id} *=1;
1255   my $transdate  = $form->{invdate} ? $dbh->quote($form->{invdate}) : "current_date";
1256   my $taxzone_id = $form->{"taxzone_id"} * 1;
1257   my $query =
1258     qq|SELECT i.id, i.trans_id, i.base_qty, i.allocated, i.sellprice, i.price_factor,
1259          c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
1260          c2.accno AS    income_accno, c2.new_chart_id AS    income_new_chart, date($transdate) - c2.valid_from AS    income_valid,
1261          c3.accno AS   expense_accno, c3.new_chart_id AS   expense_new_chart, date($transdate) - c3.valid_from AS   expense_valid
1262        FROM invoice i, parts p
1263        LEFT JOIN chart c1 ON ((SELECT inventory_accno_id FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
1264        LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
1265        LEFT JOIN chart c3 ON ((select expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
1266        WHERE (i.parts_id = p.id)
1267          AND (i.parts_id = ?)
1268          AND ((i.base_qty + i.allocated) < 0)
1269        ORDER BY trans_id|;
1270   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
1271
1272   my $allocated = 0;
1273   my $qty;
1274
1275   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
1276     if (($qty = (($ref->{base_qty} * -1) - $ref->{allocated})) > $totalqty) {
1277       $qty = $totalqty;
1278     }
1279
1280     $form->update_balance($dbh, "invoice", "allocated", qq|id = $ref->{id}|, $qty);
1281
1282     # total expenses and inventory
1283     # sellprice is the cost of the item
1284     my $linetotal = $form->round_amount(($ref->{sellprice} * $qty) / ( ($ref->{price_factor} || 1) * ( $basefactor || 1 )), 2);
1285
1286     if (!$main::eur) {
1287       $ref->{expense_accno} = ($form->{"expense_accno_$row"}) ? $form->{"expense_accno_$row"} : $ref->{expense_accno};
1288       # add to expense
1289       $form->{amount_cogs}{ $form->{id} }{ $ref->{expense_accno} } += -$linetotal;
1290       $form->{expense_inventory} .= " " . $ref->{expense_accno};
1291       $ref->{inventory_accno} = ($form->{"inventory_accno_$row"}) ? $form->{"inventory_accno_$row"} : $ref->{inventory_accno};
1292       # deduct inventory
1293       $form->{amount_cogs}{ $form->{id} }{ $ref->{inventory_accno} } -= -$linetotal;
1294       $form->{expense_inventory} .= " " . $ref->{inventory_accno};
1295     }
1296
1297     # add allocated
1298     $allocated -= $qty;
1299
1300     last if (($totalqty -= $qty) <= 0);
1301   }
1302
1303   $sth->finish;
1304
1305   $main::lxdebug->leave_sub();
1306
1307   return $allocated;
1308 }
1309
1310 sub reverse_invoice {
1311   $main::lxdebug->enter_sub();
1312
1313   my ($dbh, $form) = @_;
1314
1315   # reverse inventory items
1316   my $query =
1317     qq|SELECT i.id, i.parts_id, i.qty, i.assemblyitem, p.assembly, p.inventory_accno_id
1318        FROM invoice i
1319        JOIN parts p ON (i.parts_id = p.id)
1320        WHERE i.trans_id = ?|;
1321   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id"}));
1322
1323   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
1324
1325     if ($ref->{inventory_accno_id}) {
1326       # de-allocated purchases
1327       $query =
1328         qq|SELECT i.id, i.trans_id, i.allocated
1329            FROM invoice i
1330            WHERE (i.parts_id = ?) AND (i.allocated > 0)
1331            ORDER BY i.trans_id DESC|;
1332       my $sth2 = prepare_execute_query($form, $dbh, $query, conv_i($ref->{"parts_id"}));
1333
1334       while (my $inhref = $sth2->fetchrow_hashref('NAME_lc')) {
1335         my $qty = $ref->{qty};
1336         if (($ref->{qty} - $inhref->{allocated}) > 0) {
1337           $qty = $inhref->{allocated};
1338         }
1339
1340         # update invoice
1341         $form->update_balance($dbh, "invoice", "allocated", qq|id = $inhref->{id}|, $qty * -1);
1342
1343         last if (($ref->{qty} -= $qty) <= 0);
1344       }
1345       $sth2->finish;
1346     }
1347   }
1348
1349   $sth->finish;
1350
1351   # delete acc_trans
1352   my @values = (conv_i($form->{id}));
1353   do_query($form, $dbh, qq|DELETE FROM acc_trans WHERE trans_id = ?|, @values);
1354   do_query($form, $dbh, qq|DELETE FROM invoice WHERE trans_id = ?|, @values);
1355
1356   if ($form->{lizenzen}) {
1357     $query =
1358       qq|DELETE FROM licenseinvoice
1359          WHERE trans_id in (SELECT id FROM invoice WHERE trans_id = ?)|;
1360     do_query($form, $dbh, $query, @values);
1361   }
1362
1363   do_query($form, $dbh, qq|DELETE FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|, @values);
1364
1365   $main::lxdebug->leave_sub();
1366 }
1367
1368 sub delete_invoice {
1369   $main::lxdebug->enter_sub();
1370
1371   my ($self, $myconfig, $form, $spool) = @_;
1372
1373   # connect to database
1374   my $dbh = $form->dbconnect_noauto($myconfig);
1375
1376   &reverse_invoice($dbh, $form);
1377
1378   my @values = (conv_i($form->{id}));
1379
1380   # Falls wir ein Storno haben, müssen zwei Felder in der stornierten Rechnung wieder
1381   # zurückgesetzt werden. Vgl:
1382   #  id | storno | storno_id |  paid   |  amount   
1383   #----+--------+-----------+---------+-----------
1384   # 18 | f      |           | 0.00000 | 119.00000
1385   # ZU:
1386   # 18 | t      |           |  119.00000 |  119.00000
1387   #
1388   if($form->{storno}){
1389     # storno_id auslesen und korrigieren
1390     my ($invoice_id) = selectfirst_array_query($form, $dbh, qq|SELECT storno_id FROM ar WHERE id = ?|,@values);
1391     do_query($form, $dbh, qq|UPDATE ar SET storno = 'f', paid = 0 WHERE id = ?|, $invoice_id);
1392   }
1393
1394   # delete AR record
1395   do_query($form, $dbh, qq|DELETE FROM ar WHERE id = ?|, @values);
1396
1397   # delete spool files
1398   my @spoolfiles = selectall_array_query($form, $dbh, qq|SELECT spoolfile FROM status WHERE trans_id = ?|, @values);
1399
1400   # delete status entries
1401   do_query($form, $dbh, qq|DELETE FROM status WHERE trans_id = ?|, @values);
1402
1403   my $rc = $dbh->commit;
1404   $dbh->disconnect;
1405
1406   if ($rc) {
1407     map { unlink "$spool/$_" if -f "$spool/$_"; } @spoolfiles;
1408   }
1409
1410   $main::lxdebug->leave_sub();
1411
1412   return $rc;
1413 }
1414
1415 sub retrieve_invoice {
1416   $main::lxdebug->enter_sub();
1417
1418   my ($self, $myconfig, $form) = @_;
1419
1420   # connect to database
1421   my $dbh = $form->get_standard_dbh;
1422
1423   my ($sth, $ref, $query);
1424
1425   my $query_transdate = ", current_date AS invdate" if !$form->{id};
1426
1427   $query =
1428     qq|SELECT
1429          (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
1430          (SELECT c.accno FROM chart c WHERE d.income_accno_id = c.id)    AS income_accno,
1431          (SELECT c.accno FROM chart c WHERE d.expense_accno_id = c.id)   AS expense_accno,
1432          (SELECT c.accno FROM chart c WHERE d.fxgain_accno_id = c.id)    AS fxgain_accno,
1433          (SELECT c.accno FROM chart c WHERE d.fxloss_accno_id = c.id)    AS fxloss_accno,
1434          d.curr AS currencies
1435          ${query_transdate}
1436        FROM defaults d|;
1437
1438   $ref = selectfirst_hashref_query($form, $dbh, $query);
1439   map { $form->{$_} = $ref->{$_} } keys %{ $ref };
1440
1441   if ($form->{id}) {
1442     my $id = conv_i($form->{id});
1443
1444     # retrieve invoice
1445     #erweiterung um das entsprechende feld lieferscheinnummer (a.donumber) in der html-maske anzuzeigen 12.02.2009 jb
1446
1447     $query =
1448       qq|SELECT
1449            a.invnumber, a.ordnumber, a.quonumber, a.cusordnumber,
1450            a.orddate, a.quodate, a.globalproject_id,
1451            a.transdate AS invdate, a.deliverydate, a.paid, a.storno, a.gldate,
1452            a.shippingpoint, a.shipvia, a.terms, a.notes, a.intnotes, a.taxzone_id,
1453            a.duedate, a.taxincluded, a.curr AS currency, a.shipto_id, a.cp_id,
1454            a.employee_id, a.salesman_id, a.payment_id,
1455            a.language_id, a.delivery_customer_id, a.delivery_vendor_id, a.type,
1456            a.transaction_description,
1457            a.marge_total, a.marge_percent,
1458            e.name AS employee, a.donumber
1459          FROM ar a
1460          LEFT JOIN employee e ON (e.id = a.employee_id)
1461          WHERE a.id = ?|;
1462     $ref = selectfirst_hashref_query($form, $dbh, $query, $id);
1463     map { $form->{$_} = $ref->{$_} } keys %{ $ref };
1464
1465
1466     $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "buy");
1467
1468     # get shipto
1469     $query = qq|SELECT * FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|;
1470     $ref = selectfirst_hashref_query($form, $dbh, $query, $id);
1471     delete $ref->{id};
1472     map { $form->{$_} = $ref->{$_} } keys %{ $ref };
1473
1474     foreach my $vc (qw(customer vendor)) {
1475       next if !$form->{"delivery_${vc}_id"};
1476       ($form->{"delivery_${vc}_string"}) = selectrow_query($form, $dbh, qq|SELECT name FROM customer WHERE id = ?|, $id);
1477     }
1478
1479     # get printed, emailed
1480     $query = qq|SELECT printed, emailed, spoolfile, formname FROM status WHERE trans_id = ?|;
1481     $sth = prepare_execute_query($form, $dbh, $query, $id);
1482
1483     while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
1484       $form->{printed} .= "$ref->{formname} " if $ref->{printed};
1485       $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
1486       $form->{queued} .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
1487     }
1488     $sth->finish;
1489     map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
1490
1491     my $transdate = $form->{deliverydate} ? $dbh->quote($form->{deliverydate})
1492                   : $form->{invdate}      ? $dbh->quote($form->{invdate})
1493                   :                         "current_date";
1494
1495
1496     my $taxzone_id = $form->{taxzone_id} *= 1;
1497     $taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
1498
1499     # retrieve individual items
1500     $query =
1501       qq|SELECT
1502            c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
1503            c2.accno AS income_accno,    c2.new_chart_id AS income_new_chart,    date($transdate) - c2.valid_from as income_valid,
1504            c3.accno AS expense_accno,   c3.new_chart_id AS expense_new_chart,   date($transdate) - c3.valid_from AS expense_valid,
1505
1506            i.id AS invoice_id,
1507            i.description, i.longdescription, i.qty, i.fxsellprice AS sellprice, i.discount, i.parts_id AS id, i.unit, i.deliverydate AS reqdate,
1508            i.project_id, i.serialnumber, i.id AS invoice_pos, i.pricegroup_id, i.ordnumber, i.transdate, i.cusordnumber, i.subtotal, i.lastcost,
1509            i.price_factor_id, i.price_factor, i.marge_price_factor,
1510            p.partnumber, p.assembly, p.bin, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id, p.formel,
1511            pr.projectnumber, pg.partsgroup, prg.pricegroup
1512
1513          FROM invoice i
1514          LEFT JOIN parts p ON (i.parts_id = p.id)
1515          LEFT JOIN project pr ON (i.project_id = pr.id)
1516          LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
1517          LEFT JOIN pricegroup prg ON (i.pricegroup_id = prg.id)
1518
1519          LEFT JOIN chart c1 ON ((SELECT inventory_accno_id             FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
1520          LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id}  FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
1521          LEFT JOIN chart c3 ON ((SELECT expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
1522
1523          WHERE (i.trans_id = ?) AND NOT (i.assemblyitem = '1') ORDER BY i.id|;
1524
1525     $sth = prepare_execute_query($form, $dbh, $query, $id);
1526
1527     while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
1528       # Retrieve custom variables.
1529       my $cvars = CVar->get_custom_variables(dbh        => $dbh,
1530                                              module     => 'IC',
1531                                              sub_module => 'invoice',
1532                                              trans_id   => $ref->{invoice_id},
1533                                             );
1534       map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
1535       delete $ref->{invoice_id};
1536
1537       map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid)) if !$ref->{"part_inventory_accno_id"};
1538       delete($ref->{"part_inventory_accno_id"});
1539
1540       foreach my $type (qw(inventory income expense)) {
1541         while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
1542           my $query = qq|SELECT accno, new_chart_id, date($transdate) - valid_from FROM chart WHERE id = ?|;
1543           @$ref{ map $type.$_, qw(_accno _new_chart _valid) } = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
1544         }
1545       }
1546
1547       # get tax rates and description
1548       my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
1549       $query =
1550         qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber FROM tax t
1551            LEFT JOIN chart c ON (c.id = t.chart_id)
1552            WHERE t.id IN
1553              (SELECT tk.tax_id FROM taxkeys tk
1554               WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?)
1555                 AND startdate <= date($transdate)
1556               ORDER BY startdate DESC LIMIT 1)
1557            ORDER BY c.accno|;
1558       my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
1559       $ref->{taxaccounts} = "";
1560       my $i=0;
1561       while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
1562
1563         if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
1564           $i++;
1565           $ptr->{accno} = $i;
1566         }
1567         $ref->{taxaccounts} .= "$ptr->{accno} ";
1568
1569         if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
1570           $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
1571           $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
1572           $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
1573           $form->{taxaccounts} .= "$ptr->{accno} ";
1574         }
1575
1576       }
1577
1578       if ($form->{lizenzen}) {
1579         $query = qq|SELECT l.licensenumber, l.id AS licenseid FROM license l, licenseinvoice li WHERE l.id = li.license_id AND li.trans_id = ?|;
1580         my ($licensenumber, $licenseid) = selectrow_query($form, $dbh, $query, conv_i($ref->{invoice_pos}));
1581         $ref->{lizenzen} = "<option value=\"$licenseid\">$licensenumber</option>";
1582       }
1583
1584       $ref->{qty} *= -1 if $form->{type} eq "credit_note";
1585
1586       chop $ref->{taxaccounts};
1587       push @{ $form->{invoice_details} }, $ref;
1588       $stw->finish;
1589     }
1590     $sth->finish;
1591
1592     Common::webdav_folder($form) if ($main::webdav);
1593   }
1594
1595   my $rc = $dbh->commit;
1596
1597   $main::lxdebug->leave_sub();
1598
1599   return $rc;
1600 }
1601
1602 sub get_customer {
1603   $main::lxdebug->enter_sub();
1604
1605   my ($self, $myconfig, $form) = @_;
1606
1607   # connect to database
1608   my $dbh = $form->get_standard_dbh;
1609
1610   my $dateformat = $myconfig->{dateformat};
1611   $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/;
1612
1613   my (@values, $duedate, $ref, $query);
1614
1615   if ($form->{invdate}) {
1616     $duedate = "to_date(?, '$dateformat')";
1617     push @values, $form->{invdate};
1618   } else {
1619     $duedate = "current_date";
1620   }
1621
1622   my $cid = conv_i($form->{customer_id});
1623   my $payment_id;
1624
1625   if ($form->{payment_id}) {
1626     $payment_id = "(pt.id = ?) OR";
1627     push @values, conv_i($form->{payment_id});
1628   }
1629
1630   # get customer
1631   $query =
1632     qq|SELECT
1633          c.id AS customer_id, c.name AS customer, c.discount as customer_discount, c.creditlimit, c.terms,
1634          c.email, c.cc, c.bcc, c.language_id, c.payment_id,
1635          c.street, c.zipcode, c.city, c.country,
1636          c.notes AS intnotes, c.klass as customer_klass, c.taxzone_id, c.salesman_id,
1637          $duedate + COALESCE(pt.terms_netto, 0) AS duedate,
1638          b.discount AS tradediscount, b.description AS business
1639        FROM customer c
1640        LEFT JOIN business b ON (b.id = c.business_id)
1641        LEFT JOIN payment_terms pt ON ($payment_id (c.payment_id = pt.id))
1642        WHERE c.id = ?|;
1643   push @values, $cid;
1644   $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
1645
1646   delete $ref->{salesman_id} if !$ref->{salesman_id};
1647
1648   map { $form->{$_} = $ref->{$_} } keys %$ref;
1649
1650   $query =
1651     qq|SELECT sum(amount - paid) AS dunning_amount
1652        FROM ar
1653        WHERE (paid < amount)
1654          AND (customer_id = ?)
1655          AND (dunning_config_id IS NOT NULL)|;
1656   $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
1657   map { $form->{$_} = $ref->{$_} } keys %$ref;
1658
1659   $query =
1660     qq|SELECT dnn.dunning_description AS max_dunning_level
1661        FROM dunning_config dnn
1662        WHERE id IN (SELECT dunning_config_id
1663                     FROM ar
1664                     WHERE (paid < amount) AND (customer_id = ?) AND (dunning_config_id IS NOT NULL))
1665        ORDER BY dunning_level DESC LIMIT 1|;
1666   $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
1667   map { $form->{$_} = $ref->{$_} } keys %$ref;
1668
1669   $form->{creditremaining} = $form->{creditlimit};
1670   $query = qq|SELECT SUM(amount - paid) FROM ar WHERE customer_id = ?|;
1671   my ($value) = selectrow_query($form, $dbh, $query, $cid);
1672   $form->{creditremaining} -= $value;
1673
1674   $query =
1675     qq|SELECT o.amount,
1676          (SELECT e.buy FROM exchangerate e
1677           WHERE e.curr = o.curr
1678             AND e.transdate = o.transdate)
1679        FROM oe o
1680        WHERE o.customer_id = ?
1681          AND o.quotation = '0'
1682          AND o.closed = '0'|;
1683   my $sth = prepare_execute_query($form, $dbh, $query, $cid);
1684
1685   while (my ($amount, $exch) = $sth->fetchrow_array) {
1686     $exch = 1 unless $exch;
1687     $form->{creditremaining} -= $amount * $exch;
1688   }
1689   $sth->finish;
1690
1691   # get shipto if we did not converted an order or invoice
1692   if (!$form->{shipto}) {
1693     map { delete $form->{$_} }
1694       qw(shiptoname shiptodepartment_1 shiptodepartment_2
1695          shiptostreet shiptozipcode shiptocity shiptocountry
1696          shiptocontact shiptophone shiptofax shiptoemail);
1697
1698     $query = qq|SELECT * FROM shipto WHERE trans_id = ? AND module = 'CT'|;
1699     $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
1700     delete $ref->{id};
1701     map { $form->{$_} = $ref->{$_} } keys %$ref;
1702   }
1703
1704   # setup last accounts used for this customer
1705   if (!$form->{id} && $form->{type} !~ /_(order|quotation)/) {
1706     $query =
1707       qq|SELECT c.id, c.accno, c.description, c.link, c.category
1708          FROM chart c
1709          JOIN acc_trans ac ON (ac.chart_id = c.id)
1710          JOIN ar a ON (a.id = ac.trans_id)
1711          WHERE a.customer_id = ?
1712            AND NOT (c.link LIKE '%_tax%' OR c.link LIKE '%_paid%')
1713            AND a.id IN (SELECT max(a2.id) FROM ar a2 WHERE a2.customer_id = ?)|;
1714     $sth = prepare_execute_query($form, $dbh, $query, $cid, $cid);
1715
1716     my $i = 0;
1717     while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
1718       if ($ref->{category} eq 'I') {
1719         $i++;
1720         $form->{"AR_amount_$i"} = "$ref->{accno}--$ref->{description}";
1721
1722         if ($form->{initial_transdate}) {
1723           my $tax_query =
1724             qq|SELECT tk.tax_id, t.rate
1725                FROM taxkeys tk
1726                LEFT JOIN tax t ON tk.tax_id = t.id
1727                WHERE (tk.chart_id = ?) AND (startdate <= date(?))
1728                ORDER BY tk.startdate DESC
1729                LIMIT 1|;
1730           my ($tax_id, $rate) =
1731             selectrow_query($form, $dbh, $tax_query, $ref->{id},
1732                             $form->{initial_transdate});
1733           $form->{"taxchart_$i"} = "${tax_id}--${rate}";
1734         }
1735       }
1736       if ($ref->{category} eq 'A') {
1737         $form->{ARselected} = $form->{AR_1} = $ref->{accno};
1738       }
1739     }
1740     $sth->finish;
1741     $form->{rowcount} = $i if ($i && !$form->{type});
1742   }
1743
1744   $main::lxdebug->leave_sub();
1745 }
1746
1747 sub retrieve_item {
1748   $main::lxdebug->enter_sub();
1749
1750   my ($self, $myconfig, $form) = @_;
1751
1752   # connect to database
1753   my $dbh = $form->dbconnect($myconfig);
1754
1755   my $i = $form->{rowcount};
1756
1757   my $where = qq|NOT p.obsolete = '1'|;
1758   my @values;
1759
1760   foreach my $column (qw(p.partnumber p.description pgpartsgroup )) {
1761     my ($table, $field) = split m/\./, $column;
1762     next if !$form->{"${field}_${i}"};
1763     $where .= qq| AND lower(${column}) ILIKE ?|;
1764     push @values, '%' . $form->{"${field}_${i}"} . '%';
1765   }
1766
1767   #Es soll auch nach EAN gesucht werden, ohne Einschränkung durch Beschreibung
1768   if ($form->{"partnumber_$i"} && !$form->{"description_$i"}) {
1769     $where .= qq| OR (NOT p.obsolete = '1' AND p.ean = ? )|;
1770     push @values, $form->{"partnumber_$i"};
1771   }
1772
1773   if ($form->{"description_$i"}) {
1774     $where .= qq| ORDER BY p.description|;
1775   } else {
1776     $where .= qq| ORDER BY p.partnumber|;
1777   }
1778
1779   my $transdate;
1780   if ($form->{type} eq "invoice") {
1781     $transdate =
1782       $form->{deliverydate} ? $dbh->quote($form->{deliverydate}) :
1783       $form->{invdate}      ? $dbh->quote($form->{invdate}) :
1784                               "current_date";
1785   } else {
1786     $transdate =
1787       $form->{transdate}    ? $dbh->quote($form->{transdate}) :
1788                               "current_date";
1789   }
1790
1791   my $taxzone_id = $form->{taxzone_id} * 1;
1792   $taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
1793
1794   my $query =
1795     qq|SELECT
1796          p.id, p.partnumber, p.description, p.sellprice,
1797          p.listprice, p.inventory_accno_id, p.lastcost,
1798
1799          c1.accno AS inventory_accno,
1800          c1.new_chart_id AS inventory_new_chart,
1801          date($transdate) - c1.valid_from AS inventory_valid,
1802
1803          c2.accno AS income_accno,
1804          c2.new_chart_id AS income_new_chart,
1805          date($transdate)  - c2.valid_from AS income_valid,
1806
1807          c3.accno AS expense_accno,
1808          c3.new_chart_id AS expense_new_chart,
1809          date($transdate) - c3.valid_from AS expense_valid,
1810
1811          p.unit, p.assembly, p.bin, p.onhand,
1812          p.notes AS partnotes, p.notes AS longdescription,
1813          p.not_discountable, p.formel, p.payment_id AS part_payment_id,
1814          p.price_factor_id,
1815
1816          pfac.factor AS price_factor,
1817
1818          pg.partsgroup
1819
1820        FROM parts p
1821        LEFT JOIN chart c1 ON
1822          ((SELECT inventory_accno_id
1823            FROM buchungsgruppen
1824            WHERE id = p.buchungsgruppen_id) = c1.id)
1825        LEFT JOIN chart c2 ON
1826          ((SELECT income_accno_id_${taxzone_id}
1827            FROM buchungsgruppen
1828            WHERE id = p.buchungsgruppen_id) = c2.id)
1829        LEFT JOIN chart c3 ON
1830          ((SELECT expense_accno_id_${taxzone_id}
1831            FROM buchungsgruppen
1832            WHERE id = p.buchungsgruppen_id) = c3.id)
1833        LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
1834        LEFT JOIN price_factors pfac ON (pfac.id = p.price_factor_id)
1835        WHERE $where|;
1836   my $sth = prepare_execute_query($form, $dbh, $query, @values);
1837
1838   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
1839
1840     # In der Buchungsgruppe ist immer ein Bestandskonto verknuepft, auch wenn
1841     # es sich um eine Dienstleistung handelt. Bei Dienstleistungen muss das
1842     # Buchungskonto also aus dem Ergebnis rausgenommen werden.
1843     if (!$ref->{inventory_accno_id}) {
1844       map({ delete($ref->{"inventory_${_}"}); } qw(accno new_chart valid));
1845     }
1846     delete($ref->{inventory_accno_id});
1847
1848     foreach my $type (qw(inventory income expense)) {
1849       while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
1850         my $query =
1851           qq|SELECT accno, new_chart_id, date($transdate) - valid_from
1852              FROM chart
1853              WHERE id = ?|;
1854         ($ref->{"${type}_accno"},
1855          $ref->{"${type}_new_chart"},
1856          $ref->{"${type}_valid"})
1857           = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
1858       }
1859     }
1860
1861     if ($form->{payment_id} eq "") {
1862       $form->{payment_id} = $form->{part_payment_id};
1863     }
1864
1865     # get tax rates and description
1866     my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
1867     $query =
1868       qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber
1869          FROM tax t
1870          LEFT JOIN chart c ON (c.id = t.chart_id)
1871          WHERE t.id in
1872            (SELECT tk.tax_id
1873             FROM taxkeys tk
1874             WHERE tk.chart_id = (SELECT id from chart WHERE accno = ?)
1875               AND startdate <= ?
1876             ORDER BY startdate DESC
1877             LIMIT 1)
1878          ORDER BY c.accno|;
1879     @values = ($accno_id, $transdate eq "current_date" ? "now" : $transdate);
1880     my $stw = $dbh->prepare($query);
1881     $stw->execute(@values) || $form->dberror($query);
1882
1883     $ref->{taxaccounts} = "";
1884     my $i = 0;
1885     while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
1886
1887       #    if ($customertax{$ref->{accno}})
1888       if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
1889         $i++;
1890         $ptr->{accno} = $i;
1891       }
1892       $ref->{taxaccounts} .= "$ptr->{accno} ";
1893
1894       if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
1895         $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
1896         $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
1897         $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
1898         $form->{taxaccounts} .= "$ptr->{accno} ";
1899       }
1900
1901     }
1902
1903     $stw->finish;
1904     chop $ref->{taxaccounts};
1905     if ($form->{language_id}) {
1906       $query =
1907         qq|SELECT tr.translation, tr.longdescription
1908            FROM translation tr
1909            WHERE tr.language_id = ? AND tr.parts_id = ?|;
1910       @values = (conv_i($form->{language_id}), conv_i($ref->{id}));
1911       my ($translation, $longdescription) = selectrow_query($form, $dbh, $query, @values);
1912       if ($translation ne "") {
1913         $ref->{description} = $translation;
1914         $ref->{longdescription} = $longdescription;
1915
1916       } else {
1917         $query =
1918           qq|SELECT tr.translation, tr.longdescription
1919              FROM translation tr
1920              WHERE tr.language_id IN
1921                (SELECT id
1922                 FROM language
1923                 WHERE article_code = (SELECT article_code FROM language WHERE id = ?))
1924                AND tr.parts_id = ?
1925              LIMIT 1|;
1926         @values = (conv_i($form->{language_id}), conv_i($ref->{id}));
1927         my ($translation, $longdescription) = selectrow_query($form, $dbh, $query, @values);
1928         if ($translation ne "") {
1929           $ref->{description} = $translation;
1930           $ref->{longdescription} = $longdescription;
1931         }
1932       }
1933     }
1934
1935     $ref->{onhand} *= 1;
1936
1937     push @{ $form->{item_list} }, $ref;
1938
1939     if ($form->{lizenzen}) {
1940       if ($ref->{inventory_accno} > 0) {
1941         $query =
1942           qq|SELECT l.*
1943              FROM license l
1944              WHERE l.parts_id = ? AND NOT l.id IN (SELECT li.license_id FROM licenseinvoice li)|;
1945         my $stw = prepare_execute_query($form, $dbh, $query, conv_i($ref->{id}));
1946         while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
1947           push @{ $form->{LIZENZEN}{ $ref->{id} } }, $ptr;
1948         }
1949         $stw->finish;
1950       }
1951     }
1952   }
1953   $sth->finish;
1954
1955   foreach my $item (@{ $form->{item_list} }) {
1956     my $custom_variables = CVar->get_custom_variables(module   => 'IC',
1957                                                       trans_id => $item->{id},
1958                                                       dbh      => $dbh,
1959                                                      );
1960
1961     map { $item->{"ic_cvar_" . $_->{name} } = $_->{value} } @{ $custom_variables };
1962   }
1963
1964   $dbh->disconnect;
1965
1966   $main::lxdebug->leave_sub();
1967 }
1968
1969 ##########################
1970 # get pricegroups from database
1971 # build up selected pricegroup
1972 # if an exchange rate - change price
1973 # for each part
1974 #
1975 sub get_pricegroups_for_parts {
1976
1977   $main::lxdebug->enter_sub();
1978
1979   my ($self, $myconfig, $form) = @_;
1980
1981   my $dbh = $form->dbconnect($myconfig);
1982
1983   $form->{"PRICES"} = {};
1984
1985   my $i  = 1;
1986   my $id = 0;
1987   my $all_units = AM->retrieve_units($myconfig, $form);
1988   while (($form->{"id_$i"}) or ($form->{"new_id_$i"})) {
1989     $form->{"PRICES"}{$i} = [];
1990
1991     $id = $form->{"id_$i"};
1992
1993     if (!($form->{"id_$i"}) and $form->{"new_id_$i"}) {
1994       $id = $form->{"new_id_$i"};
1995     }
1996
1997     my ($price, $selectedpricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
1998
1999     my $pricegroup_old = $form->{"pricegroup_old_$i"};
2000     $form->{"new_pricegroup_$i"} = $selectedpricegroup_id;
2001     $form->{"old_pricegroup_$i"} = $pricegroup_old;
2002
2003     my $price_new = $form->{"price_new_$i"};
2004     my $price_old = $form->{"price_old_$i"};
2005
2006     if (!$form->{"unit_old_$i"}) {
2007       # Neue Ware aus der Datenbank. In diesem Fall ist unit_$i die
2008       # Einheit, wie sie in den Stammdaten hinterlegt wurde.
2009       # Es sollte also angenommen werden, dass diese ausgewaehlt war.
2010       $form->{"unit_old_$i"} = $form->{"unit_$i"};
2011     }
2012
2013     # Die zuletzt ausgewaehlte mit der aktuell ausgewaehlten Einheit
2014     # vergleichen und bei Unterschied den Preis entsprechend umrechnen.
2015     $form->{"selected_unit_$i"} = $form->{"unit_$i"} unless ($form->{"selected_unit_$i"});
2016
2017     if (!$all_units->{$form->{"selected_unit_$i"}} ||
2018         ($all_units->{$form->{"selected_unit_$i"}}->{"base_unit"} ne
2019          $all_units->{$form->{"unit_old_$i"}}->{"base_unit"})) {
2020       # Die ausgewaehlte Einheit ist fuer diesen Artikel nicht gueltig
2021       # (z.B. Dimensionseinheit war ausgewaehlt, es handelt sich aber
2022       # um eine Dienstleistung). Dann keinerlei Umrechnung vornehmen.
2023       $form->{"unit_old_$i"} = $form->{"selected_unit_$i"} = $form->{"unit_$i"};
2024     }
2025
2026     my $basefactor = 1;
2027
2028     if ($form->{"unit_old_$i"} ne $form->{"selected_unit_$i"}) {
2029       if (defined($all_units->{$form->{"unit_old_$i"}}->{"factor"}) &&
2030           $all_units->{$form->{"unit_old_$i"}}->{"factor"}) {
2031         $basefactor = $all_units->{$form->{"selected_unit_$i"}}->{"factor"} /
2032           $all_units->{$form->{"unit_old_$i"}}->{"factor"};
2033       }
2034     }
2035
2036     if (!$form->{"basefactor_$i"}) {
2037       $form->{"basefactor_$i"} = 1;
2038     }
2039
2040     my $query =
2041       qq|SELECT
2042            pricegroup_id,
2043            (SELECT p.sellprice FROM parts p WHERE p.id = ?) AS default_sellprice,
2044            (SELECT pg.pricegroup FROM pricegroup pg WHERE id = pricegroup_id) AS pricegroup,
2045            price,
2046            '' AS selected
2047           FROM prices
2048           WHERE parts_id = ?
2049
2050           UNION
2051
2052           SELECT
2053             0 as pricegroup_id,
2054             (SELECT sellprice FROM parts WHERE id = ?) AS default_sellprice,
2055             '' AS pricegroup,
2056             (SELECT DISTINCT sellprice FROM parts where id = ?) AS price,
2057             'selected' AS selected
2058           FROM prices
2059
2060           ORDER BY pricegroup|;
2061     my @values = (conv_i($id), conv_i($id), conv_i($id), conv_i($id));
2062     my $pkq = prepare_execute_query($form, $dbh, $query, @values);
2063
2064     while (my $pkr = $pkq->fetchrow_hashref('NAME_lc')) {
2065       $pkr->{id}       = $id;
2066       $pkr->{selected} = '';
2067
2068       # if there is an exchange rate change price
2069       if (($form->{exchangerate} * 1) != 0) {
2070         $pkr->{price} /= $form->{exchangerate};
2071       }
2072
2073       $pkr->{price} *= $form->{"basefactor_$i"};
2074       $pkr->{price} *= $basefactor;
2075       $pkr->{price} = $form->format_amount($myconfig, $pkr->{price}, 5);
2076
2077       if ($selectedpricegroup_id eq undef) {
2078         if ($pkr->{pricegroup_id} eq $form->{customer_klass}) {
2079
2080           $pkr->{selected}  = ' selected';
2081
2082           # no customer pricesgroup set
2083           if ($pkr->{price} == $pkr->{default_sellprice}) {
2084
2085             $pkr->{price} = $form->{"sellprice_$i"};
2086
2087           } else {
2088
2089 # this sub should not set anything and only return. --sschoeling, 20090506
2090 #            $form->{"sellprice_$i"} = $pkr->{price};
2091           }
2092
2093         } elsif ($pkr->{price} == $pkr->{default_sellprice}) {
2094           $pkr->{price}    = $form->{"sellprice_$i"};
2095           $pkr->{selected} = ' selected';
2096         }
2097       } else {
2098         if ($selectedpricegroup_id ne $pricegroup_old) {
2099           if ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
2100             $pkr->{selected}  = ' selected';
2101           }
2102         } elsif (    (   $form->parse_amount($myconfig, $price_new)
2103                       != $form->parse_amount($myconfig, $form->{"sellprice_$i"}))
2104                  and ($price_new ne 0)) {
2105           if ($pkr->{pricegroup_id} == 0) {
2106             $pkr->{price}     = $form->{"sellprice_$i"};
2107             $pkr->{selected}  = ' selected';
2108           }
2109         } elsif ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
2110           $pkr->{selected}  = ' selected';
2111           if (    ($pkr->{pricegroup_id} == 0)
2112               and ($pkr->{price} == $form->{"sellprice_$i"})) {
2113             # $pkr->{price}                         = $form->{"sellprice_$i"};
2114           } else {
2115             $pkr->{price} = $form->{"sellprice_$i"};
2116           }
2117         }
2118       }
2119       push @{ $form->{PRICES}{$i} }, $pkr;
2120
2121     }
2122     $form->{"basefactor_$i"} *= $basefactor;
2123
2124     $i++;
2125
2126     $pkq->finish;
2127   }
2128
2129   $dbh->disconnect;
2130
2131   $main::lxdebug->leave_sub();
2132 }
2133
2134 sub has_storno {
2135   $main::lxdebug->enter_sub();
2136
2137   my ($self, $myconfig, $form, $table) = @_;
2138
2139   $main::lxdebug->leave_sub() and return 0 unless ($form->{id});
2140
2141   # make sure there's no funny stuff in $table
2142   # ToDO: die when this happens and throw an error
2143   $main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);
2144
2145   my $dbh = $form->dbconnect($myconfig);
2146
2147   my $query = qq|SELECT storno FROM $table WHERE storno_id = ?|;
2148   my ($result) = selectrow_query($form, $dbh, $query, $form->{id});
2149
2150   $dbh->disconnect();
2151
2152   $main::lxdebug->leave_sub();
2153
2154   return $result;
2155 }
2156
2157 sub is_storno {
2158   $main::lxdebug->enter_sub();
2159
2160   my ($self, $myconfig, $form, $table, $id) = @_;
2161
2162   $main::lxdebug->leave_sub() and return 0 unless ($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 id = ?|;
2171   my ($result) = selectrow_query($form, $dbh, $query, $id);
2172
2173   $dbh->disconnect();
2174
2175   $main::lxdebug->leave_sub();
2176
2177   return $result;
2178 }
2179
2180 sub get_standard_accno_current_assets {
2181   $main::lxdebug->enter_sub();
2182
2183   my ($self, $myconfig, $form) = @_;
2184
2185   my $dbh = $form->dbconnect($myconfig);
2186
2187   my $query = qq| SELECT accno FROM chart WHERE id = (SELECT ar_paid_accno_id FROM defaults)|;
2188   my ($result) = selectrow_query($form, $dbh, $query);
2189
2190   $dbh->disconnect();
2191
2192   $main::lxdebug->leave_sub();
2193
2194   return $result;
2195 }
2196
2197 1;