1 #=====================================================================
 
   4 # Based on SQL-Ledger Version 2.1.9
 
   5 # Web http://www.lx-office.org
 
   7 #=====================================================================
 
   8 # SQL-Ledger Accounting
 
   9 # Copyright (C) 1998-2002
 
  11 #  Author: Dieter Simader
 
  12 #   Email: dsimader@sql-ledger.org
 
  13 #     Web: http://www.sql-ledger.org
 
  17 # This program is free software; you can redistribute it and/or modify
 
  18 # it under the terms of the GNU General Public License as published by
 
  19 # the Free Software Foundation; either version 2 of the License, or
 
  20 # (at your option) any later version.
 
  22 # This program is distributed in the hope that it will be useful,
 
  23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  25 # GNU General Public License for more details.
 
  26 # You should have received a copy of the GNU General Public License
 
  27 # along with this program; if not, write to the Free Software
 
  28 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
  29 #======================================================================
 
  31 # Inventory invoicing module
 
  33 #======================================================================
 
  39 use List::Util qw(max);
 
  47 use SL::GenericTranslations;
 
  53   $main::lxdebug->enter_sub();
 
  55   my ($self, $myconfig, $form, $locale) = @_;
 
  57   $form->{duedate} ||= $form->{invdate};
 
  60   my $dbh = $form->dbconnect($myconfig);
 
  63   my $query = qq|SELECT date | . conv_dateq($form->{duedate}) . qq| - date | . conv_dateq($form->{invdate}) . qq| AS terms|;
 
  64   ($form->{terms}) = selectrow_query($form, $dbh, $query);
 
  66   my (@project_ids, %projectnumbers);
 
  67   $form->{TEMPLATE_ARRAYS} = {};
 
  69   push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});
 
  71   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
 
  74   foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
 
  75     $price_factors{$pfac->{id}}  = $pfac;
 
  77     $pfac->{formatted_factor}    = $form->format_amount($myconfig, $pfac->{factor});
 
  80   # sort items by partsgroup
 
  81   for my $i (1 .. $form->{rowcount}) {
 
  83 #    if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
 
  84 #      $partsgroup = $form->{"partsgroup_$i"};
 
  86 #    push @partsgroup, [$i, $partsgroup];
 
  87     push(@project_ids, $form->{"project_id_$i"}) if ($form->{"project_id_$i"});
 
  91     $query = "SELECT id, projectnumber FROM project WHERE id IN (" .
 
  92       join(", ", map({ "?" } @project_ids)) . ")";
 
  93     $sth = $dbh->prepare($query);
 
  94     $sth->execute(@project_ids) ||
 
  95       $form->dberror($query . " (" . join(", ", @project_ids) . ")");
 
  96     while (my $ref = $sth->fetchrow_hashref()) {
 
  97       $projectnumbers{$ref->{id}} = $ref->{projectnumber};
 
 102   $form->{"globalprojectnumber"} =
 
 103     $projectnumbers{$form->{"globalproject_id"}};
 
 110   my %oid = ('Pg'     => 'oid',
 
 111              'Oracle' => 'rowid');
 
 113   # sort items by partsgroup
 
 114   for $i (1 .. $form->{rowcount}) {
 
 116     if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
 
 117       $partsgroup = $form->{"partsgroup_$i"};
 
 119     push @partsgroup, [$i, $partsgroup];
 
 132   my $nodiscount_subtotal = 0;
 
 133   my $discount_subtotal = 0;
 
 135   my $subtotal_header = 0;
 
 138   $form->{discount} = [];
 
 140   IC->prepare_parts_for_printing();
 
 142   my $ic_cvar_configs = CVar->get_configs(module => 'IC');
 
 145     qw(runningnumber number description longdescription qty ship unit bin
 
 146        deliverydate_oe ordnumber_oe transdate_oe licensenumber validuntil
 
 147        partnotes serialnumber reqdate sellprice listprice netprice
 
 148        discount p_discount discount_sub nodiscount_sub
 
 149        linetotal  nodiscount_linetotal tax_rate projectnumber
 
 150        price_factor price_factor_name partsgroup);
 
 152   push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };
 
 154   my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);
 
 156   my @payment_arrays = qw(payment paymentaccount paymentdate paymentsource paymentmemo);
 
 158   map { $form->{TEMPLATE_ARRAYS}{$_} => [] } (@arrays, @tax_arrays, @payment_arrays);
 
 160   foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
 
 163     if ($item->[1] ne $sameitem) {
 
 164       push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, qq|$item->[1]|);
 
 165       $sameitem = $item->[1];
 
 167       map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
 170     $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
 
 172     if ($form->{"id_$i"} != 0) {
 
 174       # add number, description and qty to $form->{number},
 
 175       if ($form->{"subtotal_$i"} && !$subtotal_header) {
 
 176         $subtotal_header = $i;
 
 177         $position = int($position);
 
 180       } elsif ($subtotal_header) {
 
 182         $position = int($position);
 
 183         $position = $position.".".$subposition;
 
 185         $position = int($position);
 
 189       my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || { 'factor' => 1 };
 
 191       push @{ $form->{TEMPLATE_ARRAYS}->{runningnumber} },     $position;
 
 192       push @{ $form->{TEMPLATE_ARRAYS}->{number} },            $form->{"partnumber_$i"};
 
 193       push @{ $form->{TEMPLATE_ARRAYS}->{serialnumber} },      $form->{"serialnumber_$i"};
 
 194       push @{ $form->{TEMPLATE_ARRAYS}->{bin} },               $form->{"bin_$i"};
 
 195       push @{ $form->{TEMPLATE_ARRAYS}->{partnotes} },         $form->{"partnotes_$i"};
 
 196       push @{ $form->{TEMPLATE_ARRAYS}->{description} },       $form->{"description_$i"};
 
 197       push @{ $form->{TEMPLATE_ARRAYS}->{longdescription} },   $form->{"longdescription_$i"};
 
 198       push @{ $form->{TEMPLATE_ARRAYS}->{qty} },               $form->format_amount($myconfig, $form->{"qty_$i"});
 
 199       push @{ $form->{TEMPLATE_ARRAYS}->{unit} },              $form->{"unit_$i"};
 
 200       push @{ $form->{TEMPLATE_ARRAYS}->{deliverydate_oe} },   $form->{"deliverydate_$i"};
 
 201       push @{ $form->{TEMPLATE_ARRAYS}->{sellprice} },         $form->{"sellprice_$i"};
 
 202       push @{ $form->{TEMPLATE_ARRAYS}->{ordnumber_oe} },      $form->{"ordnumber_$i"};
 
 203       push @{ $form->{TEMPLATE_ARRAYS}->{transdate_oe} },      $form->{"transdate_$i"};
 
 204       push @{ $form->{TEMPLATE_ARRAYS}->{invnumber} },         $form->{"invnumber"};
 
 205       push @{ $form->{TEMPLATE_ARRAYS}->{invdate} },           $form->{"invdate"};
 
 206       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor} },      $price_factor->{formatted_factor};
 
 207       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor_name} }, $price_factor->{description};
 
 208       push @{ $form->{TEMPLATE_ARRAYS}->{partsgroup} },        $form->{"partsgroup_$i"};
 
 209       push @{ $form->{TEMPLATE_ARRAYS}->{reqdate} },           $form->{"reqdate_$i"};
 
 211       if ($form->{lizenzen}) {
 
 212         if ($form->{"licensenumber_$i"}) {
 
 213           $query = qq|SELECT licensenumber, validuntil FROM license WHERE id = ?|;
 
 214           my ($licensenumber, $validuntil) = selectrow_query($form, $dbh, $query, conv_i($form->{"licensenumber_$i"}));
 
 215           push(@{ $form->{TEMPLATE_ARRAYS}->{licensenumber} }, $licensenumber);
 
 216           push(@{ $form->{TEMPLATE_ARRAYS}->{validuntil} }, $locale->date($myconfig, $validuntil, 0));
 
 219           push(@{ $form->{TEMPLATE_ARRAYS}->{licensenumber} }, "");
 
 220           push(@{ $form->{TEMPLATE_ARRAYS}->{validuntil} },    "");
 
 225       push(@{ $form->{TEMPLATE_ARRAYS}->{listprice} }, $form->{"listprice_$i"});
 
 227       my $sellprice     = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 228       my ($dec)         = ($sellprice =~ /\.(\d+)/);
 
 229       my $decimalplaces = max 2, length($dec);
 
 231       my $parsed_discount      = $form->parse_amount($myconfig, $form->{"discount_$i"});
 
 232       my $linetotal_exact      =                     $form->{"qty_$i"} * $sellprice * (100 - $parsed_discount) / 100 / $price_factor->{factor};
 
 233       my $linetotal            = $form->round_amount($linetotal_exact, 2);
 
 234       my $discount             = $form->round_amount($form->{"qty_$i"} * $sellprice * $parsed_discount / 100 / $price_factor->{factor} - ($linetotal - $linetotal_exact),
 
 236       my $nodiscount_linetotal = $form->round_amount($form->{"qty_$i"} * $sellprice / $price_factor->{factor}, 2);
 
 237       $form->{"netprice_$i"}   = $form->round_amount($form->{"qty_$i"} ? ($linetotal / $form->{"qty_$i"}) : 0, 2);
 
 239       push @{ $form->{TEMPLATE_ARRAYS}->{netprice} }, ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : '';
 
 241       $linetotal = ($linetotal != 0) ? $linetotal : '';
 
 243       push @{ $form->{TEMPLATE_ARRAYS}->{discount} },   ($discount  != 0) ? $form->format_amount($myconfig, $discount * -1, 2) : '';
 
 244       push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} }, $form->{"discount_$i"};
 
 246       $form->{total}            += $linetotal;
 
 247       $form->{nodiscount_total} += $nodiscount_linetotal;
 
 248       $form->{discount_total}   += $discount;
 
 250       if ($subtotal_header) {
 
 251         $discount_subtotal   += $linetotal;
 
 252         $nodiscount_subtotal += $nodiscount_linetotal;
 
 255       if ($form->{"subtotal_$i"} && $subtotal_header && ($subtotal_header != $i)) {
 
 256         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} },   $form->format_amount($myconfig, $discount_subtotal,   2);
 
 257         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, $form->format_amount($myconfig, $nodiscount_subtotal, 2);
 
 259         $discount_subtotal   = 0;
 
 260         $nodiscount_subtotal = 0;
 
 261         $subtotal_header     = 0;
 
 264         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} },   "";
 
 265         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, "";
 
 268       if (!$form->{"discount_$i"}) {
 
 269         $nodiscount += $linetotal;
 
 272       push @{ $form->{TEMPLATE_ARRAYS}->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2);
 
 273       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} }, $form->format_amount($myconfig, $nodiscount_linetotal, 2);
 
 275       push(@{ $form->{TEMPLATE_ARRAYS}->{projectnumber} }, $projectnumbers{$form->{"project_id_$i"}});
 
 277       @taxaccounts = split(/ /, $form->{"taxaccounts_$i"});
 
 281       map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;
 
 283       if ($form->{taxincluded}) {
 
 286         $taxamount = $linetotal * $taxrate / (1 + $taxrate);
 
 287         $taxbase = $linetotal - $taxamount;
 
 289         $taxamount = $linetotal * $taxrate;
 
 290         $taxbase   = $linetotal;
 
 293       if ($form->round_amount($taxrate, 7) == 0) {
 
 294         if ($form->{taxincluded}) {
 
 295           foreach my $accno (@taxaccounts) {
 
 296             $taxamount            = $form->round_amount($linetotal * $form->{"${accno}_rate"} / (1 + abs($form->{"${accno}_rate"})), 2);
 
 298             $taxaccounts{$accno} += $taxamount;
 
 299             $taxdiff             += $taxamount;
 
 301             $taxbase{$accno}     += $taxbase;
 
 303           $taxaccounts{ $taxaccounts[0] } += $taxdiff;
 
 305           foreach my $accno (@taxaccounts) {
 
 306             $taxaccounts{$accno} += $linetotal * $form->{"${accno}_rate"};
 
 307             $taxbase{$accno}     += $taxbase;
 
 311         foreach my $accno (@taxaccounts) {
 
 312           $taxaccounts{$accno} += $taxamount * $form->{"${accno}_rate"} / $taxrate;
 
 313           $taxbase{$accno}     += $taxbase;
 
 316       my $tax_rate = $taxrate * 100;
 
 317       push(@{ $form->{TEMPLATE_ARRAYS}->{tax_rate} }, qq|$tax_rate|);
 
 318       if ($form->{"assembly_$i"}) {
 
 321         # get parts and push them onto the stack
 
 323         if ($form->{groupitems}) {
 
 325             qq|ORDER BY pg.partsgroup, a.$oid{$myconfig->{dbdriver}}|;
 
 327           $sortorder = qq|ORDER BY a.$oid{$myconfig->{dbdriver}}|;
 
 331           qq|SELECT p.partnumber, p.description, p.unit, a.qty, pg.partsgroup
 
 333              JOIN parts p ON (a.parts_id = p.id)
 
 334              LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
 
 335              WHERE (a.bom = '1') AND (a.id = ?) $sortorder|;
 
 336         $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id_$i"}));
 
 338         while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
 339           if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
 
 340             map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
 341             $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
 
 342             push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $sameitem);
 
 345           map { $form->{"a_$_"} = $ref->{$_} } qw(partnumber description);
 
 347           push(@{ $form->{TEMPLATE_ARRAYS}->{description} },
 
 348                $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}
 
 350                  . qq| -- $form->{"a_partnumber"}, $form->{"a_description"}|);
 
 351           map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
 357       map { push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} }, $form->{"ic_cvar_$_->{name}_$i"} } @{ $ic_cvar_configs };
 
 361   foreach my $item (sort keys %taxaccounts) {
 
 362     $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
 
 364     push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase} },        $form->format_amount($myconfig, $taxbase{$item}, 2));
 
 365     push(@{ $form->{TEMPLATE_ARRAYS}->{tax} },            $form->format_amount($myconfig, $taxamount,      2));
 
 366     push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate} },        $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
 
 367     push(@{ $form->{TEMPLATE_ARRAYS}->{taxdescription} }, $form->{"${item}_description"} . q{ } . 100 * $form->{"${item}_rate"} . q{%});
 
 368     push(@{ $form->{TEMPLATE_ARRAYS}->{taxnumber} },      $form->{"${item}_taxnumber"});
 
 371   for my $i (1 .. $form->{paidaccounts}) {
 
 372     if ($form->{"paid_$i"}) {
 
 373       my ($accno, $description) = split(/--/, $form->{"AR_paid_$i"});
 
 375       push(@{ $form->{TEMPLATE_ARRAYS}->{payment} },        $form->{"paid_$i"});
 
 376       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentaccount} }, $description);
 
 377       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentdate} },    $form->{"datepaid_$i"});
 
 378       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentsource} },  $form->{"source_$i"});
 
 379       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentmemo} },    $form->{"memo_$i"});
 
 381       $form->{paid} += $form->parse_amount($myconfig, $form->{"paid_$i"});
 
 384   if($form->{taxincluded}) {
 
 385     $form->{subtotal} = $form->format_amount($myconfig, $form->{total} - $tax, 2);
 
 388     $form->{subtotal} = $form->format_amount($myconfig, $form->{total}, 2);
 
 391   $form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
 
 392   $form->{discount_total}      = $form->format_amount($myconfig, $form->{discount_total}, 2);
 
 393   $form->{nodiscount}          = $form->format_amount($myconfig, $nodiscount, 2);
 
 394   $form->{yesdiscount}         = $form->format_amount($myconfig, $form->{nodiscount_total} - $nodiscount, 2);
 
 396   $form->{invtotal} = ($form->{taxincluded}) ? $form->{total} : $form->{total} + $tax;
 
 397   $form->{total}    = $form->format_amount($myconfig, $form->{invtotal} - $form->{paid}, 2);
 
 399   $form->{invtotal} = $form->format_amount($myconfig, $form->{invtotal}, 2);
 
 400   $form->{paid}     = $form->format_amount($myconfig, $form->{paid}, 2);
 
 402   $form->set_payment_options($myconfig, $form->{invdate});
 
 404   $form->{username} = $myconfig->{name};
 
 408   $main::lxdebug->leave_sub();
 
 411 sub project_description {
 
 412   $main::lxdebug->enter_sub();
 
 414   my ($self, $dbh, $id) = @_;
 
 415   my $form = \%main::form;
 
 417   my $query = qq|SELECT description FROM project WHERE id = ?|;
 
 418   my ($description) = selectrow_query($form, $dbh, $query, conv_i($id));
 
 420   $main::lxdebug->leave_sub();
 
 425 sub customer_details {
 
 426   $main::lxdebug->enter_sub();
 
 428   my ($self, $myconfig, $form, @wanted_vars) = @_;
 
 430   # connect to database
 
 431   my $dbh = $form->dbconnect($myconfig);
 
 433   my $language_id = $form->{language_id};
 
 435   # get contact id, set it if nessessary
 
 438   my @values =  (conv_i($form->{customer_id}));
 
 441   if ($form->{cp_id}) {
 
 442     $where = qq| AND (cp.cp_id = ?) |;
 
 443     push(@values, conv_i($form->{cp_id}));
 
 446   # get rest for the customer
 
 448     qq|SELECT ct.*, cp.*, ct.notes as customernotes,
 
 449          ct.phone AS customerphone, ct.fax AS customerfax, ct.email AS customeremail
 
 451        LEFT JOIN contacts cp on ct.id = cp.cp_cv_id
 
 452        WHERE (ct.id = ?) $where
 
 455   my $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
 
 457   # remove id and taxincluded before copy back
 
 458   delete @$ref{qw(id taxincluded)};
 
 460   @wanted_vars = grep({ $_ } @wanted_vars);
 
 461   if (scalar(@wanted_vars) > 0) {
 
 463     map({ $h_wanted_vars{$_} = 1; } @wanted_vars);
 
 464     map({ delete($ref->{$_}) unless ($h_wanted_vars{$_}); } keys(%{$ref}));
 
 467   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 469   if ($form->{delivery_customer_id}) {
 
 471       qq|SELECT *, notes as customernotes
 
 475     $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{delivery_customer_id}));
 
 477     map { $form->{"dc_$_"} = $ref->{$_} } keys %$ref;
 
 480   if ($form->{delivery_vendor_id}) {
 
 482       qq|SELECT *, notes as customernotes
 
 486     $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{delivery_vendor_id}));
 
 488     map { $form->{"dv_$_"} = $ref->{$_} } keys %$ref;
 
 491   my $custom_variables = CVar->get_custom_variables('dbh'      => $dbh,
 
 493                                                     'trans_id' => $form->{customer_id});
 
 494   map { $form->{"vc_cvar_$_->{name}"} = $_->{value} } @{ $custom_variables };
 
 496   $form->{cp_greeting} = GenericTranslations->get('dbh'              => $dbh,
 
 497                                                   'translation_type' => 'greetings::' . ($form->{cp_gender} eq 'f' ? 'female' : 'male'),
 
 498                                                   'language_id'      => $language_id,
 
 499                                                   'allow_fallback'   => 1);
 
 504   $main::lxdebug->leave_sub();
 
 508   $main::lxdebug->enter_sub();
 
 510   my ($self, $myconfig, $form, $provided_dbh, $payments_only) = @_;
 
 512   # connect to database, turn off autocommit
 
 513   my $dbh = $provided_dbh ? $provided_dbh : $form->dbconnect_noauto($myconfig);
 
 515   my ($query, $sth, $null, $project_id, @values);
 
 516   my $exchangerate = 0;
 
 518   my $ic_cvar_configs = CVar->get_configs(module => 'IC',
 
 521   if (!$form->{employee_id}) {
 
 522     $form->get_employee($dbh);
 
 525   $form->{defaultcurrency} = $form->get_default_currency($myconfig);
 
 527   ($null, $form->{department_id}) = split(/--/, $form->{department});
 
 529   my $all_units = AM->retrieve_units($myconfig, $form);
 
 531   if (!$payments_only) {
 
 533       &reverse_invoice($dbh, $form);
 
 536       $query = qq|SELECT nextval('glid')|;
 
 537       ($form->{"id"}) = selectrow_query($form, $dbh, $query);
 
 539       $query = qq|INSERT INTO ar (id, invnumber) VALUES (?, ?)|;
 
 540       do_query($form, $dbh, $query, $form->{"id"}, $form->{"id"});
 
 542       if (!$form->{invnumber}) {
 
 544           $form->update_defaults($myconfig, $form->{type} eq "credit_note" ?
 
 545                                  "cnnumber" : "invnumber", $dbh);
 
 550   my ($netamount, $invoicediff) = (0, 0);
 
 551   my ($amount, $linetotal, $lastincomeaccno);
 
 553   my ($currencies)    = selectfirst_array_query($form, $dbh, qq|SELECT curr FROM defaults|);
 
 554   my $defaultcurrency = (split m/:/, $currencies)[0];
 
 556   if ($form->{currency} eq $defaultcurrency) {
 
 557     $form->{exchangerate} = 1;
 
 559     $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'buy');
 
 562   $form->{exchangerate} =
 
 565     : $form->parse_amount($myconfig, $form->{exchangerate});
 
 567   $form->{expense_inventory} = "";
 
 571   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
 
 572   my %price_factors = map { $_->{id} => $_->{factor} } @{ $form->{ALL_PRICE_FACTORS} };
 
 575   $form->{amount}      = {};
 
 576   $form->{amount_cogs} = {};
 
 578   foreach my $i (1 .. $form->{rowcount}) {
 
 579     if ($form->{type} eq "credit_note") {
 
 580       $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}) * -1;
 
 581       $form->{shipped} = 1;
 
 583       $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
 
 588     $form->{"marge_percent_$i"} = $form->parse_amount($myconfig, $form->{"marge_percent_$i"}) * 1;
 
 589     $form->{"marge_total_$i"} = $form->parse_amount($myconfig, $form->{"marge_total_$i"}) * 1;
 
 590     $form->{"lastcost_$i"} = $form->{"lastcost_$i"} * 1;
 
 592     if ($form->{storno}) {
 
 593       $form->{"qty_$i"} *= -1;
 
 596     if ($form->{"id_$i"}) {
 
 599       if (defined($baseunits{$form->{"id_$i"}})) {
 
 600         $item_unit = $baseunits{$form->{"id_$i"}};
 
 603         $query = qq|SELECT unit FROM parts WHERE id = ?|;
 
 604         ($item_unit) = selectrow_query($form, $dbh, $query, conv_i($form->{"id_$i"}));
 
 605         $baseunits{$form->{"id_$i"}} = $item_unit;
 
 608       if (defined($all_units->{$item_unit}->{factor})
 
 609           && ($all_units->{$item_unit}->{factor} ne '')
 
 610           && ($all_units->{$item_unit}->{factor} != 0)) {
 
 611         $basefactor = $all_units->{$form->{"unit_$i"}}->{factor} / $all_units->{$item_unit}->{factor};
 
 615       $baseqty = $form->{"qty_$i"} * $basefactor;
 
 617       my ($allocated, $taxrate) = (0, 0);
 
 621       map { $taxrate += $form->{"${_}_rate"} } split(/ /, $form->{"taxaccounts_$i"});
 
 623       # keep entered selling price
 
 625         $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 627       my ($dec) = ($fxsellprice =~ /\.(\d+)/);
 
 629       my $decimalplaces = ($dec > 2) ? $dec : 2;
 
 631       # undo discount formatting
 
 632       $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
 
 635       $form->{"sellprice_$i"} = $fxsellprice * (1 - $form->{"discount_$i"});
 
 637       # round linetotal to 2 decimal places
 
 638       $price_factor = $price_factors{ $form->{"price_factor_id_$i"} } || 1;
 
 639       $linetotal    = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2);
 
 641       if ($form->{taxincluded}) {
 
 642         $taxamount = $linetotal * ($taxrate / (1 + $taxrate));
 
 643         $form->{"sellprice_$i"} =
 
 644           $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
 
 646         $taxamount = $linetotal * $taxrate;
 
 649       $netamount += $linetotal;
 
 651       if ($taxamount != 0) {
 
 653           $form->{amount}{ $form->{id} }{$_} +=
 
 654             $taxamount * $form->{"${_}_rate"} / $taxrate
 
 655         } split(/ /, $form->{"taxaccounts_$i"});
 
 658       # add amount to income, $form->{amount}{trans_id}{accno}
 
 659       $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate} / $price_factor;
 
 661       $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2) * $form->{exchangerate};
 
 662       $linetotal = $form->round_amount($linetotal, 2);
 
 664       # this is the difference from the inventory
 
 665       $invoicediff += ($amount - $linetotal);
 
 667       $form->{amount}{ $form->{id} }{ $form->{"income_accno_$i"} } +=
 
 670       $lastincomeaccno = $form->{"income_accno_$i"};
 
 672       # adjust and round sellprice
 
 673       $form->{"sellprice_$i"} =
 
 674         $form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate},
 
 677       next if $payments_only;
 
 679       if ($form->{"inventory_accno_$i"} || $form->{"assembly_$i"}) {
 
 681         if ($form->{"assembly_$i"}) {
 
 682           # record assembly item as allocated
 
 683           &process_assembly($dbh, $form, $form->{"id_$i"}, $baseqty);
 
 686           $allocated = &cogs($dbh, $form, $form->{"id_$i"}, $baseqty, $basefactor, $i);
 
 690       # get pricegroup_id and save it
 
 691       ($null, my $pricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
 
 694       my ($invoice_id) = selectfirst_array_query($form, $dbh, qq|SELECT nextval('invoiceid')|);
 
 696       # save detail record in invoice table
 
 698         qq|INSERT INTO invoice (id, trans_id, parts_id, description, longdescription, qty,
 
 699                                 sellprice, fxsellprice, discount, allocated, assemblyitem,
 
 700                                 unit, deliverydate, project_id, serialnumber, pricegroup_id,
 
 701                                 ordnumber, transdate, cusordnumber, base_qty, subtotal,
 
 702                                 marge_percent, marge_total, lastcost,
 
 703                                 price_factor_id, price_factor, marge_price_factor)
 
 704            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
 
 705                    (SELECT factor FROM price_factors WHERE id = ?), ?)|;
 
 707       @values = ($invoice_id, conv_i($form->{id}), conv_i($form->{"id_$i"}),
 
 708                  $form->{"description_$i"}, $form->{"longdescription_$i"}, $form->{"qty_$i"},
 
 709                  $form->{"sellprice_$i"}, $fxsellprice,
 
 710                  $form->{"discount_$i"}, $allocated, 'f',
 
 711                  $form->{"unit_$i"}, conv_date($form->{"reqdate_$i"}), conv_i($form->{"project_id_$i"}),
 
 712                  $form->{"serialnumber_$i"}, conv_i($pricegroup_id),
 
 713                  $form->{"ordnumber_$i"}, conv_date($form->{"transdate_$i"}),
 
 714                  $form->{"cusordnumber_$i"}, $baseqty, $form->{"subtotal_$i"} ? 't' : 'f',
 
 715                  $form->{"marge_percent_$i"}, $form->{"marge_total_$i"},
 
 716                  $form->{"lastcost_$i"},
 
 717                  conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
 
 718                  conv_i($form->{"marge_price_factor_$i"}));
 
 719       do_query($form, $dbh, $query, @values);
 
 721       if ($form->{lizenzen} && $form->{"licensenumber_$i"}) {
 
 723           qq|INSERT INTO licenseinvoice (trans_id, license_id)
 
 724              VALUES ((SELECT id FROM invoice WHERE trans_id = ? ORDER BY oid DESC LIMIT 1), ?)|;
 
 725         @values = (conv_i($form->{"id"}), conv_i($form->{"licensenumber_$i"}));
 
 726         do_query($form, $dbh, $query, @values);
 
 729       CVar->save_custom_variables(module       => 'IC',
 
 730                                   sub_module   => 'invoice',
 
 731                                   trans_id     => $invoice_id,
 
 732                                   configs      => $ic_cvar_configs,
 
 734                                   name_prefix  => 'ic_',
 
 735                                   name_postfix => "_$i",
 
 740   $form->{datepaid} = $form->{invdate};
 
 742   # total payments, don't move we need it here
 
 743   for my $i (1 .. $form->{paidaccounts}) {
 
 744     if ($form->{type} eq "credit_note") {
 
 745       $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"}) * -1;
 
 747       $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
 
 749     $form->{paid} += $form->{"paid_$i"};
 
 750     $form->{datepaid} = $form->{"datepaid_$i"} if ($form->{"datepaid_$i"});
 
 753   my ($tax, $diff) = (0, 0);
 
 755   $netamount = $form->round_amount($netamount, 2);
 
 757   # figure out rounding errors for total amount vs netamount + taxes
 
 758   if ($form->{taxincluded}) {
 
 760     $amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
 
 761     $diff += $amount - $netamount * $form->{exchangerate};
 
 762     $netamount = $amount;
 
 764     foreach my $item (split(/ /, $form->{taxaccounts})) {
 
 765       $amount = $form->{amount}{ $form->{id} }{$item} * $form->{exchangerate};
 
 766       $form->{amount}{ $form->{id} }{$item} = $form->round_amount($amount, 2);
 
 767       $tax += $form->{amount}{ $form->{id} }{$item};
 
 768       $netamount -= $form->{amount}{ $form->{id} }{$item};
 
 771     $invoicediff += $diff;
 
 772     ######## this only applies to tax included
 
 773     if ($lastincomeaccno) {
 
 774       $form->{amount}{ $form->{id} }{$lastincomeaccno} += $invoicediff;
 
 778     $amount    = $form->round_amount($netamount * $form->{exchangerate}, 2);
 
 779     $diff      = $amount - $netamount * $form->{exchangerate};
 
 780     $netamount = $amount;
 
 781     foreach my $item (split(/ /, $form->{taxaccounts})) {
 
 782       $form->{amount}{ $form->{id} }{$item} =
 
 783         $form->round_amount($form->{amount}{ $form->{id} }{$item}, 2);
 
 786                  $form->{amount}{ $form->{id} }{$item} * $form->{exchangerate},
 
 789         $amount - $form->{amount}{ $form->{id} }{$item} *
 
 790         $form->{exchangerate};
 
 791       $form->{amount}{ $form->{id} }{$item} = $form->round_amount($amount, 2);
 
 792       $tax += $form->{amount}{ $form->{id} }{$item};
 
 796   $form->{amount}{ $form->{id} }{ $form->{AR} } = $netamount + $tax;
 
 798     $form->round_amount($form->{paid} * $form->{exchangerate} + $diff, 2);
 
 801   $form->{amount}{ $form->{id} }{ $form->{AR} } *= -1;
 
 803   # update exchangerate
 
 804   if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
 
 805     $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate},
 
 806                                $form->{exchangerate}, 0);
 
 809   $project_id = conv_i($form->{"globalproject_id"});
 
 811   foreach my $trans_id (keys %{ $form->{amount_cogs} }) {
 
 812     foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
 
 813       next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
 
 815       $form->{amount_cogs}{$trans_id}{$accno} = $form->round_amount($form->{amount_cogs}{$trans_id}{$accno}, 2);
 
 817       if (!$payments_only && ($form->{amount_cogs}{$trans_id}{$accno} != 0)) {
 
 819           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
 
 820                VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, 0, ?)|;
 
 821         @values = (conv_i($trans_id), $accno, $form->{amount_cogs}{$trans_id}{$accno}, conv_date($form->{invdate}), conv_i($project_id));
 
 822         do_query($form, $dbh, $query, @values);
 
 823         $form->{amount_cogs}{$trans_id}{$accno} = 0;
 
 827     foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
 
 828       $form->{amount_cogs}{$trans_id}{$accno} = $form->round_amount($form->{amount_cogs}{$trans_id}{$accno}, 2);
 
 830       if (!$payments_only && ($form->{amount_cogs}{$trans_id}{$accno} != 0)) {
 
 832           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
 
 833                VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, 0, ?)|;
 
 834         @values = (conv_i($trans_id), $accno, $form->{amount_cogs}{$trans_id}{$accno}, conv_date($form->{invdate}), conv_i($project_id));
 
 835         do_query($form, $dbh, $query, @values);
 
 840   foreach my $trans_id (keys %{ $form->{amount} }) {
 
 841     foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
 
 842       next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
 
 844       $form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2);
 
 846       if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
 
 848           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
 
 849              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
 
 850                      (SELECT taxkey_id  FROM chart WHERE accno = ?), ?)|;
 
 851         @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_i($project_id));
 
 852         do_query($form, $dbh, $query, @values);
 
 853         $form->{amount}{$trans_id}{$accno} = 0;
 
 857     foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
 
 858       $form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2);
 
 860       if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
 
 862           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
 
 863              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
 
 864                      (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
 
 865         @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_i($project_id));
 
 866         do_query($form, $dbh, $query, @values);
 
 871   # deduct payment differences from diff
 
 872   for my $i (1 .. $form->{paidaccounts}) {
 
 873     if ($form->{"paid_$i"} != 0) {
 
 875         $form->round_amount($form->{"paid_$i"} * $form->{exchangerate}, 2);
 
 876       $diff -= $amount - $form->{"paid_$i"} * $form->{exchangerate};
 
 880   # record payments and offsetting AR
 
 881   if (!$form->{storno}) {
 
 882     for my $i (1 .. $form->{paidaccounts}) {
 
 884       next if ($form->{"paid_$i"} == 0);
 
 886       my ($accno) = split(/--/, $form->{"AR_paid_$i"});
 
 887       $form->{"datepaid_$i"} = $form->{invdate}
 
 888       unless ($form->{"datepaid_$i"});
 
 889       $form->{datepaid} = $form->{"datepaid_$i"};
 
 893       if ($form->{currency} eq $defaultcurrency) {
 
 894         $form->{"exchangerate_$i"} = 1;
 
 896         $exchangerate              = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy');
 
 897         $form->{"exchangerate_$i"} = $exchangerate || $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
 
 901       $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $diff, 2);
 
 903       if ($form->{amount}{ $form->{id} }{ $form->{AR} } != 0) {
 
 905         qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
 
 906            VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
 
 907                    (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
 
 908         @values = (conv_i($form->{"id"}), $form->{AR}, $amount, $form->{"datepaid_$i"}, $form->{AR}, $project_id);
 
 909         do_query($form, $dbh, $query, @values);
 
 913       $form->{"paid_$i"} *= -1;
 
 916       qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, source, memo, taxkey, project_id)
 
 917          VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, ?, ?,
 
 918                  (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
 
 919       @values = (conv_i($form->{"id"}), $accno, $form->{"paid_$i"}, $form->{"datepaid_$i"},
 
 920                  $form->{"source_$i"}, $form->{"memo_$i"}, $accno, $project_id);
 
 921       do_query($form, $dbh, $query, @values);
 
 923       # exchangerate difference
 
 924       $form->{fx}{$accno}{ $form->{"datepaid_$i"} } +=
 
 925       $form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $diff;
 
 929       $form->{"paid_$i"} * $form->{exchangerate} - $form->{"paid_$i"} *
 
 930       $form->{"exchangerate_$i"};
 
 932         $form->{fx}{ $form->{fxgain_accno} }{ $form->{"datepaid_$i"} } +=
 
 935         $form->{fx}{ $form->{fxloss_accno} }{ $form->{"datepaid_$i"} } +=
 
 941       # update exchange rate
 
 942       if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
 
 943         $form->update_exchangerate($dbh, $form->{currency},
 
 944                                    $form->{"datepaid_$i"},
 
 945                                    $form->{"exchangerate_$i"}, 0);
 
 949   } else {                      # if (!$form->{storno})
 
 950     $form->{marge_total} *= -1;
 
 953   if ($payments_only) {
 
 954     $query = qq|UPDATE ar SET paid = ?, datepaid = ? WHERE id = ?|;
 
 955     do_query($form, $dbh, $query,  $form->{paid}, $form->{paid} ? conv_date($form->{datepaid}) : undef, conv_i($form->{id}));
 
 957     if (!$provided_dbh) {
 
 962     $main::lxdebug->leave_sub();
 
 966   # record exchange rate differences and gains/losses
 
 967   foreach my $accno (keys %{ $form->{fx} }) {
 
 968     foreach my $transdate (keys %{ $form->{fx}{$accno} }) {
 
 970           ($form->{fx}{$accno}{$transdate} =
 
 971            $form->round_amount($form->{fx}{$accno}{$transdate}, 2)
 
 976           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, cleared, fx_transaction, taxkey, project_id)
 
 977              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, '0', '1',
 
 978              (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
 
 979         @values = (conv_i($form->{"id"}), $accno, $form->{fx}{$accno}{$transdate}, conv_date($transdate), $accno, $project_id);
 
 980         do_query($form, $dbh, $query, @values);
 
 985   $amount = $netamount + $tax;
 
 988   #erweiterung fuer lieferscheinnummer (donumber) 12.02.09 jb
 
 990   $query = qq|UPDATE ar set
 
 991                 invnumber   = ?, ordnumber     = ?, quonumber     = ?, cusordnumber  = ?,
 
 992                 transdate   = ?, orddate       = ?, quodate       = ?, customer_id   = ?,
 
 993                 amount      = ?, netamount     = ?, paid          = ?, datepaid      = ?,
 
 994                 duedate     = ?, deliverydate  = ?, invoice       = ?, shippingpoint = ?,
 
 995                 shipvia     = ?, terms         = ?, notes         = ?, intnotes      = ?,
 
 996                 curr        = ?, department_id = ?, payment_id    = ?, taxincluded   = ?,
 
 997                 type        = ?, language_id   = ?, taxzone_id    = ?, shipto_id     = ?,
 
 998                 employee_id = ?, salesman_id   = ?, storno_id     = ?, storno        = ?,
 
 999                 cp_id       = ?, marge_total   = ?, marge_percent = ?,
 
1000                 globalproject_id               = ?, delivery_customer_id             = ?,
 
1001                 transaction_description        = ?, delivery_vendor_id               = ?,
 
1004   @values = (          $form->{"invnumber"},           $form->{"ordnumber"},             $form->{"quonumber"},          $form->{"cusordnumber"},
 
1005              conv_date($form->{"invdate"}),  conv_date($form->{"orddate"}),    conv_date($form->{"quodate"}),    conv_i($form->{"customer_id"}),
 
1006                        $amount,                        $netamount,                       $form->{"paid"},     conv_date($form->{"datepaid"}),
 
1007              conv_date($form->{"duedate"}),  conv_date($form->{"deliverydate"}),    '1',                                $form->{"shippingpoint"},
 
1008                        $form->{"shipvia"},      conv_i($form->{"terms"}),                $form->{"notes"},              $form->{"intnotes"},
 
1009                        $form->{"currency"},     conv_i($form->{"department_id"}), conv_i($form->{"payment_id"}),        $form->{"taxincluded"} ? 't' : 'f',
 
1010                        $form->{"type"},         conv_i($form->{"language_id"}),   conv_i($form->{"taxzone_id"}), conv_i($form->{"shipto_id"}),
 
1011                 conv_i($form->{"employee_id"}), conv_i($form->{"salesman_id"}),   conv_i($form->{storno_id}),           $form->{"storno"} ? 't' : 'f',
 
1012                 conv_i($form->{"cp_id"}),            1 * $form->{marge_total} ,      1 * $form->{marge_percent},
 
1013                 conv_i($form->{"globalproject_id"}),                              conv_i($form->{"delivery_customer_id"}),
 
1014                        $form->{transaction_description},                          conv_i($form->{"delivery_vendor_id"}),
 
1015                        $form->{"donumber"}, #das entsprechende feld lieferscheinnummer aus der html-form 12.02.09 jb
 
1016                 conv_i($form->{"id"}));
 
1017   do_query($form, $dbh, $query, @values);
 
1019   if($form->{"formname"} eq "credit_note") {
 
1020     for my $i (1 .. $form->{rowcount}) {
 
1021       $query = qq|UPDATE parts SET onhand = onhand - ? WHERE id = ?|;
 
1022       @values = (conv_i($form->{"qty_$i"}), conv_i($form->{"id_$i"}));
 
1023       do_query($form, $dbh, $query, @values);
 
1027   if ($form->{storno}) {
 
1030            paid = paid + amount,
 
1032            intnotes = ? || intnotes
 
1034     do_query($form, $dbh, $query, "Rechnung storniert am $form->{invdate} ", conv_i($form->{"storno_id"}));
 
1035     do_query($form, $dbh, qq|UPDATE ar SET paid = amount WHERE id = ?|, conv_i($form->{"id"}));
 
1039   $form->{name} = $form->{customer};
 
1040   $form->{name} =~ s/--\Q$form->{customer_id}\E//;
 
1042   if (!$form->{shipto_id}) {
 
1043     $form->add_shipto($dbh, $form->{id}, "AR");
 
1046   # save printed, emailed and queued
 
1047   $form->save_status($dbh);
 
1049   Common::webdav_folder($form) if ($main::webdav);
 
1051   # Link this record to the records it was created from.
 
1052   RecordLinks->create_links('dbh'        => $dbh,
 
1054                             'from_table' => 'oe',
 
1055                             'from_ids'   => $form->{convert_from_oe_ids},
 
1057                             'to_id'      => $form->{id},
 
1059   delete $form->{convert_from_oe_ids};
 
1061   my @convert_from_do_ids = map { $_ * 1 } grep { $_ } split m/\s+/, $form->{convert_from_do_ids};
 
1063   if (scalar @convert_from_do_ids) {
 
1064     DO->close_orders('dbh' => $dbh,
 
1065                      'ids' => \@convert_from_do_ids);
 
1067     RecordLinks->create_links('dbh'        => $dbh,
 
1069                               'from_table' => 'delivery_orders',
 
1070                               'from_ids'   => \@convert_from_do_ids,
 
1072                               'to_id'      => $form->{id},
 
1075   delete $form->{convert_from_do_ids};
 
1077   ARAP->close_orders_if_billed('dbh'     => $dbh,
 
1078                                'arap_id' => $form->{id},
 
1082   if (!$provided_dbh) {
 
1087   $main::lxdebug->leave_sub();
 
1092 sub _delete_payments {
 
1093   $main::lxdebug->enter_sub();
 
1095   my ($self, $form, $dbh) = @_;
 
1097   my @delete_acc_trans_ids;
 
1099   # Delete old payment entries from acc_trans.
 
1101     qq|SELECT acc_trans_id
 
1103        WHERE (trans_id = ?) AND fx_transaction
 
1107        SELECT at.acc_trans_id
 
1109        LEFT JOIN chart c ON (at.chart_id = c.id)
 
1110        WHERE (trans_id = ?) AND (c.link LIKE '%AR_paid%')|;
 
1111   push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}), conv_i($form->{id}));
 
1114     qq|SELECT at.acc_trans_id
 
1116        LEFT JOIN chart c ON (at.chart_id = c.id)
 
1117        WHERE (trans_id = ?)
 
1118          AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
 
1119        ORDER BY at.acc_trans_id
 
1121   push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}));
 
1123   if (@delete_acc_trans_ids) {
 
1124     $query = qq|DELETE FROM acc_trans WHERE acc_trans_id IN (| . join(", ", @delete_acc_trans_ids) . qq|)|;
 
1125     do_query($form, $dbh, $query);
 
1128   $main::lxdebug->leave_sub();
 
1132   $main::lxdebug->enter_sub();
 
1134   my ($self, $myconfig, $form, $locale) = @_;
 
1136   # connect to database, turn off autocommit
 
1137   my $dbh = $form->dbconnect_noauto($myconfig);
 
1139   my (%payments, $old_form, $row, $item, $query, %keep_vars);
 
1141   $old_form = save_form();
 
1143   # Delete all entries in acc_trans from prior payments.
 
1144   $self->_delete_payments($form, $dbh);
 
1146   # Save the new payments the user made before cleaning up $form.
 
1147   map { $payments{$_} = $form->{$_} } grep m/^datepaid_\d+$|^memo_\d+$|^source_\d+$|^exchangerate_\d+$|^paid_\d+$|^AR_paid_\d+$|^paidaccounts$/, keys %{ $form };
 
1149   # Clean up $form so that old content won't tamper the results.
 
1150   %keep_vars = map { $_, 1 } qw(login password id);
 
1151   map { delete $form->{$_} unless $keep_vars{$_} } keys %{ $form };
 
1153   # Retrieve the invoice from the database.
 
1154   $self->retrieve_invoice($myconfig, $form);
 
1156   # Set up the content of $form in the way that IS::post_invoice() expects.
 
1157   $form->{exchangerate} = $form->format_amount($myconfig, $form->{exchangerate});
 
1159   for $row (1 .. scalar @{ $form->{invoice_details} }) {
 
1160     $item = $form->{invoice_details}->[$row - 1];
 
1162     map { $item->{$_} = $form->format_amount($myconfig, $item->{$_}) } qw(qty sellprice discount);
 
1164     map { $form->{"${_}_${row}"} = $item->{$_} } keys %{ $item };
 
1167   $form->{rowcount} = scalar @{ $form->{invoice_details} };
 
1169   delete @{$form}{qw(invoice_details paidaccounts storno paid)};
 
1171   # Restore the payment options from the user input.
 
1172   map { $form->{$_} = $payments{$_} } keys %payments;
 
1174   # Get the AR accno (which is normally done by Form::create_links()).
 
1178        LEFT JOIN chart c ON (at.chart_id = c.id)
 
1179        WHERE (trans_id = ?)
 
1180          AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
 
1181        ORDER BY at.acc_trans_id
 
1184   ($form->{AR}) = selectfirst_array_query($form, $dbh, $query, conv_i($form->{id}));
 
1186   # Post the new payments.
 
1187   $self->post_invoice($myconfig, $form, $dbh, 1);
 
1189   restore_form($old_form);
 
1191   my $rc = $dbh->commit();
 
1194   $main::lxdebug->leave_sub();
 
1199 sub process_assembly {
 
1200   $main::lxdebug->enter_sub();
 
1202   my ($dbh, $form, $id, $totalqty) = @_;
 
1205     qq|SELECT a.parts_id, a.qty, p.assembly, p.partnumber, p.description, p.unit,
 
1206          p.inventory_accno_id, p.income_accno_id, p.expense_accno_id
 
1208        JOIN parts p ON (a.parts_id = p.id)
 
1210   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
 
1212   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1216     $ref->{inventory_accno_id} *= 1;
 
1217     $ref->{expense_accno_id}   *= 1;
 
1219     # multiply by number of assemblies
 
1220     $ref->{qty} *= $totalqty;
 
1222     if ($ref->{assembly}) {
 
1223       &process_assembly($dbh, $form, $ref->{parts_id}, $ref->{qty});
 
1226       if ($ref->{inventory_accno_id}) {
 
1227         $allocated = &cogs($dbh, $form, $ref->{parts_id}, $ref->{qty});
 
1231     # save detail record for individual assembly item in invoice table
 
1233       qq|INSERT INTO invoice (trans_id, description, parts_id, qty, sellprice, fxsellprice, allocated, assemblyitem, unit)
 
1234          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)|;
 
1235     my @values = (conv_i($form->{id}), $ref->{description}, conv_i($ref->{parts_id}), $ref->{qty}, 0, 0, $allocated, 't', $ref->{unit});
 
1236     do_query($form, $dbh, $query, @values);
 
1242   $main::lxdebug->leave_sub();
 
1246   $main::lxdebug->enter_sub();
 
1248   my ($dbh, $form, $id, $totalqty, $basefactor, $row) = @_;
 
1252   $form->{taxzone_id} *=1;
 
1253   my $transdate  = $form->{invdate} ? $dbh->quote($form->{invdate}) : "current_date";
 
1254   my $taxzone_id = $form->{"taxzone_id"} * 1;
 
1256     qq|SELECT i.id, i.trans_id, i.base_qty, i.allocated, i.sellprice,
 
1257          c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
 
1258          c2.accno AS    income_accno, c2.new_chart_id AS    income_new_chart, date($transdate) - c2.valid_from AS    income_valid,
 
1259          c3.accno AS   expense_accno, c3.new_chart_id AS   expense_new_chart, date($transdate) - c3.valid_from AS   expense_valid
 
1260        FROM invoice i, parts p
 
1261        LEFT JOIN chart c1 ON ((SELECT inventory_accno_id FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
 
1262        LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
 
1263        LEFT JOIN chart c3 ON ((select expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
 
1264        WHERE (i.parts_id = p.id)
 
1265          AND (i.parts_id = ?)
 
1266          AND ((i.base_qty + i.allocated) < 0)
 
1268   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
 
1273   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1274     if (($qty = (($ref->{base_qty} * -1) - $ref->{allocated})) > $totalqty) {
 
1278     $form->update_balance($dbh, "invoice", "allocated", qq|id = $ref->{id}|, $qty);
 
1280     # total expenses and inventory
 
1281     # sellprice is the cost of the item
 
1282     my $linetotal = $form->round_amount(($ref->{sellprice} * $qty) / ( $basefactor || 1 ), 2);
 
1285       $ref->{expense_accno} = ($form->{"expense_accno_$row"}) ? $form->{"expense_accno_$row"} : $ref->{expense_accno};
 
1287       $form->{amount_cogs}{ $form->{id} }{ $ref->{expense_accno} } += -$linetotal;
 
1288       $form->{expense_inventory} .= " " . $ref->{expense_accno};
 
1289       $ref->{inventory_accno} = ($form->{"inventory_accno_$row"}) ? $form->{"inventory_accno_$row"} : $ref->{inventory_accno};
 
1291       $form->{amount_cogs}{ $form->{id} }{ $ref->{inventory_accno} } -= -$linetotal;
 
1292       $form->{expense_inventory} .= " " . $ref->{inventory_accno};
 
1298     last if (($totalqty -= $qty) <= 0);
 
1303   $main::lxdebug->leave_sub();
 
1308 sub reverse_invoice {
 
1309   $main::lxdebug->enter_sub();
 
1311   my ($dbh, $form) = @_;
 
1313   # reverse inventory items
 
1315     qq|SELECT i.id, i.parts_id, i.qty, i.assemblyitem, p.assembly, p.inventory_accno_id
 
1317        JOIN parts p ON (i.parts_id = p.id)
 
1318        WHERE i.trans_id = ?|;
 
1319   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id"}));
 
1321   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1323     if ($ref->{inventory_accno_id}) {
 
1324       # de-allocated purchases
 
1326         qq|SELECT i.id, i.trans_id, i.allocated
 
1328            WHERE (i.parts_id = ?) AND (i.allocated > 0)
 
1329            ORDER BY i.trans_id DESC|;
 
1330       my $sth2 = prepare_execute_query($form, $dbh, $query, conv_i($ref->{"parts_id"}));
 
1332       while (my $inhref = $sth2->fetchrow_hashref('NAME_lc')) {
 
1333         my $qty = $ref->{qty};
 
1334         if (($ref->{qty} - $inhref->{allocated}) > 0) {
 
1335           $qty = $inhref->{allocated};
 
1339         $form->update_balance($dbh, "invoice", "allocated", qq|id = $inhref->{id}|, $qty * -1);
 
1341         last if (($ref->{qty} -= $qty) <= 0);
 
1350   my @values = (conv_i($form->{id}));
 
1351   do_query($form, $dbh, qq|DELETE FROM acc_trans WHERE trans_id = ?|, @values);
 
1352   do_query($form, $dbh, qq|DELETE FROM invoice WHERE trans_id = ?|, @values);
 
1354   if ($form->{lizenzen}) {
 
1356       qq|DELETE FROM licenseinvoice
 
1357          WHERE trans_id in (SELECT id FROM invoice WHERE trans_id = ?)|;
 
1358     do_query($form, $dbh, $query, @values);
 
1361   do_query($form, $dbh, qq|DELETE FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|, @values);
 
1363   $main::lxdebug->leave_sub();
 
1366 sub delete_invoice {
 
1367   $main::lxdebug->enter_sub();
 
1369   my ($self, $myconfig, $form, $spool) = @_;
 
1371   # connect to database
 
1372   my $dbh = $form->dbconnect_noauto($myconfig);
 
1374   &reverse_invoice($dbh, $form);
 
1376   my @values = (conv_i($form->{id}));
 
1379   do_query($form, $dbh, qq|DELETE FROM ar WHERE id = ?|, @values);
 
1381   # delete spool files
 
1382   my @spoolfiles = selectall_array_query($form, $dbh, qq|SELECT spoolfile FROM status WHERE trans_id = ?|, @values);
 
1384   # delete status entries
 
1385   do_query($form, $dbh, qq|DELETE FROM status WHERE trans_id = ?|, @values);
 
1387   my $rc = $dbh->commit;
 
1391     map { unlink "$spool/$_" if -f "$spool/$_"; } @spoolfiles;
 
1394   $main::lxdebug->leave_sub();
 
1399 sub retrieve_invoice {
 
1400   $main::lxdebug->enter_sub();
 
1402   my ($self, $myconfig, $form) = @_;
 
1404   # connect to database
 
1405   my $dbh = $form->dbconnect_noauto($myconfig);
 
1407   my ($sth, $ref, $query);
 
1409   my $query_transdate = ", current_date AS invdate" if !$form->{id};
 
1413          (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
 
1414          (SELECT c.accno FROM chart c WHERE d.income_accno_id = c.id)    AS income_accno,
 
1415          (SELECT c.accno FROM chart c WHERE d.expense_accno_id = c.id)   AS expense_accno,
 
1416          (SELECT c.accno FROM chart c WHERE d.fxgain_accno_id = c.id)    AS fxgain_accno,
 
1417          (SELECT c.accno FROM chart c WHERE d.fxloss_accno_id = c.id)    AS fxloss_accno,
 
1418          d.curr AS currencies
 
1422   $ref = selectfirst_hashref_query($form, $dbh, $query);
 
1423   map { $form->{$_} = $ref->{$_} } keys %{ $ref };
 
1426     my $id = conv_i($form->{id});
 
1429     #erweiterung um das entsprechende feld lieferscheinnummer (a.donumber) in der html-maske anzuzeigen 12.02.2009 jb
 
1433            a.invnumber, a.ordnumber, a.quonumber, a.cusordnumber,
 
1434            a.orddate, a.quodate, a.globalproject_id,
 
1435            a.transdate AS invdate, a.deliverydate, a.paid, a.storno, a.gldate,
 
1436            a.shippingpoint, a.shipvia, a.terms, a.notes, a.intnotes, a.taxzone_id,
 
1437            a.duedate, a.taxincluded, a.curr AS currency, a.shipto_id, a.cp_id,
 
1438            a.employee_id, a.salesman_id, a.payment_id,
 
1439            a.language_id, a.delivery_customer_id, a.delivery_vendor_id, a.type,
 
1440            a.transaction_description,
 
1441            a.marge_total, a.marge_percent,
 
1442            e.name AS employee, a.donumber
 
1444          LEFT JOIN employee e ON (e.id = a.employee_id)
 
1446     $ref = selectfirst_hashref_query($form, $dbh, $query, $id);
 
1447     map { $form->{$_} = $ref->{$_} } keys %{ $ref };
 
1450     $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "buy");
 
1453     $query = qq|SELECT * FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|;
 
1454     $ref = selectfirst_hashref_query($form, $dbh, $query, $id);
 
1456     map { $form->{$_} = $ref->{$_} } keys %{ $ref };
 
1458     foreach my $vc (qw(customer vendor)) {
 
1459       next if !$form->{"delivery_${vc}_id"};
 
1460       ($form->{"delivery_${vc}_string"}) = selectrow_query($form, $dbh, qq|SELECT name FROM customer WHERE id = ?|, $id);
 
1463     # get printed, emailed
 
1464     $query = qq|SELECT printed, emailed, spoolfile, formname FROM status WHERE trans_id = ?|;
 
1465     $sth = prepare_execute_query($form, $dbh, $query, $id);
 
1467     while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1468       $form->{printed} .= "$ref->{formname} " if $ref->{printed};
 
1469       $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
 
1470       $form->{queued} .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
 
1473     map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
 
1475     my $transdate = $form->{deliverydate} ? $dbh->quote($form->{deliverydate})
 
1476                   : $form->{invdate}      ? $dbh->quote($form->{invdate})
 
1480     my $taxzone_id = $form->{taxzone_id} *= 1;
 
1481     $taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
 
1483     # retrieve individual items
 
1486            c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
 
1487            c2.accno AS income_accno,    c2.new_chart_id AS income_new_chart,    date($transdate) - c2.valid_from as income_valid,
 
1488            c3.accno AS expense_accno,   c3.new_chart_id AS expense_new_chart,   date($transdate) - c3.valid_from AS expense_valid,
 
1491            i.description, i.longdescription, i.qty, i.fxsellprice AS sellprice, i.discount, i.parts_id AS id, i.unit, i.deliverydate AS reqdate,
 
1492            i.project_id, i.serialnumber, i.id AS invoice_pos, i.pricegroup_id, i.ordnumber, i.transdate, i.cusordnumber, i.subtotal, i.lastcost,
 
1493            i.price_factor_id, i.price_factor, i.marge_price_factor,
 
1494            p.partnumber, p.assembly, p.bin, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id, p.formel,
 
1495            pr.projectnumber, pg.partsgroup, prg.pricegroup
 
1498          LEFT JOIN parts p ON (i.parts_id = p.id)
 
1499          LEFT JOIN project pr ON (i.project_id = pr.id)
 
1500          LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
 
1501          LEFT JOIN pricegroup prg ON (i.pricegroup_id = prg.id)
 
1503          LEFT JOIN chart c1 ON ((SELECT inventory_accno_id             FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
 
1504          LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id}  FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
 
1505          LEFT JOIN chart c3 ON ((SELECT expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
 
1507          WHERE (i.trans_id = ?) AND NOT (i.assemblyitem = '1') ORDER BY i.id|;
 
1509     $sth = prepare_execute_query($form, $dbh, $query, $id);
 
1511     while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1512       # Retrieve custom variables.
 
1513       my $cvars = CVar->get_custom_variables(dbh        => $dbh,
 
1515                                              sub_module => 'invoice',
 
1516                                              trans_id   => $ref->{invoice_id},
 
1518       map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
 
1519       delete $ref->{invoice_id};
 
1521       map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid)) if !$ref->{"part_inventory_accno_id"};
 
1522       delete($ref->{"part_inventory_accno_id"});
 
1524       foreach my $type (qw(inventory income expense)) {
 
1525         while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
 
1526           my $query = qq|SELECT accno, new_chart_id, date($transdate) - valid_from FROM chart WHERE id = ?|;
 
1527           @$ref{ map $type.$_, qw(_accno _new_chart _valid) } = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
 
1531       # get tax rates and description
 
1532       my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
 
1534         qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber FROM tax t
 
1535            LEFT JOIN chart c ON (c.id = t.chart_id)
 
1537              (SELECT tk.tax_id FROM taxkeys tk
 
1538               WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?)
 
1539                 AND startdate <= date($transdate)
 
1540               ORDER BY startdate DESC LIMIT 1)
 
1542       my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
 
1543       $ref->{taxaccounts} = "";
 
1545       while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
 
1547         if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
 
1551         $ref->{taxaccounts} .= "$ptr->{accno} ";
 
1553         if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
 
1554           $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
 
1555           $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
 
1556           $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
 
1557           $form->{taxaccounts} .= "$ptr->{accno} ";
 
1562       if ($form->{lizenzen}) {
 
1563         $query = qq|SELECT l.licensenumber, l.id AS licenseid FROM license l, licenseinvoice li WHERE l.id = li.license_id AND li.trans_id = ?|;
 
1564         my ($licensenumber, $licenseid) = selectrow_query($form, $dbh, $query, conv_i($ref->{invoice_pos}));
 
1565         $ref->{lizenzen} = "<option value=\"$licenseid\">$licensenumber</option>";
 
1568       $ref->{qty} *= -1 if $form->{type} eq "credit_note";
 
1570       chop $ref->{taxaccounts};
 
1571       push @{ $form->{invoice_details} }, $ref;
 
1576     Common::webdav_folder($form) if ($main::webdav);
 
1579   my $rc = $dbh->commit;
 
1582   $main::lxdebug->leave_sub();
 
1588   $main::lxdebug->enter_sub();
 
1590   my ($self, $myconfig, $form) = @_;
 
1592   # connect to database
 
1593   my $dbh = $form->dbconnect($myconfig);
 
1595   my $dateformat = $myconfig->{dateformat};
 
1596   $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/;
 
1598   my (@values, $duedate, $ref, $query);
 
1600   if ($form->{invdate}) {
 
1601     $duedate = "to_date(?, '$dateformat')";
 
1602     push @values, $form->{invdate};
 
1604     $duedate = "current_date";
 
1607   my $cid = conv_i($form->{customer_id});
 
1610   if ($form->{payment_id}) {
 
1611     $payment_id = "(pt.id = ?) OR";
 
1612     push @values, conv_i($form->{payment_id});
 
1618          c.id AS customer_id, c.name AS customer, c.discount as customer_discount, c.creditlimit, c.terms,
 
1619          c.email, c.cc, c.bcc, c.language_id, c.payment_id,
 
1620          c.street, c.zipcode, c.city, c.country,
 
1621          c.notes AS intnotes, c.klass as customer_klass, c.taxzone_id, c.salesman_id,
 
1622          $duedate + COALESCE(pt.terms_netto, 0) AS duedate,
 
1623          b.discount AS tradediscount, b.description AS business
 
1625        LEFT JOIN business b ON (b.id = c.business_id)
 
1626        LEFT JOIN payment_terms pt ON ($payment_id (c.payment_id = pt.id))
 
1629   $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
 
1631   delete $ref->{salesman_id} if !$ref->{salesman_id};
 
1633   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1636     qq|SELECT sum(amount - paid) AS dunning_amount
 
1638        WHERE (paid < amount)
 
1639          AND (customer_id = ?)
 
1640          AND (dunning_config_id IS NOT NULL)|;
 
1641   $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
 
1642   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1645     qq|SELECT dnn.dunning_description AS max_dunning_level
 
1646        FROM dunning_config dnn
 
1647        WHERE id IN (SELECT dunning_config_id
 
1649                     WHERE (paid < amount) AND (customer_id = ?) AND (dunning_config_id IS NOT NULL))
 
1650        ORDER BY dunning_level DESC LIMIT 1|;
 
1651   $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
 
1652   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1654   $form->{creditremaining} = $form->{creditlimit};
 
1655   $query = qq|SELECT SUM(amount - paid) FROM ar WHERE customer_id = ?|;
 
1656   my ($value) = selectrow_query($form, $dbh, $query, $cid);
 
1657   $form->{creditremaining} -= $value;
 
1661          (SELECT e.buy FROM exchangerate e
 
1662           WHERE e.curr = o.curr
 
1663             AND e.transdate = o.transdate)
 
1665        WHERE o.customer_id = ?
 
1666          AND o.quotation = '0'
 
1667          AND o.closed = '0'|;
 
1668   my $sth = prepare_execute_query($form, $dbh, $query, $cid);
 
1670   while (my ($amount, $exch) = $sth->fetchrow_array) {
 
1671     $exch = 1 unless $exch;
 
1672     $form->{creditremaining} -= $amount * $exch;
 
1676   # get shipto if we did not converted an order or invoice
 
1677   if (!$form->{shipto}) {
 
1678     map { delete $form->{$_} }
 
1679       qw(shiptoname shiptodepartment_1 shiptodepartment_2
 
1680          shiptostreet shiptozipcode shiptocity shiptocountry
 
1681          shiptocontact shiptophone shiptofax shiptoemail);
 
1683     $query = qq|SELECT * FROM shipto WHERE trans_id = ? AND module = 'CT'|;
 
1684     $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
 
1686     map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1689   # setup last accounts used for this customer
 
1690   if (!$form->{id} && $form->{type} !~ /_(order|quotation)/) {
 
1692       qq|SELECT c.id, c.accno, c.description, c.link, c.category
 
1694          JOIN acc_trans ac ON (ac.chart_id = c.id)
 
1695          JOIN ar a ON (a.id = ac.trans_id)
 
1696          WHERE a.customer_id = ?
 
1697            AND NOT (c.link LIKE '%_tax%' OR c.link LIKE '%_paid%')
 
1698            AND a.id IN (SELECT max(a2.id) FROM ar a2 WHERE a2.customer_id = ?)|;
 
1699     $sth = prepare_execute_query($form, $dbh, $query, $cid, $cid);
 
1702     while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1703       if ($ref->{category} eq 'I') {
 
1705         $form->{"AR_amount_$i"} = "$ref->{accno}--$ref->{description}";
 
1707         if ($form->{initial_transdate}) {
 
1709             qq|SELECT tk.tax_id, t.rate
 
1711                LEFT JOIN tax t ON tk.tax_id = t.id
 
1712                WHERE (tk.chart_id = ?) AND (startdate <= date(?))
 
1713                ORDER BY tk.startdate DESC
 
1715           my ($tax_id, $rate) =
 
1716             selectrow_query($form, $dbh, $tax_query, $ref->{id},
 
1717                             $form->{initial_transdate});
 
1718           $form->{"taxchart_$i"} = "${tax_id}--${rate}";
 
1721       if ($ref->{category} eq 'A') {
 
1722         $form->{ARselected} = $form->{AR_1} = $ref->{accno};
 
1726     $form->{rowcount} = $i if ($i && !$form->{type});
 
1731   $main::lxdebug->leave_sub();
 
1735   $main::lxdebug->enter_sub();
 
1737   my ($self, $myconfig, $form) = @_;
 
1739   # connect to database
 
1740   my $dbh = $form->dbconnect($myconfig);
 
1742   my $i = $form->{rowcount};
 
1744   my $where = qq|NOT p.obsolete = '1'|;
 
1747   foreach my $column (qw(p.partnumber p.description pgpartsgroup )) {
 
1748     my ($table, $field) = split m/\./, $column;
 
1749     next if !$form->{"${field}_${i}"};
 
1750     $where .= qq| AND lower(${column}) ILIKE ?|;
 
1751     push @values, '%' . $form->{"${field}_${i}"} . '%';
 
1754   #Es soll auch nach EAN gesucht werden, ohne Einschränkung durch Beschreibung
 
1755   if ($form->{"partnumber_$i"} && !$form->{"description_$i"}) {
 
1756         $where .= qq| OR (NOT p.obsolete = '1' AND p.ean = ? )|;
 
1757         push @values, $form->{"partnumber_$i"};
 
1760   if ($form->{"description_$i"}) {
 
1761     $where .= qq| ORDER BY p.description|;
 
1763     $where .= qq| ORDER BY p.partnumber|;
 
1767   if ($form->{type} eq "invoice") {
 
1769       $form->{deliverydate} ? $dbh->quote($form->{deliverydate}) :
 
1770       $form->{invdate}      ? $dbh->quote($form->{invdate}) :
 
1774       $form->{transdate}    ? $dbh->quote($form->{transdate}) :
 
1778   my $taxzone_id = $form->{taxzone_id} * 1;
 
1779   $taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
 
1783          p.id, p.partnumber, p.description, p.sellprice,
 
1784          p.listprice, p.inventory_accno_id, p.lastcost,
 
1786          c1.accno AS inventory_accno,
 
1787          c1.new_chart_id AS inventory_new_chart,
 
1788          date($transdate) - c1.valid_from AS inventory_valid,
 
1790          c2.accno AS income_accno,
 
1791          c2.new_chart_id AS income_new_chart,
 
1792          date($transdate)  - c2.valid_from AS income_valid,
 
1794          c3.accno AS expense_accno,
 
1795          c3.new_chart_id AS expense_new_chart,
 
1796          date($transdate) - c3.valid_from AS expense_valid,
 
1798          p.unit, p.assembly, p.bin, p.onhand,
 
1799          p.notes AS partnotes, p.notes AS longdescription,
 
1800          p.not_discountable, p.formel, p.payment_id AS part_payment_id,
 
1803          pfac.factor AS price_factor,
 
1808        LEFT JOIN chart c1 ON
 
1809          ((SELECT inventory_accno_id
 
1810            FROM buchungsgruppen
 
1811            WHERE id = p.buchungsgruppen_id) = c1.id)
 
1812        LEFT JOIN chart c2 ON
 
1813          ((SELECT income_accno_id_${taxzone_id}
 
1814            FROM buchungsgruppen
 
1815            WHERE id = p.buchungsgruppen_id) = c2.id)
 
1816        LEFT JOIN chart c3 ON
 
1817          ((SELECT expense_accno_id_${taxzone_id}
 
1818            FROM buchungsgruppen
 
1819            WHERE id = p.buchungsgruppen_id) = c3.id)
 
1820        LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
 
1821        LEFT JOIN price_factors pfac ON (pfac.id = p.price_factor_id)
 
1823   my $sth = prepare_execute_query($form, $dbh, $query, @values);
 
1825   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1827     # In der Buchungsgruppe ist immer ein Bestandskonto verknuepft, auch wenn
 
1828     # es sich um eine Dienstleistung handelt. Bei Dienstleistungen muss das
 
1829     # Buchungskonto also aus dem Ergebnis rausgenommen werden.
 
1830     if (!$ref->{inventory_accno_id}) {
 
1831       map({ delete($ref->{"inventory_${_}"}); } qw(accno new_chart valid));
 
1833     delete($ref->{inventory_accno_id});
 
1835     foreach my $type (qw(inventory income expense)) {
 
1836       while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
 
1838           qq|SELECT accno, new_chart_id, date($transdate) - valid_from
 
1841         ($ref->{"${type}_accno"},
 
1842          $ref->{"${type}_new_chart"},
 
1843          $ref->{"${type}_valid"})
 
1844           = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
 
1848     if ($form->{payment_id} eq "") {
 
1849       $form->{payment_id} = $form->{part_payment_id};
 
1852     # get tax rates and description
 
1853     my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
 
1855       qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber
 
1857          LEFT JOIN chart c ON (c.id = t.chart_id)
 
1861             WHERE tk.chart_id = (SELECT id from chart WHERE accno = ?)
 
1863             ORDER BY startdate DESC
 
1866     @values = ($accno_id, $transdate eq "current_date" ? "now" : $transdate);
 
1867     my $stw = $dbh->prepare($query);
 
1868     $stw->execute(@values) || $form->dberror($query);
 
1870     $ref->{taxaccounts} = "";
 
1872     while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
 
1874       #    if ($customertax{$ref->{accno}})
 
1875       if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
 
1879       $ref->{taxaccounts} .= "$ptr->{accno} ";
 
1881       if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
 
1882         $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
 
1883         $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
 
1884         $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
 
1885         $form->{taxaccounts} .= "$ptr->{accno} ";
 
1891     chop $ref->{taxaccounts};
 
1892     if ($form->{language_id}) {
 
1894         qq|SELECT tr.translation, tr.longdescription
 
1896            WHERE tr.language_id = ? AND tr.parts_id = ?|;
 
1897       @values = (conv_i($form->{language_id}), conv_i($ref->{id}));
 
1898       my ($translation, $longdescription) = selectrow_query($form, $dbh, $query, @values);
 
1899       if ($translation ne "") {
 
1900         $ref->{description} = $translation;
 
1901         $ref->{longdescription} = $longdescription;
 
1905           qq|SELECT tr.translation, tr.longdescription
 
1907              WHERE tr.language_id IN
 
1910                 WHERE article_code = (SELECT article_code FROM language WHERE id = ?))
 
1913         @values = (conv_i($form->{language_id}), conv_i($ref->{id}));
 
1914         my ($translation, $longdescription) = selectrow_query($form, $dbh, $query, @values);
 
1915         if ($translation ne "") {
 
1916           $ref->{description} = $translation;
 
1917           $ref->{longdescription} = $longdescription;
 
1922     $ref->{onhand} *= 1;
 
1924     push @{ $form->{item_list} }, $ref;
 
1926     if ($form->{lizenzen}) {
 
1927       if ($ref->{inventory_accno} > 0) {
 
1931              WHERE l.parts_id = ? AND NOT l.id IN (SELECT li.license_id FROM licenseinvoice li)|;
 
1932         my $stw = prepare_execute_query($form, $dbh, $query, conv_i($ref->{id}));
 
1933         while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
 
1934           push @{ $form->{LIZENZEN}{ $ref->{id} } }, $ptr;
 
1942   foreach my $item (@{ $form->{item_list} }) {
 
1943     my $custom_variables = CVar->get_custom_variables(module   => 'IC',
 
1944                                                       trans_id => $item->{id},
 
1948     map { $item->{"ic_cvar_" . $_->{name} } = $_->{value} } @{ $custom_variables };
 
1953   $main::lxdebug->leave_sub();
 
1956 ##########################
 
1957 # get pricegroups from database
 
1958 # build up selected pricegroup
 
1959 # if an exchange rate - change price
 
1962 sub get_pricegroups_for_parts {
 
1964   $main::lxdebug->enter_sub();
 
1966   my ($self, $myconfig, $form) = @_;
 
1968   my $dbh = $form->dbconnect($myconfig);
 
1970   $form->{"PRICES"} = {};
 
1974   my $all_units = AM->retrieve_units($myconfig, $form);
 
1975   while (($form->{"id_$i"}) or ($form->{"new_id_$i"})) {
 
1976     $form->{"PRICES"}{$i} = [];
 
1978     $id = $form->{"id_$i"};
 
1980     if (!($form->{"id_$i"}) and $form->{"new_id_$i"}) {
 
1982       $id = $form->{"new_id_$i"};
 
1985     my ($price, $selectedpricegroup_id) = split(/--/,
 
1986       $form->{"sellprice_pg_$i"});
 
1988     my $pricegroup_old = $form->{"pricegroup_old_$i"};
 
1989     $form->{"new_pricegroup_$i"} = $selectedpricegroup_id;
 
1990     $form->{"old_pricegroup_$i"} = $pricegroup_old;
 
1992     my $price_new = $form->{"price_new_$i"};
 
1993     my $price_old = $form->{"price_old_$i"};
 
1995     if (!$form->{"unit_old_$i"}) {
 
1996       # Neue Ware aus der Datenbank. In diesem Fall ist unit_$i die
 
1997       # Einheit, wie sie in den Stammdaten hinterlegt wurde.
 
1998       # Es sollte also angenommen werden, dass diese ausgewaehlt war.
 
1999       $form->{"unit_old_$i"} = $form->{"unit_$i"};
 
2002     # Die zuletzt ausgewaehlte mit der aktuell ausgewaehlten Einheit
 
2003     # vergleichen und bei Unterschied den Preis entsprechend umrechnen.
 
2004     $form->{"selected_unit_$i"} = $form->{"unit_$i"} unless ($form->{"selected_unit_$i"});
 
2006     if (!$all_units->{$form->{"selected_unit_$i"}} ||
 
2007         ($all_units->{$form->{"selected_unit_$i"}}->{"base_unit"} ne
 
2008          $all_units->{$form->{"unit_old_$i"}}->{"base_unit"})) {
 
2009       # Die ausgewaehlte Einheit ist fuer diesen Artikel nicht gueltig
 
2010       # (z.B. Dimensionseinheit war ausgewaehlt, es handelt sich aber
 
2011       # um eine Dienstleistung). Dann keinerlei Umrechnung vornehmen.
 
2012       $form->{"unit_old_$i"} = $form->{"selected_unit_$i"} = $form->{"unit_$i"};
 
2017     if ($form->{"unit_old_$i"} ne $form->{"selected_unit_$i"}) {
 
2018       if (defined($all_units->{$form->{"unit_old_$i"}}->{"factor"}) &&
 
2019           $all_units->{$form->{"unit_old_$i"}}->{"factor"}) {
 
2020         $basefactor = $all_units->{$form->{"selected_unit_$i"}}->{"factor"} /
 
2021           $all_units->{$form->{"unit_old_$i"}}->{"factor"};
 
2025     if (!$form->{"basefactor_$i"}) {
 
2026       $form->{"basefactor_$i"} = 1;
 
2032            (SELECT p.sellprice FROM parts p WHERE p.id = ?) AS default_sellprice,
 
2033            (SELECT pg.pricegroup FROM pricegroup pg WHERE id = pricegroup_id) AS pricegroup,
 
2043             (SELECT sellprice FROM parts WHERE id = ?) AS default_sellprice,
 
2045             (SELECT DISTINCT sellprice FROM parts where id = ?) AS price,
 
2046             'selected' AS selected
 
2049           ORDER BY pricegroup|;
 
2050     my @values = (conv_i($id), conv_i($id), conv_i($id), conv_i($id));
 
2051     my $pkq = prepare_execute_query($form, $dbh, $query, @values);
 
2053     while (my $pkr = $pkq->fetchrow_hashref('NAME_lc')) {
 
2055       $pkr->{selected} = '';
 
2057       # if there is an exchange rate change price
 
2058       if (($form->{exchangerate} * 1) != 0) {
 
2060         $pkr->{price} /= $form->{exchangerate};
 
2063       $pkr->{price} *= $form->{"basefactor_$i"};
 
2065       $pkr->{price} *= $basefactor;
 
2067       $pkr->{price} = $form->format_amount($myconfig, $pkr->{price}, 5);
 
2069       if ($selectedpricegroup_id eq undef) {
 
2070         if ($pkr->{pricegroup_id} eq $form->{customer_klass}) {
 
2072           $pkr->{selected}  = ' selected';
 
2074           # no customer pricesgroup set
 
2075           if ($pkr->{price} == $pkr->{default_sellprice}) {
 
2077             $pkr->{price} = $form->{"sellprice_$i"};
 
2081 # this sub should not set anything and only return. --sschoeling, 20090506
 
2082 #            $form->{"sellprice_$i"} = $pkr->{price};
 
2085         } elsif ($pkr->{price} == $pkr->{default_sellprice}) {
 
2086           $pkr->{price}    = $form->{"sellprice_$i"};
 
2087           $pkr->{selected} = ' selected';
 
2091       if ($selectedpricegroup_id or $selectedpricegroup_id == 0) {
 
2092         if ($selectedpricegroup_id ne $pricegroup_old) {
 
2093           if ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
 
2094             $pkr->{selected}  = ' selected';
 
2096         } elsif (($price_new != $form->{"sellprice_$i"}) and ($price_new ne 0)) {
 
2097           if ($pkr->{pricegroup_id} == 0) {
 
2098             $pkr->{price}     = $form->{"sellprice_$i"};
 
2099             $pkr->{selected}  = ' selected';
 
2101         } elsif ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
 
2102           $pkr->{selected}  = ' selected';
 
2103           if (    ($pkr->{pricegroup_id} == 0)
 
2104               and ($pkr->{price} == $form->{"sellprice_$i"})) {
 
2105             # $pkr->{price}                         = $form->{"sellprice_$i"};
 
2107             $pkr->{price} = $form->{"sellprice_$i"};
 
2111       push @{ $form->{PRICES}{$i} }, $pkr;
 
2114     $form->{"basefactor_$i"} *= $basefactor;
 
2123   $main::lxdebug->leave_sub();
 
2127   $main::lxdebug->enter_sub();
 
2129   my ($self, $myconfig, $form, $table) = @_;
 
2131   $main::lxdebug->leave_sub() and return 0 unless ($form->{id});
 
2133   # make sure there's no funny stuff in $table
 
2134   # ToDO: die when this happens and throw an error
 
2135   $main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);
 
2137   my $dbh = $form->dbconnect($myconfig);
 
2139   my $query = qq|SELECT storno FROM $table WHERE storno_id = ?|;
 
2140   my ($result) = selectrow_query($form, $dbh, $query, $form->{id});
 
2144   $main::lxdebug->leave_sub();
 
2150   $main::lxdebug->enter_sub();
 
2152   my ($self, $myconfig, $form, $table, $id) = @_;
 
2154   $main::lxdebug->leave_sub() and return 0 unless ($id);
 
2156   # make sure there's no funny stuff in $table
 
2157   # ToDO: die when this happens and throw an error
 
2158   $main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);
 
2160   my $dbh = $form->dbconnect($myconfig);
 
2162   my $query = qq|SELECT storno FROM $table WHERE id = ?|;
 
2163   my ($result) = selectrow_query($form, $dbh, $query, $id);
 
2167   $main::lxdebug->leave_sub();