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 #======================================================================
 
  37 use List::Util qw(max);
 
  43 use SL::DATEV qw(:CONSTANTS);
 
  46 use SL::GenericTranslations;
 
  47 use SL::HTML::Restrict;
 
  60   $main::lxdebug->enter_sub();
 
  62   my ($self, $myconfig, $form, $locale) = @_;
 
  64   $form->{duedate} ||= $form->{invdate};
 
  67   my $dbh = $form->get_standard_dbh;
 
  70   my $query = qq|SELECT date | . conv_dateq($form->{duedate}) . qq| - date | . conv_dateq($form->{invdate}) . qq| AS terms|;
 
  71   ($form->{terms}) = selectrow_query($form, $dbh, $query);
 
  74   $form->{TEMPLATE_ARRAYS} = {};
 
  76   push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});
 
  78   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
 
  81   foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
 
  82     $price_factors{$pfac->{id}}  = $pfac;
 
  84     $pfac->{formatted_factor}    = $form->format_amount($myconfig, $pfac->{factor});
 
  87   # sort items by partsgroup
 
  88   for my $i (1 .. $form->{rowcount}) {
 
  90 #    if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
 
  91 #      $partsgroup = $form->{"partsgroup_$i"};
 
  93 #    push @partsgroup, [$i, $partsgroup];
 
  94     push(@project_ids, $form->{"project_id_$i"}) if ($form->{"project_id_$i"});
 
 100     $projects = SL::DB::Manager::Project->get_all(query => [ id => \@project_ids ]);
 
 101     %projects_by_id = map { $_->id => $_ } @$projects;
 
 104   if ($projects_by_id{$form->{"globalproject_id"}}) {
 
 105     $form->{globalprojectnumber} = $projects_by_id{$form->{"globalproject_id"}}->projectnumber;
 
 106     $form->{globalprojectdescription} = $projects_by_id{$form->{"globalproject_id"}}->description;
 
 108     for (@{ $projects_by_id{$form->{"globalproject_id"}}->cvars_by_config }) {
 
 109       $form->{"project_cvar_" . $_->config->name} = $_->value_as_text;
 
 119   # sort items by partsgroup
 
 120   for $i (1 .. $form->{rowcount}) {
 
 122     if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
 
 123       $partsgroup = $form->{"partsgroup_$i"};
 
 125     push @partsgroup, [$i, $partsgroup];
 
 138   my $nodiscount_subtotal = 0;
 
 139   my $discount_subtotal = 0;
 
 141   my $subtotal_header = 0;
 
 144   $form->{discount} = [];
 
 146   IC->prepare_parts_for_printing(myconfig => $myconfig, form => $form);
 
 148   my $ic_cvar_configs = CVar->get_configs(module => 'IC');
 
 149   my $project_cvar_configs = CVar->get_configs(module => 'Projects');
 
 152     qw(runningnumber number description longdescription qty ship unit bin
 
 153        deliverydate_oe ordnumber_oe donumber_do transdate_oe validuntil
 
 154        partnotes serialnumber reqdate sellprice listprice netprice
 
 155        discount p_discount discount_sub nodiscount_sub
 
 156        linetotal  nodiscount_linetotal tax_rate projectnumber projectdescription
 
 157        price_factor price_factor_name partsgroup weight lineweight);
 
 159   push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };
 
 160   push @arrays, map { "project_cvar_$_->{name}" } @{ $project_cvar_configs };
 
 162   my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);
 
 164   my @payment_arrays = qw(payment paymentaccount paymentdate paymentsource paymentmemo);
 
 166   map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays, @payment_arrays);
 
 169   foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
 
 172     if ($item->[1] ne $sameitem) {
 
 173       push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, qq|$item->[1]|);
 
 174       $sameitem = $item->[1];
 
 176       map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
 179     $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
 
 181     if ($form->{"id_$i"} != 0) {
 
 183       # add number, description and qty to $form->{number},
 
 184       if ($form->{"subtotal_$i"} && !$subtotal_header) {
 
 185         $subtotal_header = $i;
 
 186         $position = int($position);
 
 189       } elsif ($subtotal_header) {
 
 191         $position = int($position);
 
 192         $position = $position.".".$subposition;
 
 194         $position = int($position);
 
 198       my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || { 'factor' => 1 };
 
 200       push @{ $form->{TEMPLATE_ARRAYS}->{runningnumber} },     $position;
 
 201       push @{ $form->{TEMPLATE_ARRAYS}->{number} },            $form->{"partnumber_$i"};
 
 202       push @{ $form->{TEMPLATE_ARRAYS}->{serialnumber} },      $form->{"serialnumber_$i"};
 
 203       push @{ $form->{TEMPLATE_ARRAYS}->{bin} },               $form->{"bin_$i"};
 
 204       push @{ $form->{TEMPLATE_ARRAYS}->{partnotes} },         $form->{"partnotes_$i"};
 
 205       push @{ $form->{TEMPLATE_ARRAYS}->{description} },       $form->{"description_$i"};
 
 206       push @{ $form->{TEMPLATE_ARRAYS}->{longdescription} },   $form->{"longdescription_$i"};
 
 207       push @{ $form->{TEMPLATE_ARRAYS}->{qty} },               $form->format_amount($myconfig, $form->{"qty_$i"});
 
 208       push @{ $form->{TEMPLATE_ARRAYS}->{qty_nofmt} },         $form->{"qty_$i"};
 
 209       push @{ $form->{TEMPLATE_ARRAYS}->{unit} },              $form->{"unit_$i"};
 
 210       push @{ $form->{TEMPLATE_ARRAYS}->{deliverydate_oe} },   $form->{"reqdate_$i"};
 
 211       push @{ $form->{TEMPLATE_ARRAYS}->{sellprice} },         $form->{"sellprice_$i"};
 
 212       push @{ $form->{TEMPLATE_ARRAYS}->{sellprice_nofmt} },   $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 213       push @{ $form->{TEMPLATE_ARRAYS}->{ordnumber_oe} },      $form->{"ordnumber_$i"};
 
 214       push @{ $form->{TEMPLATE_ARRAYS}->{donumber_do} },       $form->{"donumber_$i"};
 
 215       push @{ $form->{TEMPLATE_ARRAYS}->{transdate_oe} },      $form->{"transdate_$i"};
 
 216       push @{ $form->{TEMPLATE_ARRAYS}->{invnumber} },         $form->{"invnumber"};
 
 217       push @{ $form->{TEMPLATE_ARRAYS}->{invdate} },           $form->{"invdate"};
 
 218       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor} },      $price_factor->{formatted_factor};
 
 219       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor_name} }, $price_factor->{description};
 
 220       push @{ $form->{TEMPLATE_ARRAYS}->{partsgroup} },        $form->{"partsgroup_$i"};
 
 221       push @{ $form->{TEMPLATE_ARRAYS}->{reqdate} },           $form->{"reqdate_$i"};
 
 222       push(@{ $form->{TEMPLATE_ARRAYS}->{listprice} },         $form->{"listprice_$i"});
 
 224       my $sellprice     = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 225       my ($dec)         = ($sellprice =~ /\.(\d+)/);
 
 226       my $decimalplaces = max 2, length($dec);
 
 228       my $parsed_discount            = $form->parse_amount($myconfig, $form->{"discount_$i"});
 
 230       my $linetotal_exact            = $form->{"qty_$i"} * $sellprice * (100 - $parsed_discount) / 100 / $price_factor->{factor};
 
 231       my $linetotal                  = $form->round_amount($linetotal_exact, 2);
 
 233       my $nodiscount_exact_linetotal = $form->{"qty_$i"} * $sellprice                                  / $price_factor->{factor};
 
 234       my $nodiscount_linetotal       = $form->round_amount($nodiscount_exact_linetotal,2);
 
 236       my $discount                   = $nodiscount_linetotal - $linetotal; # is always rounded because $nodiscount_linetotal and $linetotal are rounded
 
 238       my $discount_round_error       = $discount + ($linetotal_exact - $nodiscount_exact_linetotal); # not used
 
 240       $form->{"netprice_$i"}   = $form->round_amount($form->{"qty_$i"} ? ($linetotal / $form->{"qty_$i"}) : 0, 2);
 
 242       push @{ $form->{TEMPLATE_ARRAYS}->{netprice} },       ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : '';
 
 243       push @{ $form->{TEMPLATE_ARRAYS}->{netprice_nofmt} }, ($form->{"netprice_$i"} != 0) ? $form->{"netprice_$i"} : '';
 
 245       $linetotal = ($linetotal != 0) ? $linetotal : '';
 
 247       push @{ $form->{TEMPLATE_ARRAYS}->{discount} },       ($discount != 0) ? $form->format_amount($myconfig, $discount * -1, 2) : '';
 
 248       push @{ $form->{TEMPLATE_ARRAYS}->{discount_nofmt} }, ($discount != 0) ? $discount * -1 : '';
 
 249       push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} },     $form->{"discount_$i"};
 
 251       $form->{total}            += $linetotal;
 
 252       $form->{nodiscount_total} += $nodiscount_linetotal;
 
 253       $form->{discount_total}   += $discount;
 
 255       if ($subtotal_header) {
 
 256         $discount_subtotal   += $linetotal;
 
 257         $nodiscount_subtotal += $nodiscount_linetotal;
 
 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}->{discount_sub_nofmt} },   $discount_subtotal;
 
 263         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} },       $form->format_amount($myconfig, $nodiscount_subtotal, 2);
 
 264         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub_nofmt} }, $nodiscount_subtotal;
 
 266         $discount_subtotal   = 0;
 
 267         $nodiscount_subtotal = 0;
 
 268         $subtotal_header     = 0;
 
 271         push @{ $form->{TEMPLATE_ARRAYS}->{$_} }, "" for qw(discount_sub nodiscount_sub discount_sub_nofmt nodiscount_sub_nofmt);
 
 274       if (!$form->{"discount_$i"}) {
 
 275         $nodiscount += $linetotal;
 
 278       push @{ $form->{TEMPLATE_ARRAYS}->{linetotal} },                  $form->format_amount($myconfig, $linetotal, 2);
 
 279       push @{ $form->{TEMPLATE_ARRAYS}->{linetotal_nofmt} },            $linetotal_exact;
 
 280       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} },       $form->format_amount($myconfig, $nodiscount_linetotal, 2);
 
 281       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal_nofmt} }, $nodiscount_linetotal;
 
 283       my $project = $projects_by_id{$form->{"project_id_$i"}} || SL::DB::Project->new;
 
 285       push @{ $form->{TEMPLATE_ARRAYS}->{projectnumber} },              $project->projectnumber;
 
 286       push @{ $form->{TEMPLATE_ARRAYS}->{projectdescription} },         $project->description;
 
 288       my $lineweight = $form->{"qty_$i"} * $form->{"weight_$i"};
 
 289       $totalweight += $lineweight;
 
 290       push @{ $form->{TEMPLATE_ARRAYS}->{weight} },            $form->format_amount($myconfig, $form->{"weight_$i"}, 3);
 
 291       push @{ $form->{TEMPLATE_ARRAYS}->{weight_nofmt} },      $form->{"weight_$i"};
 
 292       push @{ $form->{TEMPLATE_ARRAYS}->{lineweight} },        $form->format_amount($myconfig, $lineweight, 3);
 
 293       push @{ $form->{TEMPLATE_ARRAYS}->{lineweight_nofmt} },  $lineweight;
 
 295       @taxaccounts = split(/ /, $form->{"taxaccounts_$i"});
 
 299       map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;
 
 301       if ($form->{taxincluded}) {
 
 304         $taxamount = $linetotal * $taxrate / (1 + $taxrate);
 
 305         $taxbase = $linetotal - $taxamount;
 
 307         $taxamount = $linetotal * $taxrate;
 
 308         $taxbase   = $linetotal;
 
 311       if ($form->round_amount($taxrate, 7) == 0) {
 
 312         if ($form->{taxincluded}) {
 
 313           foreach my $accno (@taxaccounts) {
 
 314             $taxamount            = $form->round_amount($linetotal * $form->{"${accno}_rate"} / (1 + abs($form->{"${accno}_rate"})), 2);
 
 316             $taxaccounts{$accno} += $taxamount;
 
 317             $taxdiff             += $taxamount;
 
 319             $taxbase{$accno}     += $taxbase;
 
 321           $taxaccounts{ $taxaccounts[0] } += $taxdiff;
 
 323           foreach my $accno (@taxaccounts) {
 
 324             $taxaccounts{$accno} += $linetotal * $form->{"${accno}_rate"};
 
 325             $taxbase{$accno}     += $taxbase;
 
 329         foreach my $accno (@taxaccounts) {
 
 330           $taxaccounts{$accno} += $taxamount * $form->{"${accno}_rate"} / $taxrate;
 
 331           $taxbase{$accno}     += $taxbase;
 
 334       my $tax_rate = $taxrate * 100;
 
 335       push(@{ $form->{TEMPLATE_ARRAYS}->{tax_rate} }, qq|$tax_rate|);
 
 336       if ($form->{"assembly_$i"}) {
 
 339         # get parts and push them onto the stack
 
 341         if ($form->{groupitems}) {
 
 343             qq|ORDER BY pg.partsgroup, a.oid|;
 
 345           $sortorder = qq|ORDER BY a.oid|;
 
 349           qq|SELECT p.partnumber, p.description, p.unit, a.qty, pg.partsgroup
 
 351              JOIN parts p ON (a.parts_id = p.id)
 
 352              LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
 
 353              WHERE (a.bom = '1') AND (a.id = ?) $sortorder|;
 
 354         $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id_$i"}));
 
 356         while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
 357           if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
 
 358             map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
 359             $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
 
 360             push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $sameitem);
 
 363           map { $form->{"a_$_"} = $ref->{$_} } qw(partnumber description);
 
 365           push(@{ $form->{TEMPLATE_ARRAYS}->{description} },
 
 366                $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}
 
 368                  . qq| -- $form->{"a_partnumber"}, $form->{"a_description"}|);
 
 369           map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
 375       push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} },
 
 376         CVar->format_to_template(CVar->parse($form->{"ic_cvar_$_->{name}_$i"}, $_), $_)
 
 377           for @{ $ic_cvar_configs };
 
 379       push @{ $form->{TEMPLATE_ARRAYS}->{"project_cvar_" . $_->config->name} }, $_->value_as_text for @{ $project->cvars_by_config };
 
 383   $form->{totalweight}       = $form->format_amount($myconfig, $totalweight, 3);
 
 384   $form->{totalweight_nofmt} = $totalweight;
 
 385   my $defaults = AM->get_defaults();
 
 386   $form->{weightunit}        = $defaults->{weightunit};
 
 388   foreach my $item (sort keys %taxaccounts) {
 
 389     $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
 
 391     push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase} },        $form->format_amount($myconfig, $taxbase{$item}, 2));
 
 392     push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase_nofmt} },  $taxbase{$item});
 
 393     push(@{ $form->{TEMPLATE_ARRAYS}->{tax} },            $form->format_amount($myconfig, $taxamount,      2));
 
 394     push(@{ $form->{TEMPLATE_ARRAYS}->{tax_nofmt} },      $taxamount );
 
 395     push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate} },        $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
 
 396     push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate_nofmt} },  $form->{"${item}_rate"} * 100);
 
 397     push(@{ $form->{TEMPLATE_ARRAYS}->{taxnumber} },      $form->{"${item}_taxnumber"});
 
 399     my $tax_obj     = SL::DB::Manager::Tax->find_by(taxnumber => $form->{"${item}_taxnumber"});
 
 400     my $description = $tax_obj ? $tax_obj->translated_attribute('taxdescription',  $form->{language_id}, 0) : '';
 
 401     push(@{ $form->{TEMPLATE_ARRAYS}->{taxdescription} }, $description . q{ } . 100 * $form->{"${item}_rate"} . q{%});
 
 404   for my $i (1 .. $form->{paidaccounts}) {
 
 405     if ($form->{"paid_$i"}) {
 
 406       my ($accno, $description) = split(/--/, $form->{"AR_paid_$i"});
 
 408       push(@{ $form->{TEMPLATE_ARRAYS}->{payment} },        $form->{"paid_$i"});
 
 409       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentaccount} }, $description);
 
 410       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentdate} },    $form->{"datepaid_$i"});
 
 411       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentsource} },  $form->{"source_$i"});
 
 412       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentmemo} },    $form->{"memo_$i"});
 
 414       $form->{paid} += $form->parse_amount($myconfig, $form->{"paid_$i"});
 
 417   if($form->{taxincluded}) {
 
 418     $form->{subtotal}       = $form->format_amount($myconfig, $form->{total} - $tax, 2);
 
 419     $form->{subtotal_nofmt} = $form->{total} - $tax;
 
 422     $form->{subtotal}       = $form->format_amount($myconfig, $form->{total}, 2);
 
 423     $form->{subtotal_nofmt} = $form->{total};
 
 426   $form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
 
 427   $form->{discount_total}      = $form->format_amount($myconfig, $form->{discount_total}, 2);
 
 428   $form->{nodiscount}          = $form->format_amount($myconfig, $nodiscount, 2);
 
 429   $form->{yesdiscount}         = $form->format_amount($myconfig, $form->{nodiscount_total} - $nodiscount, 2);
 
 431   $form->{invtotal} = ($form->{taxincluded}) ? $form->{total} : $form->{total} + $tax;
 
 432   $form->{total}    = $form->format_amount($myconfig, $form->{invtotal} - $form->{paid}, 2);
 
 434   $form->{invtotal} = $form->format_amount($myconfig, $form->{invtotal}, 2);
 
 435   $form->{paid}     = $form->format_amount($myconfig, $form->{paid}, 2);
 
 437   $form->set_payment_options($myconfig, $form->{invdate});
 
 439   $form->{delivery_term} = SL::DB::Manager::DeliveryTerm->find_by(id => $form->{delivery_term_id} || undef);
 
 440   $form->{delivery_term}->description_long($form->{delivery_term}->translated_attribute('description_long', $form->{language_id})) if $form->{delivery_term} && $form->{language_id};
 
 442   $form->{username} = $myconfig->{name};
 
 444   $main::lxdebug->leave_sub();
 
 447 sub project_description {
 
 448   $main::lxdebug->enter_sub();
 
 450   my ($self, $dbh, $id) = @_;
 
 451   my $form = \%main::form;
 
 453   my $query = qq|SELECT description FROM project WHERE id = ?|;
 
 454   my ($description) = selectrow_query($form, $dbh, $query, conv_i($id));
 
 456   $main::lxdebug->leave_sub();
 
 461 sub customer_details {
 
 462   $main::lxdebug->enter_sub();
 
 464   my ($self, $myconfig, $form, @wanted_vars) = @_;
 
 466   # connect to database
 
 467   my $dbh = $form->get_standard_dbh;
 
 469   my $language_id = $form->{language_id};
 
 471   # get contact id, set it if nessessary
 
 474   my @values =  (conv_i($form->{customer_id}));
 
 477   if ($form->{cp_id}) {
 
 478     $where = qq| AND (cp.cp_id = ?) |;
 
 479     push(@values, conv_i($form->{cp_id}));
 
 482   # get rest for the customer
 
 484     qq|SELECT ct.*, cp.*, ct.notes as customernotes,
 
 485          ct.phone AS customerphone, ct.fax AS customerfax, ct.email AS customeremail,
 
 488        LEFT JOIN contacts cp on ct.id = cp.cp_cv_id
 
 489        LEFT JOIN currencies cu ON (ct.currency_id = cu.id)
 
 490        WHERE (ct.id = ?) $where
 
 493   my $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
 
 495   # remove id and taxincluded before copy back
 
 496   delete @$ref{qw(id taxincluded)};
 
 498   @wanted_vars = grep({ $_ } @wanted_vars);
 
 499   if (scalar(@wanted_vars) > 0) {
 
 501     map({ $h_wanted_vars{$_} = 1; } @wanted_vars);
 
 502     map({ delete($ref->{$_}) unless ($h_wanted_vars{$_}); } keys(%{$ref}));
 
 505   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 507   if ($form->{delivery_customer_id}) {
 
 509       qq|SELECT *, notes as customernotes
 
 513     $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{delivery_customer_id}));
 
 515     map { $form->{"dc_$_"} = $ref->{$_} } keys %$ref;
 
 518   if ($form->{delivery_vendor_id}) {
 
 520       qq|SELECT *, notes as customernotes
 
 524     $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{delivery_vendor_id}));
 
 526     map { $form->{"dv_$_"} = $ref->{$_} } keys %$ref;
 
 529   my $custom_variables = CVar->get_custom_variables('dbh'      => $dbh,
 
 531                                                     'trans_id' => $form->{customer_id});
 
 532   map { $form->{"vc_cvar_$_->{name}"} = $_->{value} } @{ $custom_variables };
 
 534   $form->{cp_greeting} = GenericTranslations->get('dbh'              => $dbh,
 
 535                                                   'translation_type' => 'greetings::' . ($form->{cp_gender} eq 'f' ? 'female' : 'male'),
 
 536                                                   'language_id'      => $language_id,
 
 537                                                   'allow_fallback'   => 1);
 
 540   $main::lxdebug->leave_sub();
 
 544   $main::lxdebug->enter_sub();
 
 546   my ($self, $myconfig, $form, $provided_dbh, $payments_only) = @_;
 
 548   # connect to database, turn off autocommit
 
 549   my $dbh = $provided_dbh ? $provided_dbh : $form->get_standard_dbh;
 
 550   my $restricter = SL::HTML::Restrict->create;
 
 552   my ($query, $sth, $null, $project_id, @values);
 
 553   my $exchangerate = 0;
 
 555   my $ic_cvar_configs = CVar->get_configs(module => 'IC',
 
 558   if (!$form->{employee_id}) {
 
 559     $form->get_employee($dbh);
 
 562   $form->{defaultcurrency} = $form->get_default_currency($myconfig);
 
 563   my $defaultcurrency = $form->{defaultcurrency};
 
 565   # Seit neuestem wird die department_id schon Ã¼bergeben UND $form->department nicht mehr
 
 566   # korrekt zusammengebaut. Sehr wahrscheinlich beim Umstieg auf T8 kaputt gegangen
 
 567   # Ich lass den Code von 2005 erstmal noch stehen ;-) jb 03-2011
 
 568   if (!$form->{department_id}){
 
 569     ($null, $form->{department_id}) = split(/--/, $form->{department});
 
 572   my $all_units = AM->retrieve_units($myconfig, $form);
 
 574   if (!$payments_only) {
 
 576       &reverse_invoice($dbh, $form);
 
 579       my $trans_number   = SL::TransNumber->new(type => $form->{type}, dbh => $dbh, number => $form->{invnumber}, save => 1);
 
 580       $form->{invnumber} = $trans_number->create_unique unless $trans_number->is_unique;
 
 582       $query = qq|SELECT nextval('glid')|;
 
 583       ($form->{"id"}) = selectrow_query($form, $dbh, $query);
 
 585       $query = qq|INSERT INTO ar (id, invnumber, currency_id) VALUES (?, ?, (SELECT id FROM currencies WHERE name=?))|;
 
 586       do_query($form, $dbh, $query, $form->{"id"}, $form->{"id"}, $form->{currency});
 
 588       if (!$form->{invnumber}) {
 
 589         my $trans_number   = SL::TransNumber->new(type => $form->{type}, dbh => $dbh, number => $form->{invnumber}, id => $form->{id});
 
 590         $form->{invnumber} = $trans_number->create_unique;
 
 595   my ($netamount, $invoicediff) = (0, 0);
 
 596   my ($amount, $linetotal, $lastincomeaccno);
 
 598   if ($form->{currency} eq $defaultcurrency) {
 
 599     $form->{exchangerate} = 1;
 
 601     $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{invdate}, 'buy');
 
 604   $form->{exchangerate} =
 
 607     : $form->parse_amount($myconfig, $form->{exchangerate});
 
 609   $form->{expense_inventory} = "";
 
 613   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
 
 614   my %price_factors = map { $_->{id} => $_->{factor} } @{ $form->{ALL_PRICE_FACTORS} };
 
 617   $form->{amount}      = {};
 
 618   $form->{amount_cogs} = {};
 
 620   foreach my $i (1 .. $form->{rowcount}) {
 
 621     if ($form->{type} eq "credit_note") {
 
 622       $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}) * -1;
 
 623       $form->{shipped} = 1;
 
 625       $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
 
 630     $form->{"marge_percent_$i"} = $form->parse_amount($myconfig, $form->{"marge_percent_$i"}) * 1;
 
 631     $form->{"marge_absolut_$i"} = $form->parse_amount($myconfig, $form->{"marge_absolut_$i"}) * 1;
 
 632     $form->{"lastcost_$i"} = $form->parse_amount($myconfig, $form->{"lastcost_$i"}) * 1;
 
 634     if ($form->{storno}) {
 
 635       $form->{"qty_$i"} *= -1;
 
 638     if ($form->{"id_$i"}) {
 
 641       if (defined($baseunits{$form->{"id_$i"}})) {
 
 642         $item_unit = $baseunits{$form->{"id_$i"}};
 
 645         $query = qq|SELECT unit FROM parts WHERE id = ?|;
 
 646         ($item_unit) = selectrow_query($form, $dbh, $query, conv_i($form->{"id_$i"}));
 
 647         $baseunits{$form->{"id_$i"}} = $item_unit;
 
 650       if (defined($all_units->{$item_unit}->{factor})
 
 651           && ($all_units->{$item_unit}->{factor} ne '')
 
 652           && ($all_units->{$item_unit}->{factor} != 0)) {
 
 653         $basefactor = $all_units->{$form->{"unit_$i"}}->{factor} / $all_units->{$item_unit}->{factor};
 
 657       $baseqty = $form->{"qty_$i"} * $basefactor;
 
 659       my ($allocated, $taxrate) = (0, 0);
 
 663       map { $taxrate += $form->{"${_}_rate"} } split(/ /, $form->{"taxaccounts_$i"});
 
 665       # keep entered selling price
 
 667         $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 669       my ($dec) = ($fxsellprice =~ /\.(\d+)/);
 
 671       my $decimalplaces = ($dec > 2) ? $dec : 2;
 
 673       # undo discount formatting
 
 674       $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
 
 677       $form->{"sellprice_$i"} = $fxsellprice * (1 - $form->{"discount_$i"});
 
 679       # round linetotal to 2 decimal places
 
 680       $price_factor = $price_factors{ $form->{"price_factor_id_$i"} } || 1;
 
 681       $linetotal    = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2);
 
 683       if ($form->{taxincluded}) {
 
 684         $taxamount = $linetotal * ($taxrate / (1 + $taxrate));
 
 685         $form->{"sellprice_$i"} =
 
 686           $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
 
 688         $taxamount = $linetotal * $taxrate;
 
 691       $netamount += $linetotal;
 
 693       if ($taxamount != 0) {
 
 695           $form->{amount}{ $form->{id} }{$_} +=
 
 696             $taxamount * $form->{"${_}_rate"} / $taxrate
 
 697         } split(/ /, $form->{"taxaccounts_$i"});
 
 700       # add amount to income, $form->{amount}{trans_id}{accno}
 
 701       $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate} / $price_factor;
 
 703       $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2) * $form->{exchangerate};
 
 704       $linetotal = $form->round_amount($linetotal, 2);
 
 706       # this is the difference from the inventory
 
 707       $invoicediff += ($amount - $linetotal);
 
 709       $form->{amount}{ $form->{id} }{ $form->{"income_accno_$i"} } +=
 
 712       $lastincomeaccno = $form->{"income_accno_$i"};
 
 714       # adjust and round sellprice
 
 715       $form->{"sellprice_$i"} =
 
 716         $form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate},
 
 719       next if $payments_only;
 
 721       if ($form->{"inventory_accno_$i"} || $form->{"assembly_$i"}) {
 
 723         if ($form->{"assembly_$i"}) {
 
 724           # record assembly item as allocated
 
 725           &process_assembly($dbh, $myconfig, $form, $form->{"id_$i"}, $baseqty);
 
 728           $allocated = &cogs($dbh, $myconfig, $form, $form->{"id_$i"}, $baseqty, $basefactor, $i);
 
 732       # Get pricegroup_id and save it. Unfortunately the interface
 
 733       # also uses ID "0" for signalling that none is selected, but "0"
 
 734       # must not be stored in the database. Therefore we cannot simply
 
 736       ($null, my $pricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
 
 738       $pricegroup_id  = undef if !$pricegroup_id;
 
 740       my ($invoice_id) = selectfirst_array_query($form, $dbh, qq|SELECT nextval('invoiceid')|);
 
 742       # save detail record in invoice table
 
 744         qq|INSERT INTO invoice (id, trans_id, parts_id, description, longdescription, qty,
 
 745                                 sellprice, fxsellprice, discount, allocated, assemblyitem,
 
 746                                 unit, deliverydate, project_id, serialnumber, pricegroup_id,
 
 747                                 ordnumber, donumber, transdate, cusordnumber, base_qty, subtotal,
 
 748                                 marge_percent, marge_total, lastcost,
 
 749                                 price_factor_id, price_factor, marge_price_factor)
 
 750            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
 
 751                    (SELECT factor FROM price_factors WHERE id = ?), ?)|;
 
 753       @values = ($invoice_id, conv_i($form->{id}), conv_i($form->{"id_$i"}),
 
 754                  $form->{"description_$i"}, $restricter->process($form->{"longdescription_$i"}), $form->{"qty_$i"},
 
 755                  $form->{"sellprice_$i"}, $fxsellprice,
 
 756                  $form->{"discount_$i"}, $allocated, 'f',
 
 757                  $form->{"unit_$i"}, conv_date($form->{"reqdate_$i"}), conv_i($form->{"project_id_$i"}),
 
 758                  $form->{"serialnumber_$i"}, $pricegroup_id,
 
 759                  $form->{"ordnumber_$i"}, $form->{"donumber_$i"}, conv_date($form->{"transdate_$i"}),
 
 760                  $form->{"cusordnumber_$i"}, $baseqty, $form->{"subtotal_$i"} ? 't' : 'f',
 
 761                  $form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
 
 762                  $form->{"lastcost_$i"},
 
 763                  conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
 
 764                  conv_i($form->{"marge_price_factor_$i"}));
 
 765       do_query($form, $dbh, $query, @values);
 
 767       CVar->save_custom_variables(module       => 'IC',
 
 768                                   sub_module   => 'invoice',
 
 769                                   trans_id     => $invoice_id,
 
 770                                   configs      => $ic_cvar_configs,
 
 772                                   name_prefix  => 'ic_',
 
 773                                   name_postfix => "_$i",
 
 778   # total payments, don't move we need it here
 
 779   for my $i (1 .. $form->{paidaccounts}) {
 
 780     if ($form->{type} eq "credit_note") {
 
 781       $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"}) * -1;
 
 783       $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
 
 785     $form->{paid} += $form->{"paid_$i"};
 
 786     $form->{datepaid} = $form->{"datepaid_$i"} if ($form->{"datepaid_$i"});
 
 789   my ($tax, $diff) = (0, 0);
 
 791   $netamount = $form->round_amount($netamount, 2);
 
 793   # figure out rounding errors for total amount vs netamount + taxes
 
 794   if ($form->{taxincluded}) {
 
 796     $amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
 
 797     $diff += $amount - $netamount * $form->{exchangerate};
 
 798     $netamount = $amount;
 
 800     foreach my $item (split(/ /, $form->{taxaccounts})) {
 
 801       $amount = $form->{amount}{ $form->{id} }{$item} * $form->{exchangerate};
 
 802       $form->{amount}{ $form->{id} }{$item} = $form->round_amount($amount, 2);
 
 803       $tax += $form->{amount}{ $form->{id} }{$item};
 
 804       $netamount -= $form->{amount}{ $form->{id} }{$item};
 
 807     $invoicediff += $diff;
 
 808     ######## this only applies to tax included
 
 809     if ($lastincomeaccno) {
 
 810       $form->{amount}{ $form->{id} }{$lastincomeaccno} += $invoicediff;
 
 814     $amount    = $form->round_amount($netamount * $form->{exchangerate}, 2);
 
 815     $diff      = $amount - $netamount * $form->{exchangerate};
 
 816     $netamount = $amount;
 
 817     foreach my $item (split(/ /, $form->{taxaccounts})) {
 
 818       $form->{amount}{ $form->{id} }{$item} =
 
 819         $form->round_amount($form->{amount}{ $form->{id} }{$item}, 2);
 
 822                  $form->{amount}{ $form->{id} }{$item} * $form->{exchangerate},
 
 825         $amount - $form->{amount}{ $form->{id} }{$item} *
 
 826         $form->{exchangerate};
 
 827       $form->{amount}{ $form->{id} }{$item} = $form->round_amount($amount, 2);
 
 828       $tax += $form->{amount}{ $form->{id} }{$item};
 
 832   $form->{amount}{ $form->{id} }{ $form->{AR} } = $netamount + $tax;
 
 834     $form->round_amount($form->{paid} * $form->{exchangerate} + $diff, 2);
 
 837   $form->{amount}{ $form->{id} }{ $form->{AR} } *= -1;
 
 839   # update exchangerate
 
 840   if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
 
 841     $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate},
 
 842                                $form->{exchangerate}, 0);
 
 845   $project_id = conv_i($form->{"globalproject_id"});
 
 846   # entsprechend auch beim Bestimmen des Steuerschlüssels in Taxkey.pm berücksichtigen
 
 847   my $taxdate = $form->{deliverydate} ? $form->{deliverydate} : $form->{invdate};
 
 849   foreach my $trans_id (keys %{ $form->{amount_cogs} }) {
 
 850     foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
 
 851       next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
 
 853       $form->{amount_cogs}{$trans_id}{$accno} = $form->round_amount($form->{amount_cogs}{$trans_id}{$accno}, 2);
 
 855       if (!$payments_only && ($form->{amount_cogs}{$trans_id}{$accno} != 0)) {
 
 857           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
 
 858                VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, (SELECT id FROM tax WHERE taxkey=0), 0, ?, (SELECT link FROM chart WHERE accno = ?))|;
 
 859         @values = (conv_i($trans_id), $accno, $form->{amount_cogs}{$trans_id}{$accno}, conv_date($form->{invdate}), conv_i($project_id), $accno);
 
 860         do_query($form, $dbh, $query, @values);
 
 861         $form->{amount_cogs}{$trans_id}{$accno} = 0;
 
 865     foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
 
 866       $form->{amount_cogs}{$trans_id}{$accno} = $form->round_amount($form->{amount_cogs}{$trans_id}{$accno}, 2);
 
 868       if (!$payments_only && ($form->{amount_cogs}{$trans_id}{$accno} != 0)) {
 
 870           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
 
 871                VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, (SELECT id FROM tax WHERE taxkey=0), 0, ?, (SELECT link FROM chart WHERE accno = ?))|;
 
 872         @values = (conv_i($trans_id), $accno, $form->{amount_cogs}{$trans_id}{$accno}, conv_date($form->{invdate}), conv_i($project_id), $accno);
 
 873         do_query($form, $dbh, $query, @values);
 
 878   foreach my $trans_id (keys %{ $form->{amount} }) {
 
 879     foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
 
 880       next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
 
 882       $form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2);
 
 884       if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
 
 886           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
 
 887              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
 
 890                       WHERE chart_id= (SELECT id
 
 894                       ORDER BY startdate DESC LIMIT 1),
 
 897                       WHERE chart_id= (SELECT id
 
 901                       ORDER BY startdate DESC LIMIT 1),
 
 903                      (SELECT link FROM chart WHERE accno = ?))|;
 
 904         @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno);
 
 905         do_query($form, $dbh, $query, @values);
 
 906         $form->{amount}{$trans_id}{$accno} = 0;
 
 910     foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
 
 911       $form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2);
 
 913       if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
 
 915           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
 
 916              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
 
 919                       WHERE chart_id= (SELECT id
 
 923                       ORDER BY startdate DESC LIMIT 1),
 
 926                       WHERE chart_id= (SELECT id
 
 930                       ORDER BY startdate DESC LIMIT 1),
 
 932                      (SELECT link FROM chart WHERE accno = ?))|;
 
 933         @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno);
 
 934         do_query($form, $dbh, $query, @values);
 
 939   # deduct payment differences from diff
 
 940   for my $i (1 .. $form->{paidaccounts}) {
 
 941     if ($form->{"paid_$i"} != 0) {
 
 943         $form->round_amount($form->{"paid_$i"} * $form->{exchangerate}, 2);
 
 944       $diff -= $amount - $form->{"paid_$i"} * $form->{exchangerate};
 
 948   # record payments and offsetting AR
 
 949   if (!$form->{storno}) {
 
 950     for my $i (1 .. $form->{paidaccounts}) {
 
 952       if ($form->{"acc_trans_id_$i"}
 
 954           && (SL::DB::Default->get->payments_changeable == 0)) {
 
 958       next if ($form->{"paid_$i"} == 0);
 
 960       my ($accno) = split(/--/, $form->{"AR_paid_$i"});
 
 961       $form->{"datepaid_$i"} = $form->{invdate}
 
 962       unless ($form->{"datepaid_$i"});
 
 963       $form->{datepaid} = $form->{"datepaid_$i"};
 
 967       if ($form->{currency} eq $defaultcurrency) {
 
 968         $form->{"exchangerate_$i"} = 1;
 
 970         $exchangerate              = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy');
 
 971         $form->{"exchangerate_$i"} = $exchangerate || $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
 
 975       $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $diff, 2);
 
 977       if ($form->{amount}{ $form->{id} }{ $form->{AR} } != 0) {
 
 979         qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
 
 980            VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
 
 983                     WHERE chart_id= (SELECT id
 
 987                     ORDER BY startdate DESC LIMIT 1),
 
 990                     WHERE chart_id= (SELECT id
 
 994                     ORDER BY startdate DESC LIMIT 1),
 
 996                    (SELECT link FROM chart WHERE accno = ?))|;
 
 997         @values = (conv_i($form->{"id"}), $form->{AR}, $amount, $form->{"datepaid_$i"}, $form->{AR}, conv_date($taxdate), $form->{AR}, conv_date($taxdate), $project_id, $form->{AR});
 
 998         do_query($form, $dbh, $query, @values);
 
1002       $form->{"paid_$i"} *= -1;
 
1003       my $gldate = (conv_date($form->{"gldate_$i"}))? conv_date($form->{"gldate_$i"}) : conv_date($form->current_date($myconfig));
 
1006       qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, gldate, source, memo, tax_id, taxkey, project_id, chart_link)
 
1007          VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, ?, ?, ?,
 
1010                   WHERE chart_id= (SELECT id
 
1014                   ORDER BY startdate DESC LIMIT 1),
 
1017                   WHERE chart_id= (SELECT id
 
1021                   ORDER BY startdate DESC LIMIT 1),
 
1023                  (SELECT link FROM chart WHERE accno = ?))|;
 
1024       @values = (conv_i($form->{"id"}), $accno, $form->{"paid_$i"}, $form->{"datepaid_$i"},
 
1025                  $gldate, $form->{"source_$i"}, $form->{"memo_$i"}, $accno, conv_date($taxdate), $accno, conv_date($taxdate), $project_id, $accno);
 
1026       do_query($form, $dbh, $query, @values);
 
1028       # exchangerate difference
 
1029       $form->{fx}{$accno}{ $form->{"datepaid_$i"} } +=
 
1030         $form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $diff;
 
1034         $form->{"paid_$i"} * $form->{exchangerate} - $form->{"paid_$i"} *
 
1035         $form->{"exchangerate_$i"};
 
1037         $form->{fx}{ $form->{fxgain_accno} }{ $form->{"datepaid_$i"} } += $amount;
 
1039         $form->{fx}{ $form->{fxloss_accno} }{ $form->{"datepaid_$i"} } += $amount;
 
1044       # update exchange rate
 
1045       if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
 
1046         $form->update_exchangerate($dbh, $form->{currency},
 
1047                                    $form->{"datepaid_$i"},
 
1048                                    $form->{"exchangerate_$i"}, 0);
 
1052   } else {                      # if (!$form->{storno})
 
1053     $form->{marge_total} *= -1;
 
1056   IO->set_datepaid(table => 'ar', id => $form->{id}, dbh => $dbh);
 
1058   # record exchange rate differences and gains/losses
 
1059   foreach my $accno (keys %{ $form->{fx} }) {
 
1060     foreach my $transdate (keys %{ $form->{fx}{$accno} }) {
 
1061       $form->{fx}{$accno}{$transdate} = $form->round_amount($form->{fx}{$accno}{$transdate}, 2);
 
1062       if ( $form->{fx}{$accno}{$transdate} != 0 ) {
 
1065           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, cleared, fx_transaction, tax_id, taxkey, project_id, chart_link)
 
1066              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, '0', '1',
 
1069                   WHERE chart_id= (SELECT id
 
1073                   ORDER BY startdate DESC LIMIT 1),
 
1076                   WHERE chart_id= (SELECT id
 
1080                   ORDER BY startdate DESC LIMIT 1),
 
1082                  (SELECT link FROM chart WHERE accno = ?))|;
 
1083         @values = (conv_i($form->{"id"}), $accno, $form->{fx}{$accno}{$transdate}, conv_date($transdate), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno);
 
1084         do_query($form, $dbh, $query, @values);
 
1089   if ($payments_only) {
 
1090     $query = qq|UPDATE ar SET paid = ? WHERE id = ?|;
 
1091     do_query($form, $dbh, $query,  $form->{paid}, conv_i($form->{id}));
 
1093     $dbh->commit if !$provided_dbh;
 
1095     $main::lxdebug->leave_sub();
 
1099   $amount = $netamount + $tax;
 
1102   #erweiterung fuer lieferscheinnummer (donumber) 12.02.09 jb
 
1104   $query = qq|UPDATE ar set
 
1105                 invnumber   = ?, ordnumber     = ?, quonumber     = ?, cusordnumber  = ?,
 
1106                 transdate   = ?, orddate       = ?, quodate       = ?, customer_id   = ?,
 
1107                 amount      = ?, netamount     = ?, paid          = ?,
 
1108                 duedate     = ?, deliverydate  = ?, invoice       = ?, shippingpoint = ?,
 
1109                 shipvia     = ?, terms         = ?, notes         = ?, intnotes      = ?,
 
1110                 currency_id = (SELECT id FROM currencies WHERE name = ?),
 
1111                 department_id = ?, payment_id    = ?, taxincluded   = ?,
 
1112                 type        = ?, language_id   = ?, taxzone_id    = ?, shipto_id     = ?,
 
1113                 employee_id = ?, salesman_id   = ?, storno_id     = ?, storno        = ?,
 
1114                 cp_id       = ?, marge_total   = ?, marge_percent = ?,
 
1115                 globalproject_id               = ?, delivery_customer_id             = ?,
 
1116                 transaction_description        = ?, delivery_vendor_id               = ?,
 
1117                 donumber    = ?, invnumber_for_credit_note = ?,        direct_debit  = ?,
 
1118                 delivery_term_id = ?
 
1120   @values = (          $form->{"invnumber"},           $form->{"ordnumber"},             $form->{"quonumber"},          $form->{"cusordnumber"},
 
1121              conv_date($form->{"invdate"}),  conv_date($form->{"orddate"}),    conv_date($form->{"quodate"}),    conv_i($form->{"customer_id"}),
 
1122                        $amount,                        $netamount,                       $form->{"paid"},
 
1123              conv_date($form->{"duedate"}),  conv_date($form->{"deliverydate"}),    '1',                                $form->{"shippingpoint"},
 
1124                        $form->{"shipvia"},      conv_i($form->{"terms"}),                $form->{"notes"},              $form->{"intnotes"},
 
1125                        $form->{"currency"},     conv_i($form->{"department_id"}), conv_i($form->{"payment_id"}),        $form->{"taxincluded"} ? 't' : 'f',
 
1126                        $form->{"type"},         conv_i($form->{"language_id"}),   conv_i($form->{"taxzone_id"}), conv_i($form->{"shipto_id"}),
 
1127                 conv_i($form->{"employee_id"}), conv_i($form->{"salesman_id"}),   conv_i($form->{storno_id}),           $form->{"storno"} ? 't' : 'f',
 
1128                 conv_i($form->{"cp_id"}),            1 * $form->{marge_total} ,      1 * $form->{marge_percent},
 
1129                 conv_i($form->{"globalproject_id"}),                              conv_i($form->{"delivery_customer_id"}),
 
1130                        $form->{transaction_description},                          conv_i($form->{"delivery_vendor_id"}),
 
1131                        $form->{"donumber"}, $form->{"invnumber_for_credit_note"},        $form->{direct_debit} ? 't' : 'f',
 
1132                 conv_i($form->{delivery_term_id}),
 
1133                 conv_i($form->{"id"}));
 
1134   do_query($form, $dbh, $query, @values);
 
1137   if ($form->{storno}) {
 
1140            paid = paid + amount,
 
1142            intnotes = ? || intnotes
 
1144     do_query($form, $dbh, $query, "Rechnung storniert am $form->{invdate} ", conv_i($form->{"storno_id"}));
 
1145     do_query($form, $dbh, qq|UPDATE ar SET paid = amount WHERE id = ?|, conv_i($form->{"id"}));
 
1148   $form->{name} = $form->{customer};
 
1149   $form->{name} =~ s/--\Q$form->{customer_id}\E//;
 
1152   if (!$form->{shipto_id}) {
 
1153     $form->add_shipto($dbh, $form->{id}, "AR");
 
1156   # save printed, emailed and queued
 
1157   $form->save_status($dbh);
 
1159   Common::webdav_folder($form);
 
1161   # Link this record to the records it was created from.
 
1162   RecordLinks->create_links('dbh'        => $dbh,
 
1164                             'from_table' => 'oe',
 
1165                             'from_ids'   => $form->{convert_from_oe_ids},
 
1167                             'to_id'      => $form->{id},
 
1169   delete $form->{convert_from_oe_ids};
 
1171   my @convert_from_do_ids = map { $_ * 1 } grep { $_ } split m/\s+/, $form->{convert_from_do_ids};
 
1173   if (scalar @convert_from_do_ids) {
 
1174     DO->close_orders('dbh' => $dbh,
 
1175                      'ids' => \@convert_from_do_ids);
 
1177     RecordLinks->create_links('dbh'        => $dbh,
 
1179                               'from_table' => 'delivery_orders',
 
1180                               'from_ids'   => \@convert_from_do_ids,
 
1182                               'to_id'      => $form->{id},
 
1185   delete $form->{convert_from_do_ids};
 
1187   ARAP->close_orders_if_billed('dbh'     => $dbh,
 
1188                                'arap_id' => $form->{id},
 
1191   # safety check datev export
 
1192   if ($::instance_conf->get_datev_check_on_sales_invoice) {
 
1193     my $transdate = $::form->{invdate} ? DateTime->from_lxoffice($::form->{invdate}) : undef;
 
1194     $transdate  ||= DateTime->today;
 
1196     my $datev = SL::DATEV->new(
 
1197       exporttype => DATEV_ET_BUCHUNGEN,
 
1198       format     => DATEV_FORMAT_KNE,
 
1202       trans_id   => $form->{id},
 
1207     if ($datev->errors) {
 
1209       die join "\n", $::locale->text('DATEV check returned errors:'), $datev->errors;
 
1214   $dbh->commit if !$provided_dbh;
 
1216   $main::lxdebug->leave_sub();
 
1221 sub _delete_payments {
 
1222   $main::lxdebug->enter_sub();
 
1224   my ($self, $form, $dbh) = @_;
 
1226   my @delete_acc_trans_ids;
 
1228   # Delete old payment entries from acc_trans.
 
1230     qq|SELECT acc_trans_id
 
1232        WHERE (trans_id = ?) AND fx_transaction
 
1236        SELECT at.acc_trans_id
 
1238        LEFT JOIN chart c ON (at.chart_id = c.id)
 
1239        WHERE (trans_id = ?) AND (c.link LIKE '%AR_paid%')|;
 
1240   push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}), conv_i($form->{id}));
 
1243     qq|SELECT at.acc_trans_id
 
1245        LEFT JOIN chart c ON (at.chart_id = c.id)
 
1246        WHERE (trans_id = ?)
 
1247          AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
 
1248        ORDER BY at.acc_trans_id
 
1250   push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}));
 
1252   if (@delete_acc_trans_ids) {
 
1253     $query = qq|DELETE FROM acc_trans WHERE acc_trans_id IN (| . join(", ", @delete_acc_trans_ids) . qq|)|;
 
1254     do_query($form, $dbh, $query);
 
1257   $main::lxdebug->leave_sub();
 
1261   $main::lxdebug->enter_sub();
 
1263   my ($self, $myconfig, $form, $locale) = @_;
 
1265   # connect to database, turn off autocommit
 
1266   my $dbh = $form->get_standard_dbh;
 
1268   my (%payments, $old_form, $row, $item, $query, %keep_vars);
 
1270   $old_form = save_form();
 
1272   # Delete all entries in acc_trans from prior payments.
 
1273   if (SL::DB::Default->get->payments_changeable != 0) {
 
1274     $self->_delete_payments($form, $dbh);
 
1277   # Save the new payments the user made before cleaning up $form.
 
1278   map { $payments{$_} = $form->{$_} } grep m/^datepaid_\d+$|^gldate_\d+$|^acc_trans_id_\d+$|^memo_\d+$|^source_\d+$|^exchangerate_\d+$|^paid_\d+$|^AR_paid_\d+$|^paidaccounts$/, keys %{ $form };
 
1280   # Clean up $form so that old content won't tamper the results.
 
1281   %keep_vars = map { $_, 1 } qw(login password id);
 
1282   map { delete $form->{$_} unless $keep_vars{$_} } keys %{ $form };
 
1284   # Retrieve the invoice from the database.
 
1285   $self->retrieve_invoice($myconfig, $form);
 
1287   # Set up the content of $form in the way that IS::post_invoice() expects.
 
1288   $form->{exchangerate} = $form->format_amount($myconfig, $form->{exchangerate});
 
1290   for $row (1 .. scalar @{ $form->{invoice_details} }) {
 
1291     $item = $form->{invoice_details}->[$row - 1];
 
1293     map { $item->{$_} = $form->format_amount($myconfig, $item->{$_}) } qw(qty sellprice discount);
 
1295     map { $form->{"${_}_${row}"} = $item->{$_} } keys %{ $item };
 
1298   $form->{rowcount} = scalar @{ $form->{invoice_details} };
 
1300   delete @{$form}{qw(invoice_details paidaccounts storno paid)};
 
1302   # Restore the payment options from the user input.
 
1303   map { $form->{$_} = $payments{$_} } keys %payments;
 
1305   # Get the AR accno (which is normally done by Form::create_links()).
 
1309        LEFT JOIN chart c ON (at.chart_id = c.id)
 
1310        WHERE (trans_id = ?)
 
1311          AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
 
1312        ORDER BY at.acc_trans_id
 
1315   ($form->{AR}) = selectfirst_array_query($form, $dbh, $query, conv_i($form->{id}));
 
1317   # Post the new payments.
 
1318   $self->post_invoice($myconfig, $form, $dbh, 1);
 
1320   restore_form($old_form);
 
1322   my $rc = $dbh->commit();
 
1324   $main::lxdebug->leave_sub();
 
1329 sub process_assembly {
 
1330   $main::lxdebug->enter_sub();
 
1332   my ($dbh, $myconfig, $form, $id, $totalqty) = @_;
 
1335     qq|SELECT a.parts_id, a.qty, p.assembly, p.partnumber, p.description, p.unit,
 
1336          p.inventory_accno_id, p.income_accno_id, p.expense_accno_id
 
1338        JOIN parts p ON (a.parts_id = p.id)
 
1340   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
 
1342   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1346     $ref->{inventory_accno_id} *= 1;
 
1347     $ref->{expense_accno_id}   *= 1;
 
1349     # multiply by number of assemblies
 
1350     $ref->{qty} *= $totalqty;
 
1352     if ($ref->{assembly}) {
 
1353       &process_assembly($dbh, $myconfig, $form, $ref->{parts_id}, $ref->{qty});
 
1356       if ($ref->{inventory_accno_id}) {
 
1357         $allocated = &cogs($dbh, $myconfig, $form, $ref->{parts_id}, $ref->{qty});
 
1361     # save detail record for individual assembly item in invoice table
 
1363       qq|INSERT INTO invoice (trans_id, description, parts_id, qty, sellprice, fxsellprice, allocated, assemblyitem, unit)
 
1364          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)|;
 
1365     my @values = (conv_i($form->{id}), $ref->{description}, conv_i($ref->{parts_id}), $ref->{qty}, 0, 0, $allocated, 't', $ref->{unit});
 
1366     do_query($form, $dbh, $query, @values);
 
1372   $main::lxdebug->leave_sub();
 
1376   $main::lxdebug->enter_sub();
 
1378   # adjust allocated in table invoice according to FIFO princicple
 
1379   # for a certain part with part_id $id
 
1381   my ($dbh, $myconfig, $form, $id, $totalqty, $basefactor, $row) = @_;
 
1385   $form->{taxzone_id} *=1;
 
1386   my $transdate  = $form->{invdate} ? $dbh->quote($form->{invdate}) : "current_date";
 
1387   my $taxzone_id = $form->{"taxzone_id"} * 1;
 
1389     qq|SELECT i.id, i.trans_id, i.base_qty, i.allocated, i.sellprice, i.price_factor,
 
1390          c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
 
1391          c2.accno AS    income_accno, c2.new_chart_id AS    income_new_chart, date($transdate) - c2.valid_from AS    income_valid,
 
1392          c3.accno AS   expense_accno, c3.new_chart_id AS   expense_new_chart, date($transdate) - c3.valid_from AS   expense_valid
 
1393        FROM invoice i, parts p
 
1394        LEFT JOIN chart c1 ON ((SELECT inventory_accno_id FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
 
1395        LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
 
1396        LEFT JOIN chart c3 ON ((select expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
 
1397        WHERE (i.parts_id = p.id)
 
1398          AND (i.parts_id = ?)
 
1399          AND ((i.base_qty + i.allocated) < 0)
 
1401   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
 
1406 # all invoice entries of an example part:
 
1408 # id | trans_id | base_qty | allocated | sellprice | inventory_accno | income_accno | expense_accno
 
1409 # ---+----------+----------+-----------+-----------+-----------------+--------------+---------------
 
1410 #  4 |        4 |       -5 |         5 |  20.00000 | 1140            | 4400         | 5400     bought 5 for 20
 
1411 #  5 |        5 |        4 |        -4 |  50.00000 | 1140            | 4400         | 5400     sold   4 for 50
 
1412 #  6 |        6 |        1 |        -1 |  50.00000 | 1140            | 4400         | 5400     sold   1 for 50
 
1413 #  7 |        7 |       -5 |         1 |  20.00000 | 1140            | 4400         | 5400     bought 5 for 20
 
1414 #  8 |        8 |        1 |        -1 |  50.00000 | 1140            | 4400         | 5400     sold   1 for 50
 
1416 # AND ((i.base_qty + i.allocated) < 0) filters out all but line with id=7, elsewhere i.base_qty + i.allocated has already reached 0
 
1417 # and all parts have been allocated
 
1419 # so transaction 8 only sees transaction 7 with unallocated parts and adjusts allocated for that transaction, before allocated was 0
 
1420 #  7 |        7 |       -5 |         1 |  20.00000 | 1140            | 4400         | 5400     bought 5 for 20
 
1422 # in this example there are still 4 unsold articles
 
1425   # search all invoice entries for the part in question, adjusting "allocated"
 
1426   # until the total number of sold parts has been reached
 
1428   # ORDER BY trans_id ensures FIFO
 
1431   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1432     if (($qty = (($ref->{base_qty} * -1) - $ref->{allocated})) > $totalqty) {
 
1436     # update allocated in invoice
 
1437     $form->update_balance($dbh, "invoice", "allocated", qq|id = $ref->{id}|, $qty);
 
1439     # total expenses and inventory
 
1440     # sellprice is the cost of the item
 
1441     my $linetotal = $form->round_amount(($ref->{sellprice} * $qty) / ( ($ref->{price_factor} || 1) * ( $basefactor || 1 )), 2);
 
1443     if ( $::instance_conf->get_inventory_system eq 'perpetual' ) {
 
1444       # Bestandsmethode: when selling parts, deduct their purchase value from the inventory account
 
1445       $ref->{expense_accno} = ($form->{"expense_accno_$row"}) ? $form->{"expense_accno_$row"} : $ref->{expense_accno};
 
1447       $form->{amount_cogs}{ $form->{id} }{ $ref->{expense_accno} } += -$linetotal;
 
1448       $form->{expense_inventory} .= " " . $ref->{expense_accno};
 
1449       $ref->{inventory_accno} = ($form->{"inventory_accno_$row"}) ? $form->{"inventory_accno_$row"} : $ref->{inventory_accno};
 
1451       $form->{amount_cogs}{ $form->{id} }{ $ref->{inventory_accno} } -= -$linetotal;
 
1452       $form->{expense_inventory} .= " " . $ref->{inventory_accno};
 
1458     last if (($totalqty -= $qty) <= 0);
 
1463   $main::lxdebug->leave_sub();
 
1468 sub reverse_invoice {
 
1469   $main::lxdebug->enter_sub();
 
1471   my ($dbh, $form) = @_;
 
1473   # reverse inventory items
 
1475     qq|SELECT i.id, i.parts_id, i.qty, i.assemblyitem, p.assembly, p.inventory_accno_id
 
1477        JOIN parts p ON (i.parts_id = p.id)
 
1478        WHERE i.trans_id = ?|;
 
1479   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id"}));
 
1481   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1483     if ($ref->{inventory_accno_id}) {
 
1484       # de-allocated purchases
 
1486         qq|SELECT i.id, i.trans_id, i.allocated
 
1488            WHERE (i.parts_id = ?) AND (i.allocated > 0)
 
1489            ORDER BY i.trans_id DESC|;
 
1490       my $sth2 = prepare_execute_query($form, $dbh, $query, conv_i($ref->{"parts_id"}));
 
1492       while (my $inhref = $sth2->fetchrow_hashref('NAME_lc')) {
 
1493         my $qty = $ref->{qty};
 
1494         if (($ref->{qty} - $inhref->{allocated}) > 0) {
 
1495           $qty = $inhref->{allocated};
 
1499         $form->update_balance($dbh, "invoice", "allocated", qq|id = $inhref->{id}|, $qty * -1);
 
1501         last if (($ref->{qty} -= $qty) <= 0);
 
1510   my @values = (conv_i($form->{id}));
 
1511   do_query($form, $dbh, qq|DELETE FROM acc_trans WHERE trans_id = ?|, @values);
 
1512   do_query($form, $dbh, qq|DELETE FROM invoice WHERE trans_id = ?|, @values);
 
1513   do_query($form, $dbh, qq|DELETE FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|, @values);
 
1515   $main::lxdebug->leave_sub();
 
1518 sub delete_invoice {
 
1519   $main::lxdebug->enter_sub();
 
1521   my ($self, $myconfig, $form) = @_;
 
1523   # connect to database
 
1524   my $dbh = $form->get_standard_dbh;
 
1526   &reverse_invoice($dbh, $form);
 
1528   my @values = (conv_i($form->{id}));
 
1530   # Falls wir ein Storno haben, müssen zwei Felder in der stornierten Rechnung wieder
 
1531   # zurückgesetzt werden. Vgl:
 
1532   #  id | storno | storno_id |  paid   |  amount
 
1533   #----+--------+-----------+---------+-----------
 
1534   # 18 | f      |           | 0.00000 | 119.00000
 
1536   # 18 | t      |           |  119.00000 |  119.00000
 
1538   if($form->{storno}){
 
1539     # storno_id auslesen und korrigieren
 
1540     my ($invoice_id) = selectfirst_array_query($form, $dbh, qq|SELECT storno_id FROM ar WHERE id = ?|,@values);
 
1541     do_query($form, $dbh, qq|UPDATE ar SET storno = 'f', paid = 0 WHERE id = ?|, $invoice_id);
 
1544   # delete spool files
 
1545   my @spoolfiles = selectall_array_query($form, $dbh, qq|SELECT spoolfile FROM status WHERE trans_id = ?|, @values);
 
1548     qq|DELETE FROM status WHERE trans_id = ?|,
 
1549     qq|DELETE FROM periodic_invoices WHERE ar_id = ?|,
 
1550     qq|DELETE FROM ar WHERE id = ?|,
 
1553   map { do_query($form, $dbh, $_, @values) } @queries;
 
1555   my $rc = $dbh->commit;
 
1558     my $spool = $::lx_office_conf{paths}->{spool};
 
1559     map { unlink "$spool/$_" if -f "$spool/$_"; } @spoolfiles;
 
1562   $main::lxdebug->leave_sub();
 
1567 sub retrieve_invoice {
 
1568   $main::lxdebug->enter_sub();
 
1570   my ($self, $myconfig, $form) = @_;
 
1572   # connect to database
 
1573   my $dbh = $form->get_standard_dbh;
 
1575   my ($sth, $ref, $query);
 
1577   my $query_transdate = !$form->{id} ? ", current_date AS invdate" : '';
 
1581          (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
 
1582          (SELECT c.accno FROM chart c WHERE d.income_accno_id = c.id)    AS income_accno,
 
1583          (SELECT c.accno FROM chart c WHERE d.expense_accno_id = c.id)   AS expense_accno,
 
1584          (SELECT c.accno FROM chart c WHERE d.fxgain_accno_id = c.id)    AS fxgain_accno,
 
1585          (SELECT c.accno FROM chart c WHERE d.fxloss_accno_id = c.id)    AS fxloss_accno
 
1589   $ref = selectfirst_hashref_query($form, $dbh, $query);
 
1590   map { $form->{$_} = $ref->{$_} } keys %{ $ref };
 
1593     my $id = conv_i($form->{id});
 
1596     #erweiterung um das entsprechende feld lieferscheinnummer (a.donumber) in der html-maske anzuzeigen 12.02.2009 jb
 
1600            a.invnumber, a.ordnumber, a.quonumber, a.cusordnumber,
 
1601            a.orddate, a.quodate, a.globalproject_id,
 
1602            a.transdate AS invdate, a.deliverydate, a.paid, a.storno, a.gldate,
 
1603            a.shippingpoint, a.shipvia, a.terms, a.notes, a.intnotes, a.taxzone_id,
 
1604            a.duedate, a.taxincluded, (SELECT cu.name FROM currencies cu WHERE cu.id=a.currency_id) AS currency, a.shipto_id, a.cp_id,
 
1605            a.employee_id, a.salesman_id, a.payment_id,
 
1606            a.language_id, a.delivery_customer_id, a.delivery_vendor_id, a.type,
 
1607            a.transaction_description, a.donumber, a.invnumber_for_credit_note,
 
1608            a.marge_total, a.marge_percent, a.direct_debit, a.delivery_term_id,
 
1611          LEFT JOIN employee e ON (e.id = a.employee_id)
 
1613     $ref = selectfirst_hashref_query($form, $dbh, $query, $id);
 
1614     map { $form->{$_} = $ref->{$_} } keys %{ $ref };
 
1616     $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "buy");
 
1618     foreach my $vc (qw(customer vendor)) {
 
1619       next if !$form->{"delivery_${vc}_id"};
 
1620       ($form->{"delivery_${vc}_string"}) = selectrow_query($form, $dbh, qq|SELECT name FROM customer WHERE id = ?|, $id);
 
1623     # get printed, emailed
 
1624     $query = qq|SELECT printed, emailed, spoolfile, formname FROM status WHERE trans_id = ?|;
 
1625     $sth = prepare_execute_query($form, $dbh, $query, $id);
 
1627     while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1628       $form->{printed} .= "$ref->{formname} " if $ref->{printed};
 
1629       $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
 
1630       $form->{queued} .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
 
1633     map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
 
1635     my $transdate = $form->{deliverydate} ? $dbh->quote($form->{deliverydate})
 
1636                   : $form->{invdate}      ? $dbh->quote($form->{invdate})
 
1640     my $taxzone_id = $form->{taxzone_id} *= 1;
 
1641     $taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
 
1643     # retrieve individual items
 
1646            c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
 
1647            c2.accno AS income_accno,    c2.new_chart_id AS income_new_chart,    date($transdate) - c2.valid_from as income_valid,
 
1648            c3.accno AS expense_accno,   c3.new_chart_id AS expense_new_chart,   date($transdate) - c3.valid_from AS expense_valid,
 
1651            i.description, i.longdescription, i.qty, i.fxsellprice AS sellprice, i.discount, i.parts_id AS id, i.unit, i.deliverydate AS reqdate,
 
1652            i.project_id, i.serialnumber, i.id AS invoice_pos, i.pricegroup_id, i.ordnumber, i.donumber, i.transdate, i.cusordnumber, i.subtotal, i.lastcost,
 
1653            i.price_factor_id, i.price_factor, i.marge_price_factor,
 
1654            p.partnumber, p.assembly, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id, p.formel, p.listprice,
 
1655            pr.projectnumber, pg.partsgroup, prg.pricegroup
 
1658          LEFT JOIN parts p ON (i.parts_id = p.id)
 
1659          LEFT JOIN project pr ON (i.project_id = pr.id)
 
1660          LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
 
1661          LEFT JOIN pricegroup prg ON (i.pricegroup_id = prg.id)
 
1663          LEFT JOIN chart c1 ON ((SELECT inventory_accno_id             FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
 
1664          LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id}  FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
 
1665          LEFT JOIN chart c3 ON ((SELECT expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
 
1667          WHERE (i.trans_id = ?) AND NOT (i.assemblyitem = '1') ORDER BY i.id|;
 
1669     $sth = prepare_execute_query($form, $dbh, $query, $id);
 
1671     while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1672       # Retrieve custom variables.
 
1673       my $cvars = CVar->get_custom_variables(dbh        => $dbh,
 
1675                                              sub_module => 'invoice',
 
1676                                              trans_id   => $ref->{invoice_id},
 
1678       map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
 
1679       delete $ref->{invoice_id};
 
1681       map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid)) if !$ref->{"part_inventory_accno_id"};
 
1682       delete($ref->{"part_inventory_accno_id"});
 
1684       foreach my $type (qw(inventory income expense)) {
 
1685         while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
 
1686           my $query = qq|SELECT accno, new_chart_id, date($transdate) - valid_from FROM chart WHERE id = ?|;
 
1687           @$ref{ map $type.$_, qw(_accno _new_chart _valid) } = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
 
1691       # get tax rates and description
 
1692       my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
 
1694         qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber FROM tax t
 
1695            LEFT JOIN chart c ON (c.id = t.chart_id)
 
1697              (SELECT tk.tax_id FROM taxkeys tk
 
1698               WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?)
 
1699                 AND startdate <= date($transdate)
 
1700               ORDER BY startdate DESC LIMIT 1)
 
1702       my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
 
1703       $ref->{taxaccounts} = "";
 
1705       while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
 
1707         if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
 
1711         $ref->{taxaccounts} .= "$ptr->{accno} ";
 
1713         if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
 
1714           $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
 
1715           $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
 
1716           $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
 
1717           $form->{taxaccounts} .= "$ptr->{accno} ";
 
1722       $ref->{qty} *= -1 if $form->{type} eq "credit_note";
 
1724       chop $ref->{taxaccounts};
 
1725       push @{ $form->{invoice_details} }, $ref;
 
1730     Common::webdav_folder($form);
 
1733   my $rc = $dbh->commit;
 
1735   $main::lxdebug->leave_sub();
 
1741   $main::lxdebug->enter_sub();
 
1743   my ($self, $myconfig, $form) = @_;
 
1745   # connect to database
 
1746   my $dbh = $form->get_standard_dbh;
 
1748   my $dateformat = $myconfig->{dateformat};
 
1749   $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/;
 
1751   my (@values, $duedate, $ref, $query);
 
1753   if ($form->{invdate}) {
 
1754     $duedate = "to_date(?, '$dateformat')";
 
1755     push @values, $form->{invdate};
 
1757     $duedate = "current_date";
 
1760   my $cid = conv_i($form->{customer_id});
 
1763   if ($form->{payment_id}) {
 
1764     $payment_id = "(pt.id = ?) OR";
 
1765     push @values, conv_i($form->{payment_id});
 
1771          c.id AS customer_id, c.name AS customer, c.discount as customer_discount, c.creditlimit, c.terms,
 
1772          c.email, c.cc, c.bcc, c.language_id, c.payment_id, c.delivery_term_id,
 
1773          c.street, c.zipcode, c.city, c.country,
 
1774          c.notes AS intnotes, c.klass as customer_klass, c.taxzone_id, c.salesman_id, cu.name AS curr,
 
1775          c.taxincluded_checked, c.direct_debit,
 
1776          $duedate + COALESCE(pt.terms_netto, 0) AS duedate,
 
1777          b.discount AS tradediscount, b.description AS business
 
1779        LEFT JOIN business b ON (b.id = c.business_id)
 
1780        LEFT JOIN payment_terms pt ON ($payment_id (c.payment_id = pt.id))
 
1781        LEFT JOIN currencies cu ON (c.currency_id=cu.id)
 
1784   $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
 
1786   delete $ref->{salesman_id} if !$ref->{salesman_id};
 
1788   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1790   # use customer currency
 
1791   $form->{currency} = $form->{curr};
 
1794     qq|SELECT sum(amount - paid) AS dunning_amount
 
1796        WHERE (paid < amount)
 
1797          AND (customer_id = ?)
 
1798          AND (dunning_config_id IS NOT NULL)|;
 
1799   $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
 
1800   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1803     qq|SELECT dnn.dunning_description AS max_dunning_level
 
1804        FROM dunning_config dnn
 
1805        WHERE id IN (SELECT dunning_config_id
 
1807                     WHERE (paid < amount) AND (customer_id = ?) AND (dunning_config_id IS NOT NULL))
 
1808        ORDER BY dunning_level DESC LIMIT 1|;
 
1809   $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
 
1810   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1812   $form->{creditremaining} = $form->{creditlimit};
 
1813   $query = qq|SELECT SUM(amount - paid) FROM ar WHERE customer_id = ?|;
 
1814   my ($value) = selectrow_query($form, $dbh, $query, $cid);
 
1815   $form->{creditremaining} -= $value;
 
1819          (SELECT e.buy FROM exchangerate e
 
1820           WHERE e.currency_id = o.currency_id
 
1821             AND e.transdate = o.transdate)
 
1823        WHERE o.customer_id = ?
 
1824          AND o.quotation = '0'
 
1825          AND o.closed = '0'|;
 
1826   my $sth = prepare_execute_query($form, $dbh, $query, $cid);
 
1828   while (my ($amount, $exch) = $sth->fetchrow_array) {
 
1829     $exch = 1 unless $exch;
 
1830     $form->{creditremaining} -= $amount * $exch;
 
1834   # setup last accounts used for this customer
 
1835   if (!$form->{id} && $form->{type} !~ /_(order|quotation)/) {
 
1837       qq|SELECT c.id, c.accno, c.description, c.link, c.category
 
1839          JOIN acc_trans ac ON (ac.chart_id = c.id)
 
1840          JOIN ar a ON (a.id = ac.trans_id)
 
1841          WHERE a.customer_id = ?
 
1842            AND NOT (c.link LIKE '%_tax%' OR c.link LIKE '%_paid%')
 
1843            AND a.id IN (SELECT max(a2.id) FROM ar a2 WHERE a2.customer_id = ?)|;
 
1844     $sth = prepare_execute_query($form, $dbh, $query, $cid, $cid);
 
1847     while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1848       if ($ref->{category} eq 'I') {
 
1850         $form->{"AR_amount_$i"} = "$ref->{accno}--$ref->{description}";
 
1852         if ($form->{initial_transdate}) {
 
1854             qq|SELECT tk.tax_id, t.rate
 
1856                LEFT JOIN tax t ON tk.tax_id = t.id
 
1857                WHERE (tk.chart_id = ?) AND (startdate <= date(?))
 
1858                ORDER BY tk.startdate DESC
 
1860           my ($tax_id, $rate) =
 
1861             selectrow_query($form, $dbh, $tax_query, $ref->{id},
 
1862                             $form->{initial_transdate});
 
1863           $form->{"taxchart_$i"} = "${tax_id}--${rate}";
 
1866       if ($ref->{category} eq 'A') {
 
1867         $form->{ARselected} = $form->{AR_1} = $ref->{accno};
 
1871     $form->{rowcount} = $i if ($i && !$form->{type});
 
1874   $main::lxdebug->leave_sub();
 
1878   $main::lxdebug->enter_sub();
 
1880   my ($self, $myconfig, $form) = @_;
 
1882   # connect to database
 
1883   my $dbh = $form->get_standard_dbh;
 
1885   my $i = $form->{rowcount};
 
1887   my $where = qq|NOT p.obsolete = '1'|;
 
1890   foreach my $column (qw(p.partnumber p.description pgpartsgroup )) {
 
1891     my ($table, $field) = split m/\./, $column;
 
1892     next if !$form->{"${field}_${i}"};
 
1893     $where .= qq| AND lower(${column}) ILIKE ?|;
 
1894     push @values, '%' . $form->{"${field}_${i}"} . '%';
 
1897   #Es soll auch nach EAN gesucht werden, ohne Einschränkung durch Beschreibung
 
1898   if ($form->{"partnumber_$i"} && !$form->{"description_$i"}) {
 
1899     $where .= qq| OR (NOT p.obsolete = '1' AND p.ean = ? )|;
 
1900     push @values, $form->{"partnumber_$i"};
 
1903   # Search for part ID overrides all other criteria.
 
1904   if ($form->{"id_${i}"}) {
 
1905     $where  = qq|p.id = ?|;
 
1906     @values = ($form->{"id_${i}"});
 
1909   if ($form->{"description_$i"}) {
 
1910     $where .= qq| ORDER BY p.description|;
 
1912     $where .= qq| ORDER BY p.partnumber|;
 
1916   if ($form->{type} eq "invoice") {
 
1918       $form->{deliverydate} ? $dbh->quote($form->{deliverydate}) :
 
1919       $form->{invdate}      ? $dbh->quote($form->{invdate}) :
 
1923       $form->{transdate}    ? $dbh->quote($form->{transdate}) :
 
1927   my $taxzone_id = $form->{taxzone_id} * 1;
 
1928   $taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
 
1932          p.id, p.partnumber, p.description, p.sellprice,
 
1933          p.listprice, p.inventory_accno_id, p.lastcost,
 
1935          c1.accno AS inventory_accno,
 
1936          c1.new_chart_id AS inventory_new_chart,
 
1937          date($transdate) - c1.valid_from AS inventory_valid,
 
1939          c2.accno AS income_accno,
 
1940          c2.new_chart_id AS income_new_chart,
 
1941          date($transdate)  - c2.valid_from AS income_valid,
 
1943          c3.accno AS expense_accno,
 
1944          c3.new_chart_id AS expense_new_chart,
 
1945          date($transdate) - c3.valid_from AS expense_valid,
 
1947          p.unit, p.assembly, p.onhand,
 
1948          p.notes AS partnotes, p.notes AS longdescription,
 
1949          p.not_discountable, p.formel, p.payment_id AS part_payment_id,
 
1950          p.price_factor_id, p.weight,
 
1952          pfac.factor AS price_factor,
 
1957        LEFT JOIN chart c1 ON
 
1958          ((SELECT inventory_accno_id
 
1959            FROM buchungsgruppen
 
1960            WHERE id = p.buchungsgruppen_id) = c1.id)
 
1961        LEFT JOIN chart c2 ON
 
1962          ((SELECT income_accno_id_${taxzone_id}
 
1963            FROM buchungsgruppen
 
1964            WHERE id = p.buchungsgruppen_id) = c2.id)
 
1965        LEFT JOIN chart c3 ON
 
1966          ((SELECT expense_accno_id_${taxzone_id}
 
1967            FROM buchungsgruppen
 
1968            WHERE id = p.buchungsgruppen_id) = c3.id)
 
1969        LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
 
1970        LEFT JOIN price_factors pfac ON (pfac.id = p.price_factor_id)
 
1972   my $sth = prepare_execute_query($form, $dbh, $query, @values);
 
1974   my @translation_queries = ( [ qq|SELECT tr.translation, tr.longdescription
 
1976                                    WHERE tr.language_id = ? AND tr.parts_id = ?| ],
 
1977                               [ qq|SELECT tr.translation, tr.longdescription
 
1979                                    WHERE tr.language_id IN
 
1982                                       WHERE article_code = (SELECT article_code FROM language WHERE id = ?))
 
1985   map { push @{ $_ }, prepare_query($form, $dbh, $_->[0]) } @translation_queries;
 
1987   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1989     # In der Buchungsgruppe ist immer ein Bestandskonto verknuepft, auch wenn
 
1990     # es sich um eine Dienstleistung handelt. Bei Dienstleistungen muss das
 
1991     # Buchungskonto also aus dem Ergebnis rausgenommen werden.
 
1992     if (!$ref->{inventory_accno_id}) {
 
1993       map({ delete($ref->{"inventory_${_}"}); } qw(accno new_chart valid));
 
1995     delete($ref->{inventory_accno_id});
 
1997     foreach my $type (qw(inventory income expense)) {
 
1998       while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
 
2000           qq|SELECT accno, new_chart_id, date($transdate) - valid_from
 
2003         ($ref->{"${type}_accno"},
 
2004          $ref->{"${type}_new_chart"},
 
2005          $ref->{"${type}_valid"})
 
2006           = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
 
2010     if ($form->{payment_id} eq "") {
 
2011       $form->{payment_id} = $form->{part_payment_id};
 
2014     # get tax rates and description
 
2015     my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
 
2017       qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber
 
2019          LEFT JOIN chart c ON (c.id = t.chart_id)
 
2023             WHERE tk.chart_id = (SELECT id from chart WHERE accno = ?)
 
2025             ORDER BY startdate DESC
 
2028     @values = ($accno_id, $transdate eq "current_date" ? "now" : $transdate);
 
2029     my $stw = $dbh->prepare($query);
 
2030     $stw->execute(@values) || $form->dberror($query);
 
2032     $ref->{taxaccounts} = "";
 
2034     while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
 
2036       if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
 
2040       $ref->{taxaccounts} .= "$ptr->{accno} ";
 
2042       if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
 
2043         $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
 
2044         $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
 
2045         $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
 
2046         $form->{taxaccounts} .= "$ptr->{accno} ";
 
2052     chop $ref->{taxaccounts};
 
2054     if ($form->{language_id}) {
 
2055       for my $spec (@translation_queries) {
 
2056         do_statement($form, $spec->[1], $spec->[0], conv_i($form->{language_id}), conv_i($ref->{id}));
 
2057         my ($translation, $longdescription) = $spec->[1]->fetchrow_array;
 
2058         next unless $translation;
 
2059         $ref->{description} = $translation;
 
2060         $ref->{longdescription} = $longdescription;
 
2065     $ref->{onhand} *= 1;
 
2067     push @{ $form->{item_list} }, $ref;
 
2070   $_->[1]->finish for @translation_queries;
 
2072   foreach my $item (@{ $form->{item_list} }) {
 
2073     my $custom_variables = CVar->get_custom_variables(module   => 'IC',
 
2074                                                       trans_id => $item->{id},
 
2078     map { $item->{"ic_cvar_" . $_->{name} } = $_->{value} } @{ $custom_variables };
 
2081   $main::lxdebug->leave_sub();
 
2084 ##########################
 
2085 # get pricegroups from database
 
2086 # build up selected pricegroup
 
2087 # if an exchange rate - change price
 
2090 sub get_pricegroups_for_parts {
 
2092   $main::lxdebug->enter_sub();
 
2094   my ($self, $myconfig, $form) = @_;
 
2096   my $dbh = $form->get_standard_dbh;
 
2098   $form->{"PRICES"} = {};
 
2102   my $all_units = AM->retrieve_units($myconfig, $form);
 
2103   while (($form->{"id_$i"}) or ($form->{"new_id_$i"})) {
 
2104     $form->{"PRICES"}{$i} = [];
 
2106     $id = $form->{"id_$i"};
 
2108     if (!($form->{"id_$i"}) and $form->{"new_id_$i"}) {
 
2109       $id = $form->{"new_id_$i"};
 
2112     my ($price, $selectedpricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
 
2114     my $pricegroup_old = $form->{"pricegroup_old_$i"};
 
2116     # sellprice has format 13,0000 or 0,00000,  can't check for 0 numerically
 
2117     my $sellprice = $form->{"sellprice_$i"};
 
2118     my $pricegroup_id = $form->{"pricegroup_id_$i"};
 
2119     $form->{"new_pricegroup_$i"} = $selectedpricegroup_id;
 
2120     $form->{"old_pricegroup_$i"} = $pricegroup_old;
 
2122     my $price_new = $form->{"price_new_$i"};
 
2123     my $price_old = $form->{"price_old_$i"};
 
2125     if (!$form->{"unit_old_$i"}) {
 
2126       # Neue Ware aus der Datenbank. In diesem Fall ist unit_$i die
 
2127       # Einheit, wie sie in den Stammdaten hinterlegt wurde.
 
2128       # Es sollte also angenommen werden, dass diese ausgewaehlt war.
 
2129       $form->{"unit_old_$i"} = $form->{"unit_$i"};
 
2132     # Die zuletzt ausgewaehlte mit der aktuell ausgewaehlten Einheit
 
2133     # vergleichen und bei Unterschied den Preis entsprechend umrechnen.
 
2134     $form->{"selected_unit_$i"} = $form->{"unit_$i"} unless ($form->{"selected_unit_$i"});
 
2136     if (!$all_units->{$form->{"selected_unit_$i"}} ||
 
2137         ($all_units->{$form->{"selected_unit_$i"}}->{"base_unit"} ne
 
2138          $all_units->{$form->{"unit_old_$i"}}->{"base_unit"})) {
 
2139       # Die ausgewaehlte Einheit ist fuer diesen Artikel nicht gueltig
 
2140       # (z.B. Dimensionseinheit war ausgewaehlt, es handelt sich aber
 
2141       # um eine Dienstleistung). Dann keinerlei Umrechnung vornehmen.
 
2142       $form->{"unit_old_$i"} = $form->{"selected_unit_$i"} = $form->{"unit_$i"};
 
2147     if ($form->{"unit_old_$i"} ne $form->{"selected_unit_$i"}) {
 
2148       if (defined($all_units->{$form->{"unit_old_$i"}}->{"factor"}) &&
 
2149           $all_units->{$form->{"unit_old_$i"}}->{"factor"}) {
 
2150         $basefactor = $all_units->{$form->{"selected_unit_$i"}}->{"factor"} /
 
2151           $all_units->{$form->{"unit_old_$i"}}->{"factor"};
 
2155     if (!$form->{"basefactor_$i"}) {
 
2156       $form->{"basefactor_$i"} = 1;
 
2162             sellprice AS default_sellprice,
 
2165             'selected' AS selected
 
2171            parts.sellprice AS default_sellprice,
 
2172            pricegroup.pricegroup,
 
2176           LEFT JOIN parts ON parts.id = parts_id
 
2177           LEFT JOIN pricegroup ON pricegroup.id = pricegroup_id
 
2179           ORDER BY pricegroup|;
 
2180     my @values = (conv_i($id), conv_i($id));
 
2181     my $pkq = prepare_execute_query($form, $dbh, $query, @values);
 
2183     while (my $pkr = $pkq->fetchrow_hashref('NAME_lc')) {
 
2185       $pkr->{selected} = '';
 
2187       # if there is an exchange rate change price
 
2188       if (($form->{exchangerate} * 1) != 0) {
 
2189         $pkr->{price} /= $form->{exchangerate};
 
2192       $pkr->{price} *= $form->{"basefactor_$i"};
 
2193       $pkr->{price} *= $basefactor;
 
2194       $pkr->{price_ufmt} = $pkr->{price};
 
2195       $pkr->{price} = $form->format_amount($myconfig, $pkr->{price}, 5);
 
2197       if (!defined $selectedpricegroup_id) {
 
2198         # new entries in article list, either old invoice was loaded (edit) or a new article was added
 
2199         # Case A: open old invoice, no pricegroup selected
 
2200         # Case B: add new article to invoice, no pricegroup selected
 
2202         # to distinguish case A and B the variable pricegroup_id_$i is used
 
2203         # for new articles this variable isn't defined, for loaded articles it is
 
2204         # sellprice can't be used, as it already has 0,00 set
 
2206         if ($pkr->{pricegroup_id} eq $form->{"pricegroup_id_$i"} and defined $form->{"pricegroup_id_$i"}) {
 
2208           $pkr->{selected}  = ' selected';
 
2209         } elsif ($pkr->{pricegroup_id} eq $form->{customer_klass}
 
2210                  and not defined $form->{"pricegroup_id_$i"}
 
2211                  and $pkr->{price_ufmt} != 0    # only use customer pricegroup price if it has a value, else use default_sellprice
 
2212                                                 # for the case where pricegroup prices haven't been set
 
2214           # Case B: use default pricegroup of customer
 
2216           $pkr->{selected}  = ' selected'; # unless $form->{selected};
 
2217           # no customer pricesgroup set
 
2218           if ($pkr->{price_ufmt} == $pkr->{default_sellprice}) {
 
2220             $pkr->{price} = $form->{"sellprice_$i"};
 
2224 # this sub should not set anything and only return. --sschoeling, 20090506
 
2225 # is this correct? put in again... -- grichardson 20110119
 
2226             $form->{"sellprice_$i"} = $pkr->{price};
 
2229         } elsif ($pkr->{price_ufmt} == $pkr->{default_sellprice} and $pkr->{default_sellprice} != 0) {
 
2230           $pkr->{price}    = $form->{"sellprice_$i"};
 
2231           $pkr->{selected} = ' selected';
 
2235       # existing article: pricegroup or price changed
 
2236       if ($selectedpricegroup_id or $selectedpricegroup_id == 0) {
 
2237         if ($selectedpricegroup_id ne $pricegroup_old) {
 
2238           # pricegroup has changed
 
2239           if ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
 
2240             $pkr->{selected}  = ' selected';
 
2242         } elsif ( ($form->parse_amount($myconfig, $price_new)
 
2243                  != $form->parse_amount($myconfig, $form->{"sellprice_$i"}))
 
2244                   and ($price_new ne 0) and defined $price_new) {
 
2245           # sellprice has changed
 
2246           # when loading existing invoices $price_new is NULL
 
2247           if ($pkr->{pricegroup_id} == 0) {
 
2248             $pkr->{price}     = $form->{"sellprice_$i"};
 
2249             $pkr->{selected}  = ' selected';
 
2251         } elsif ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
 
2252           # neither sellprice nor pricegroup changed
 
2253           $pkr->{selected}  = ' selected';
 
2254           if (    ($pkr->{pricegroup_id} == 0) and ($pkr->{price} == $form->{"sellprice_$i"})) {
 
2255             # $pkr->{price}                         = $form->{"sellprice_$i"};
 
2257             $pkr->{price} = $form->{"sellprice_$i"};
 
2261       push @{ $form->{PRICES}{$i} }, $pkr;
 
2264     $form->{"basefactor_$i"} *= $basefactor;
 
2271   $main::lxdebug->leave_sub();
 
2275   $main::lxdebug->enter_sub();
 
2277   my ($self, $myconfig, $form, $table) = @_;
 
2279   $main::lxdebug->leave_sub() and return 0 unless ($form->{id});
 
2281   # make sure there's no funny stuff in $table
 
2282   # ToDO: die when this happens and throw an error
 
2283   $main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);
 
2285   my $dbh = $form->get_standard_dbh;
 
2287   my $query = qq|SELECT storno FROM $table WHERE storno_id = ?|;
 
2288   my ($result) = selectrow_query($form, $dbh, $query, $form->{id});
 
2290   $main::lxdebug->leave_sub();
 
2296   $main::lxdebug->enter_sub();
 
2298   my ($self, $myconfig, $form, $table, $id) = @_;
 
2300   $main::lxdebug->leave_sub() and return 0 unless ($id);
 
2302   # make sure there's no funny stuff in $table
 
2303   # ToDO: die when this happens and throw an error
 
2304   $main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);
 
2306   my $dbh = $form->get_standard_dbh;
 
2308   my $query = qq|SELECT storno FROM $table WHERE id = ?|;
 
2309   my ($result) = selectrow_query($form, $dbh, $query, $id);
 
2311   $main::lxdebug->leave_sub();
 
2316 sub get_standard_accno_current_assets {
 
2317   $main::lxdebug->enter_sub();
 
2319   my ($self, $myconfig, $form) = @_;
 
2321   my $dbh = $form->get_standard_dbh;
 
2323   my $query = qq| SELECT accno FROM chart WHERE id = (SELECT ar_paid_accno_id FROM defaults)|;
 
2324   my ($result) = selectrow_query($form, $dbh, $query);
 
2326   $main::lxdebug->leave_sub();