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;
 
  58   $main::lxdebug->enter_sub();
 
  60   my ($self, $myconfig, $form, $locale) = @_;
 
  62   $form->{duedate} ||= $form->{invdate};
 
  65   my $dbh = $form->get_standard_dbh;
 
  68   my $query = qq|SELECT date | . conv_dateq($form->{duedate}) . qq| - date | . conv_dateq($form->{invdate}) . qq| AS terms|;
 
  69   ($form->{terms}) = selectrow_query($form, $dbh, $query);
 
  71   my (@project_ids, %projectnumbers, %projectdescriptions);
 
  72   $form->{TEMPLATE_ARRAYS} = {};
 
  74   push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});
 
  76   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
 
  79   foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
 
  80     $price_factors{$pfac->{id}}  = $pfac;
 
  82     $pfac->{formatted_factor}    = $form->format_amount($myconfig, $pfac->{factor});
 
  85   # sort items by partsgroup
 
  86   for my $i (1 .. $form->{rowcount}) {
 
  88 #    if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
 
  89 #      $partsgroup = $form->{"partsgroup_$i"};
 
  91 #    push @partsgroup, [$i, $partsgroup];
 
  92     push(@project_ids, $form->{"project_id_$i"}) if ($form->{"project_id_$i"});
 
  96     $query = "SELECT id, projectnumber, description FROM project WHERE id IN (" .
 
  97       join(", ", map({ "?" } @project_ids)) . ")";
 
  98     $sth = $dbh->prepare($query);
 
  99     $sth->execute(@project_ids) ||
 
 100       $form->dberror($query . " (" . join(", ", @project_ids) . ")");
 
 101     while (my $ref = $sth->fetchrow_hashref()) {
 
 102       $projectnumbers{$ref->{id}} = $ref->{projectnumber};
 
 103       $projectdescriptions{$ref->{id}} = $ref->{description};
 
 108   $form->{"globalprojectnumber"} =
 
 109     $projectnumbers{$form->{"globalproject_id"}};
 
 110   $form->{"globalprojectdescription"} =
 
 111     $projectdescriptions{$form->{"globalproject_id"}};
 
 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');
 
 151     qw(runningnumber number description longdescription qty ship unit bin
 
 152        deliverydate_oe ordnumber_oe transdate_oe validuntil
 
 153        partnotes serialnumber reqdate sellprice listprice netprice
 
 154        discount p_discount discount_sub nodiscount_sub
 
 155        linetotal  nodiscount_linetotal tax_rate projectnumber projectdescription
 
 156        price_factor price_factor_name partsgroup weight lineweight);
 
 158   push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };
 
 160   my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);
 
 162   my @payment_arrays = qw(payment paymentaccount paymentdate paymentsource paymentmemo);
 
 164   map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays, @payment_arrays);
 
 167   foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
 
 170     if ($item->[1] ne $sameitem) {
 
 171       push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, qq|$item->[1]|);
 
 172       $sameitem = $item->[1];
 
 174       map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
 177     $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
 
 179     if ($form->{"id_$i"} != 0) {
 
 181       # add number, description and qty to $form->{number},
 
 182       if ($form->{"subtotal_$i"} && !$subtotal_header) {
 
 183         $subtotal_header = $i;
 
 184         $position = int($position);
 
 187       } elsif ($subtotal_header) {
 
 189         $position = int($position);
 
 190         $position = $position.".".$subposition;
 
 192         $position = int($position);
 
 196       my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || { 'factor' => 1 };
 
 198       push @{ $form->{TEMPLATE_ARRAYS}->{runningnumber} },     $position;
 
 199       push @{ $form->{TEMPLATE_ARRAYS}->{number} },            $form->{"partnumber_$i"};
 
 200       push @{ $form->{TEMPLATE_ARRAYS}->{serialnumber} },      $form->{"serialnumber_$i"};
 
 201       push @{ $form->{TEMPLATE_ARRAYS}->{bin} },               $form->{"bin_$i"};
 
 202       push @{ $form->{TEMPLATE_ARRAYS}->{partnotes} },         $form->{"partnotes_$i"};
 
 203       push @{ $form->{TEMPLATE_ARRAYS}->{description} },       $form->{"description_$i"};
 
 204       push @{ $form->{TEMPLATE_ARRAYS}->{longdescription} },   $form->{"longdescription_$i"};
 
 205       push @{ $form->{TEMPLATE_ARRAYS}->{qty} },               $form->format_amount($myconfig, $form->{"qty_$i"});
 
 206       push @{ $form->{TEMPLATE_ARRAYS}->{qty_nofmt} },         $form->{"qty_$i"};
 
 207       push @{ $form->{TEMPLATE_ARRAYS}->{unit} },              $form->{"unit_$i"};
 
 208       push @{ $form->{TEMPLATE_ARRAYS}->{deliverydate_oe} },   $form->{"reqdate_$i"};
 
 209       push @{ $form->{TEMPLATE_ARRAYS}->{sellprice} },         $form->{"sellprice_$i"};
 
 210       push @{ $form->{TEMPLATE_ARRAYS}->{sellprice_nofmt} },   $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 211       push @{ $form->{TEMPLATE_ARRAYS}->{ordnumber_oe} },      $form->{"ordnumber_$i"};
 
 212       push @{ $form->{TEMPLATE_ARRAYS}->{transdate_oe} },      $form->{"transdate_$i"};
 
 213       push @{ $form->{TEMPLATE_ARRAYS}->{invnumber} },         $form->{"invnumber"};
 
 214       push @{ $form->{TEMPLATE_ARRAYS}->{invdate} },           $form->{"invdate"};
 
 215       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor} },      $price_factor->{formatted_factor};
 
 216       push @{ $form->{TEMPLATE_ARRAYS}->{price_factor_name} }, $price_factor->{description};
 
 217       push @{ $form->{TEMPLATE_ARRAYS}->{partsgroup} },        $form->{"partsgroup_$i"};
 
 218       push @{ $form->{TEMPLATE_ARRAYS}->{reqdate} },           $form->{"reqdate_$i"};
 
 219       push(@{ $form->{TEMPLATE_ARRAYS}->{listprice} },         $form->{"listprice_$i"});
 
 221       my $sellprice     = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 222       my ($dec)         = ($sellprice =~ /\.(\d+)/);
 
 223       my $decimalplaces = max 2, length($dec);
 
 225       my $parsed_discount            = $form->parse_amount($myconfig, $form->{"discount_$i"});
 
 227       my $linetotal_exact            = $form->{"qty_$i"} * $sellprice * (100 - $parsed_discount) / 100 / $price_factor->{factor};
 
 228       my $linetotal                  = $form->round_amount($linetotal_exact, 2);
 
 230       my $nodiscount_exact_linetotal = $form->{"qty_$i"} * $sellprice                                  / $price_factor->{factor};
 
 231       my $nodiscount_linetotal       = $form->round_amount($nodiscount_exact_linetotal,2);
 
 233       my $discount                   = $nodiscount_linetotal - $linetotal; # is always rounded because $nodiscount_linetotal and $linetotal are rounded
 
 235       my $discount_round_error       = $discount + ($linetotal_exact - $nodiscount_exact_linetotal); # not used
 
 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) : '';
 
 240       push @{ $form->{TEMPLATE_ARRAYS}->{netprice_nofmt} }, ($form->{"netprice_$i"} != 0) ? $form->{"netprice_$i"} : '';
 
 242       $linetotal = ($linetotal != 0) ? $linetotal : '';
 
 244       push @{ $form->{TEMPLATE_ARRAYS}->{discount} },       ($discount != 0) ? $form->format_amount($myconfig, $discount * -1, 2) : '';
 
 245       push @{ $form->{TEMPLATE_ARRAYS}->{discount_nofmt} }, ($discount != 0) ? $discount * -1 : '';
 
 246       push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} },     $form->{"discount_$i"};
 
 248       $form->{total}            += $linetotal;
 
 249       $form->{nodiscount_total} += $nodiscount_linetotal;
 
 250       $form->{discount_total}   += $discount;
 
 252       if ($subtotal_header) {
 
 253         $discount_subtotal   += $linetotal;
 
 254         $nodiscount_subtotal += $nodiscount_linetotal;
 
 257       if ($form->{"subtotal_$i"} && $subtotal_header && ($subtotal_header != $i)) {
 
 258         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} },         $form->format_amount($myconfig, $discount_subtotal,   2);
 
 259         push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub_nofmt} },   $discount_subtotal;
 
 260         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} },       $form->format_amount($myconfig, $nodiscount_subtotal, 2);
 
 261         push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub_nofmt} }, $nodiscount_subtotal;
 
 263         $discount_subtotal   = 0;
 
 264         $nodiscount_subtotal = 0;
 
 265         $subtotal_header     = 0;
 
 268         push @{ $form->{TEMPLATE_ARRAYS}->{$_} }, "" for qw(discount_sub nodiscount_sub discount_sub_nofmt nodiscount_sub_nofmt);
 
 271       if (!$form->{"discount_$i"}) {
 
 272         $nodiscount += $linetotal;
 
 275       push @{ $form->{TEMPLATE_ARRAYS}->{linetotal} },                  $form->format_amount($myconfig, $linetotal, 2);
 
 276       push @{ $form->{TEMPLATE_ARRAYS}->{linetotal_nofmt} },            $linetotal_exact;
 
 277       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} },       $form->format_amount($myconfig, $nodiscount_linetotal, 2);
 
 278       push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal_nofmt} }, $nodiscount_linetotal;
 
 280       push(@{ $form->{TEMPLATE_ARRAYS}->{projectnumber} },              $projectnumbers{$form->{"project_id_$i"}});
 
 281       push(@{ $form->{TEMPLATE_ARRAYS}->{projectdescription} },         $projectdescriptions{$form->{"project_id_$i"}});
 
 283       my $lineweight = $form->{"qty_$i"} * $form->{"weight_$i"};
 
 284       $totalweight += $lineweight;
 
 285       push @{ $form->{TEMPLATE_ARRAYS}->{weight} },            $form->format_amount($myconfig, $form->{"weight_$i"}, 3);
 
 286       push @{ $form->{TEMPLATE_ARRAYS}->{weight_nofmt} },      $form->{"weight_$i"};
 
 287       push @{ $form->{TEMPLATE_ARRAYS}->{lineweight} },        $form->format_amount($myconfig, $lineweight, 3);
 
 288       push @{ $form->{TEMPLATE_ARRAYS}->{lineweight_nofmt} },  $lineweight;
 
 290       @taxaccounts = split(/ /, $form->{"taxaccounts_$i"});
 
 294       map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;
 
 296       if ($form->{taxincluded}) {
 
 299         $taxamount = $linetotal * $taxrate / (1 + $taxrate);
 
 300         $taxbase = $linetotal - $taxamount;
 
 302         $taxamount = $linetotal * $taxrate;
 
 303         $taxbase   = $linetotal;
 
 306       if ($form->round_amount($taxrate, 7) == 0) {
 
 307         if ($form->{taxincluded}) {
 
 308           foreach my $accno (@taxaccounts) {
 
 309             $taxamount            = $form->round_amount($linetotal * $form->{"${accno}_rate"} / (1 + abs($form->{"${accno}_rate"})), 2);
 
 311             $taxaccounts{$accno} += $taxamount;
 
 312             $taxdiff             += $taxamount;
 
 314             $taxbase{$accno}     += $taxbase;
 
 316           $taxaccounts{ $taxaccounts[0] } += $taxdiff;
 
 318           foreach my $accno (@taxaccounts) {
 
 319             $taxaccounts{$accno} += $linetotal * $form->{"${accno}_rate"};
 
 320             $taxbase{$accno}     += $taxbase;
 
 324         foreach my $accno (@taxaccounts) {
 
 325           $taxaccounts{$accno} += $taxamount * $form->{"${accno}_rate"} / $taxrate;
 
 326           $taxbase{$accno}     += $taxbase;
 
 329       my $tax_rate = $taxrate * 100;
 
 330       push(@{ $form->{TEMPLATE_ARRAYS}->{tax_rate} }, qq|$tax_rate|);
 
 331       if ($form->{"assembly_$i"}) {
 
 334         # get parts and push them onto the stack
 
 336         if ($form->{groupitems}) {
 
 338             qq|ORDER BY pg.partsgroup, a.oid|;
 
 340           $sortorder = qq|ORDER BY a.oid|;
 
 344           qq|SELECT p.partnumber, p.description, p.unit, a.qty, pg.partsgroup
 
 346              JOIN parts p ON (a.parts_id = p.id)
 
 347              LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
 
 348              WHERE (a.bom = '1') AND (a.id = ?) $sortorder|;
 
 349         $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id_$i"}));
 
 351         while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
 352           if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
 
 353             map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
 354             $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
 
 355             push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $sameitem);
 
 358           map { $form->{"a_$_"} = $ref->{$_} } qw(partnumber description);
 
 360           push(@{ $form->{TEMPLATE_ARRAYS}->{description} },
 
 361                $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}
 
 363                  . qq| -- $form->{"a_partnumber"}, $form->{"a_description"}|);
 
 364           map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
 
 370       push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} },
 
 371         CVar->format_to_template(CVar->parse($form->{"ic_cvar_$_->{name}_$i"}, $_), $_)
 
 372           for @{ $ic_cvar_configs };
 
 376   $form->{totalweight}       = $form->format_amount($myconfig, $totalweight, 3);
 
 377   $form->{totalweight_nofmt} = $totalweight;
 
 378   my $defaults = AM->get_defaults();
 
 379   $form->{weightunit}        = $defaults->{weightunit};
 
 381   foreach my $item (sort keys %taxaccounts) {
 
 382     $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
 
 384     push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase} },        $form->format_amount($myconfig, $taxbase{$item}, 2));
 
 385     push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase_nofmt} },  $taxbase{$item});
 
 386     push(@{ $form->{TEMPLATE_ARRAYS}->{tax} },            $form->format_amount($myconfig, $taxamount,      2));
 
 387     push(@{ $form->{TEMPLATE_ARRAYS}->{tax_nofmt} },      $taxamount );
 
 388     push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate} },        $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
 
 389     push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate_nofmt} },  $form->{"${item}_rate"} * 100);
 
 390     push(@{ $form->{TEMPLATE_ARRAYS}->{taxnumber} },      $form->{"${item}_taxnumber"});
 
 392     my $tax_obj     = SL::DB::Manager::Tax->find_by(taxnumber => $form->{"${item}_taxnumber"});
 
 393     my $description = $tax_obj->translated_attribute('taxdescription',  $form->{language_id}, 0) if $tax_obj;
 
 394     push(@{ $form->{TEMPLATE_ARRAYS}->{taxdescription} }, $description . q{ } . 100 * $form->{"${item}_rate"} . q{%});
 
 397   for my $i (1 .. $form->{paidaccounts}) {
 
 398     if ($form->{"paid_$i"}) {
 
 399       my ($accno, $description) = split(/--/, $form->{"AR_paid_$i"});
 
 401       push(@{ $form->{TEMPLATE_ARRAYS}->{payment} },        $form->{"paid_$i"});
 
 402       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentaccount} }, $description);
 
 403       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentdate} },    $form->{"datepaid_$i"});
 
 404       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentsource} },  $form->{"source_$i"});
 
 405       push(@{ $form->{TEMPLATE_ARRAYS}->{paymentmemo} },    $form->{"memo_$i"});
 
 407       $form->{paid} += $form->parse_amount($myconfig, $form->{"paid_$i"});
 
 410   if($form->{taxincluded}) {
 
 411     $form->{subtotal}       = $form->format_amount($myconfig, $form->{total} - $tax, 2);
 
 412     $form->{subtotal_nofmt} = $form->{total} - $tax;
 
 415     $form->{subtotal}       = $form->format_amount($myconfig, $form->{total}, 2);
 
 416     $form->{subtotal_nofmt} = $form->{total};
 
 419   $form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
 
 420   $form->{discount_total}      = $form->format_amount($myconfig, $form->{discount_total}, 2);
 
 421   $form->{nodiscount}          = $form->format_amount($myconfig, $nodiscount, 2);
 
 422   $form->{yesdiscount}         = $form->format_amount($myconfig, $form->{nodiscount_total} - $nodiscount, 2);
 
 424   $form->{invtotal} = ($form->{taxincluded}) ? $form->{total} : $form->{total} + $tax;
 
 425   $form->{total}    = $form->format_amount($myconfig, $form->{invtotal} - $form->{paid}, 2);
 
 427   $form->{invtotal} = $form->format_amount($myconfig, $form->{invtotal}, 2);
 
 428   $form->{paid}     = $form->format_amount($myconfig, $form->{paid}, 2);
 
 430   $form->set_payment_options($myconfig, $form->{invdate});
 
 432   $form->{username} = $myconfig->{name};
 
 434   $main::lxdebug->leave_sub();
 
 437 sub project_description {
 
 438   $main::lxdebug->enter_sub();
 
 440   my ($self, $dbh, $id) = @_;
 
 441   my $form = \%main::form;
 
 443   my $query = qq|SELECT description FROM project WHERE id = ?|;
 
 444   my ($description) = selectrow_query($form, $dbh, $query, conv_i($id));
 
 446   $main::lxdebug->leave_sub();
 
 451 sub customer_details {
 
 452   $main::lxdebug->enter_sub();
 
 454   my ($self, $myconfig, $form, @wanted_vars) = @_;
 
 456   # connect to database
 
 457   my $dbh = $form->get_standard_dbh;
 
 459   my $language_id = $form->{language_id};
 
 461   # get contact id, set it if nessessary
 
 464   my @values =  (conv_i($form->{customer_id}));
 
 467   if ($form->{cp_id}) {
 
 468     $where = qq| AND (cp.cp_id = ?) |;
 
 469     push(@values, conv_i($form->{cp_id}));
 
 472   # get rest for the customer
 
 474     qq|SELECT ct.*, cp.*, ct.notes as customernotes,
 
 475          ct.phone AS customerphone, ct.fax AS customerfax, ct.email AS customeremail,
 
 478        LEFT JOIN contacts cp on ct.id = cp.cp_cv_id
 
 479        LEFT JOIN currencies cu ON (ct.currency_id = cu.id)
 
 480        WHERE (ct.id = ?) $where
 
 483   my $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
 
 485   # remove id and taxincluded before copy back
 
 486   delete @$ref{qw(id taxincluded)};
 
 488   @wanted_vars = grep({ $_ } @wanted_vars);
 
 489   if (scalar(@wanted_vars) > 0) {
 
 491     map({ $h_wanted_vars{$_} = 1; } @wanted_vars);
 
 492     map({ delete($ref->{$_}) unless ($h_wanted_vars{$_}); } keys(%{$ref}));
 
 495   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 497   if ($form->{delivery_customer_id}) {
 
 499       qq|SELECT *, notes as customernotes
 
 503     $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{delivery_customer_id}));
 
 505     map { $form->{"dc_$_"} = $ref->{$_} } keys %$ref;
 
 508   if ($form->{delivery_vendor_id}) {
 
 510       qq|SELECT *, notes as customernotes
 
 514     $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{delivery_vendor_id}));
 
 516     map { $form->{"dv_$_"} = $ref->{$_} } keys %$ref;
 
 519   my $custom_variables = CVar->get_custom_variables('dbh'      => $dbh,
 
 521                                                     'trans_id' => $form->{customer_id});
 
 522   map { $form->{"vc_cvar_$_->{name}"} = $_->{value} } @{ $custom_variables };
 
 524   $form->{cp_greeting} = GenericTranslations->get('dbh'              => $dbh,
 
 525                                                   'translation_type' => 'greetings::' . ($form->{cp_gender} eq 'f' ? 'female' : 'male'),
 
 526                                                   'language_id'      => $language_id,
 
 527                                                   'allow_fallback'   => 1);
 
 530   $main::lxdebug->leave_sub();
 
 534   $main::lxdebug->enter_sub();
 
 536   my ($self, $myconfig, $form, $provided_dbh, $payments_only) = @_;
 
 538   # connect to database, turn off autocommit
 
 539   my $dbh = $provided_dbh ? $provided_dbh : $form->get_standard_dbh;
 
 541   my ($query, $sth, $null, $project_id, @values);
 
 542   my $exchangerate = 0;
 
 544   my $ic_cvar_configs = CVar->get_configs(module => 'IC',
 
 547   if (!$form->{employee_id}) {
 
 548     $form->get_employee($dbh);
 
 551   $form->{defaultcurrency} = $form->get_default_currency($myconfig);
 
 552   my $defaultcurrency = $form->{defaultcurrency};
 
 554   # Seit neuestem wird die department_id schon übergeben UND $form->department nicht mehr
 
 555   # korrekt zusammengebaut. Sehr wahrscheinlich beim Umstieg auf T8 kaputt gegangen
 
 556   # Ich lass den Code von 2005 erstmal noch stehen ;-) jb 03-2011
 
 557   if (!$form->{department_id}){
 
 558     ($null, $form->{department_id}) = split(/--/, $form->{department});
 
 561   my $all_units = AM->retrieve_units($myconfig, $form);
 
 563   if (!$payments_only) {
 
 565       &reverse_invoice($dbh, $form);
 
 568       my $trans_number   = SL::TransNumber->new(type => $form->{type}, dbh => $dbh, number => $form->{invnumber}, save => 1);
 
 569       $form->{invnumber} = $trans_number->create_unique unless $trans_number->is_unique;
 
 571       $query = qq|SELECT nextval('glid')|;
 
 572       ($form->{"id"}) = selectrow_query($form, $dbh, $query);
 
 574       $query = qq|INSERT INTO ar (id, invnumber, currency_id) VALUES (?, ?, (SELECT id FROM currencies WHERE name=?))|;
 
 575       do_query($form, $dbh, $query, $form->{"id"}, $form->{"id"}, $form->{currency});
 
 577       if (!$form->{invnumber}) {
 
 579           $form->update_defaults($myconfig, $form->{type} eq "credit_note" ?
 
 580                                  "cnnumber" : "invnumber", $dbh);
 
 585   my ($netamount, $invoicediff) = (0, 0);
 
 586   my ($amount, $linetotal, $lastincomeaccno);
 
 588   if ($form->{currency} eq $defaultcurrency) {
 
 589     $form->{exchangerate} = 1;
 
 591     $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{invdate}, 'buy');
 
 594   $form->{exchangerate} =
 
 597     : $form->parse_amount($myconfig, $form->{exchangerate});
 
 599   $form->{expense_inventory} = "";
 
 603   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
 
 604   my %price_factors = map { $_->{id} => $_->{factor} } @{ $form->{ALL_PRICE_FACTORS} };
 
 607   $form->{amount}      = {};
 
 608   $form->{amount_cogs} = {};
 
 610   foreach my $i (1 .. $form->{rowcount}) {
 
 611     if ($form->{type} eq "credit_note") {
 
 612       $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}) * -1;
 
 613       $form->{shipped} = 1;
 
 615       $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
 
 620     $form->{"marge_percent_$i"} = $form->parse_amount($myconfig, $form->{"marge_percent_$i"}) * 1;
 
 621     $form->{"marge_absolut_$i"} = $form->parse_amount($myconfig, $form->{"marge_absolut_$i"}) * 1;
 
 622     $form->{"lastcost_$i"} = $form->parse_amount($myconfig, $form->{"lastcost_$i"}) * 1;
 
 624     if ($form->{storno}) {
 
 625       $form->{"qty_$i"} *= -1;
 
 628     if ($form->{"id_$i"}) {
 
 631       if (defined($baseunits{$form->{"id_$i"}})) {
 
 632         $item_unit = $baseunits{$form->{"id_$i"}};
 
 635         $query = qq|SELECT unit FROM parts WHERE id = ?|;
 
 636         ($item_unit) = selectrow_query($form, $dbh, $query, conv_i($form->{"id_$i"}));
 
 637         $baseunits{$form->{"id_$i"}} = $item_unit;
 
 640       if (defined($all_units->{$item_unit}->{factor})
 
 641           && ($all_units->{$item_unit}->{factor} ne '')
 
 642           && ($all_units->{$item_unit}->{factor} != 0)) {
 
 643         $basefactor = $all_units->{$form->{"unit_$i"}}->{factor} / $all_units->{$item_unit}->{factor};
 
 647       $baseqty = $form->{"qty_$i"} * $basefactor;
 
 649       my ($allocated, $taxrate) = (0, 0);
 
 653       map { $taxrate += $form->{"${_}_rate"} } split(/ /, $form->{"taxaccounts_$i"});
 
 655       # keep entered selling price
 
 657         $form->parse_amount($myconfig, $form->{"sellprice_$i"});
 
 659       my ($dec) = ($fxsellprice =~ /\.(\d+)/);
 
 661       my $decimalplaces = ($dec > 2) ? $dec : 2;
 
 663       # undo discount formatting
 
 664       $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
 
 667       $form->{"sellprice_$i"} = $fxsellprice * (1 - $form->{"discount_$i"});
 
 669       # round linetotal to 2 decimal places
 
 670       $price_factor = $price_factors{ $form->{"price_factor_id_$i"} } || 1;
 
 671       $linetotal    = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2);
 
 673       if ($form->{taxincluded}) {
 
 674         $taxamount = $linetotal * ($taxrate / (1 + $taxrate));
 
 675         $form->{"sellprice_$i"} =
 
 676           $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
 
 678         $taxamount = $linetotal * $taxrate;
 
 681       $netamount += $linetotal;
 
 683       if ($taxamount != 0) {
 
 685           $form->{amount}{ $form->{id} }{$_} +=
 
 686             $taxamount * $form->{"${_}_rate"} / $taxrate
 
 687         } split(/ /, $form->{"taxaccounts_$i"});
 
 690       # add amount to income, $form->{amount}{trans_id}{accno}
 
 691       $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate} / $price_factor;
 
 693       $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2) * $form->{exchangerate};
 
 694       $linetotal = $form->round_amount($linetotal, 2);
 
 696       # this is the difference from the inventory
 
 697       $invoicediff += ($amount - $linetotal);
 
 699       $form->{amount}{ $form->{id} }{ $form->{"income_accno_$i"} } +=
 
 702       $lastincomeaccno = $form->{"income_accno_$i"};
 
 704       # adjust and round sellprice
 
 705       $form->{"sellprice_$i"} =
 
 706         $form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate},
 
 709       next if $payments_only;
 
 711       if ($form->{"inventory_accno_$i"} || $form->{"assembly_$i"}) {
 
 713         if ($form->{"assembly_$i"}) {
 
 714           # record assembly item as allocated
 
 715           &process_assembly($dbh, $myconfig, $form, $form->{"id_$i"}, $baseqty);
 
 718           $allocated = &cogs($dbh, $myconfig, $form, $form->{"id_$i"}, $baseqty, $basefactor, $i);
 
 722       # Get pricegroup_id and save it. Unfortunately the interface
 
 723       # also uses ID "0" for signalling that none is selected, but "0"
 
 724       # must not be stored in the database. Therefore we cannot simply
 
 726       ($null, my $pricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
 
 728       $pricegroup_id  = undef if !$pricegroup_id;
 
 730       my ($invoice_id) = selectfirst_array_query($form, $dbh, qq|SELECT nextval('invoiceid')|);
 
 732       # save detail record in invoice table
 
 734         qq|INSERT INTO invoice (id, trans_id, parts_id, description, longdescription, qty,
 
 735                                 sellprice, fxsellprice, discount, allocated, assemblyitem,
 
 736                                 unit, deliverydate, project_id, serialnumber, pricegroup_id,
 
 737                                 ordnumber, transdate, cusordnumber, base_qty, subtotal,
 
 738                                 marge_percent, marge_total, lastcost,
 
 739                                 price_factor_id, price_factor, marge_price_factor)
 
 740            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
 
 741                    (SELECT factor FROM price_factors WHERE id = ?), ?)|;
 
 743       @values = ($invoice_id, conv_i($form->{id}), conv_i($form->{"id_$i"}),
 
 744                  $form->{"description_$i"}, $form->{"longdescription_$i"}, $form->{"qty_$i"},
 
 745                  $form->{"sellprice_$i"}, $fxsellprice,
 
 746                  $form->{"discount_$i"}, $allocated, 'f',
 
 747                  $form->{"unit_$i"}, conv_date($form->{"reqdate_$i"}), conv_i($form->{"project_id_$i"}),
 
 748                  $form->{"serialnumber_$i"}, $pricegroup_id,
 
 749                  $form->{"ordnumber_$i"}, conv_date($form->{"transdate_$i"}),
 
 750                  $form->{"cusordnumber_$i"}, $baseqty, $form->{"subtotal_$i"} ? 't' : 'f',
 
 751                  $form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
 
 752                  $form->{"lastcost_$i"},
 
 753                  conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
 
 754                  conv_i($form->{"marge_price_factor_$i"}));
 
 755       do_query($form, $dbh, $query, @values);
 
 757       CVar->save_custom_variables(module       => 'IC',
 
 758                                   sub_module   => 'invoice',
 
 759                                   trans_id     => $invoice_id,
 
 760                                   configs      => $ic_cvar_configs,
 
 762                                   name_prefix  => 'ic_',
 
 763                                   name_postfix => "_$i",
 
 768   # total payments, don't move we need it here
 
 769   for my $i (1 .. $form->{paidaccounts}) {
 
 770     if ($form->{type} eq "credit_note") {
 
 771       $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"}) * -1;
 
 773       $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
 
 775     $form->{paid} += $form->{"paid_$i"};
 
 776     $form->{datepaid} = $form->{"datepaid_$i"} if ($form->{"datepaid_$i"});
 
 779   my ($tax, $diff) = (0, 0);
 
 781   $netamount = $form->round_amount($netamount, 2);
 
 783   # figure out rounding errors for total amount vs netamount + taxes
 
 784   if ($form->{taxincluded}) {
 
 786     $amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
 
 787     $diff += $amount - $netamount * $form->{exchangerate};
 
 788     $netamount = $amount;
 
 790     foreach my $item (split(/ /, $form->{taxaccounts})) {
 
 791       $amount = $form->{amount}{ $form->{id} }{$item} * $form->{exchangerate};
 
 792       $form->{amount}{ $form->{id} }{$item} = $form->round_amount($amount, 2);
 
 793       $tax += $form->{amount}{ $form->{id} }{$item};
 
 794       $netamount -= $form->{amount}{ $form->{id} }{$item};
 
 797     $invoicediff += $diff;
 
 798     ######## this only applies to tax included
 
 799     if ($lastincomeaccno) {
 
 800       $form->{amount}{ $form->{id} }{$lastincomeaccno} += $invoicediff;
 
 804     $amount    = $form->round_amount($netamount * $form->{exchangerate}, 2);
 
 805     $diff      = $amount - $netamount * $form->{exchangerate};
 
 806     $netamount = $amount;
 
 807     foreach my $item (split(/ /, $form->{taxaccounts})) {
 
 808       $form->{amount}{ $form->{id} }{$item} =
 
 809         $form->round_amount($form->{amount}{ $form->{id} }{$item}, 2);
 
 812                  $form->{amount}{ $form->{id} }{$item} * $form->{exchangerate},
 
 815         $amount - $form->{amount}{ $form->{id} }{$item} *
 
 816         $form->{exchangerate};
 
 817       $form->{amount}{ $form->{id} }{$item} = $form->round_amount($amount, 2);
 
 818       $tax += $form->{amount}{ $form->{id} }{$item};
 
 822   $form->{amount}{ $form->{id} }{ $form->{AR} } = $netamount + $tax;
 
 824     $form->round_amount($form->{paid} * $form->{exchangerate} + $diff, 2);
 
 827   $form->{amount}{ $form->{id} }{ $form->{AR} } *= -1;
 
 829   # update exchangerate
 
 830   if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
 
 831     $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate},
 
 832                                $form->{exchangerate}, 0);
 
 835   $project_id = conv_i($form->{"globalproject_id"});
 
 836   # entsprechend auch beim Bestimmen des Steuerschlüssels in Taxkey.pm berücksichtigen
 
 837   my $taxdate = $form->{deliverydate} ? $form->{deliverydate} : $form->{invdate};
 
 839   foreach my $trans_id (keys %{ $form->{amount_cogs} }) {
 
 840     foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
 
 841       next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
 
 843       $form->{amount_cogs}{$trans_id}{$accno} = $form->round_amount($form->{amount_cogs}{$trans_id}{$accno}, 2);
 
 845       if (!$payments_only && ($form->{amount_cogs}{$trans_id}{$accno} != 0)) {
 
 847           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
 
 848                VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, (SELECT id FROM tax WHERE taxkey=0), 0, ?, (SELECT link FROM chart WHERE accno = ?))|;
 
 849         @values = (conv_i($trans_id), $accno, $form->{amount_cogs}{$trans_id}{$accno}, conv_date($form->{invdate}), conv_i($project_id), $accno);
 
 850         do_query($form, $dbh, $query, @values);
 
 851         $form->{amount_cogs}{$trans_id}{$accno} = 0;
 
 855     foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
 
 856       $form->{amount_cogs}{$trans_id}{$accno} = $form->round_amount($form->{amount_cogs}{$trans_id}{$accno}, 2);
 
 858       if (!$payments_only && ($form->{amount_cogs}{$trans_id}{$accno} != 0)) {
 
 860           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
 
 861                VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, (SELECT id FROM tax WHERE taxkey=0), 0, ?, (SELECT link FROM chart WHERE accno = ?))|;
 
 862         @values = (conv_i($trans_id), $accno, $form->{amount_cogs}{$trans_id}{$accno}, conv_date($form->{invdate}), conv_i($project_id), $accno);
 
 863         do_query($form, $dbh, $query, @values);
 
 868   foreach my $trans_id (keys %{ $form->{amount} }) {
 
 869     foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
 
 870       next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
 
 872       $form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2);
 
 874       if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
 
 876           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
 
 877              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
 
 880                       WHERE chart_id= (SELECT id
 
 884                       ORDER BY startdate DESC LIMIT 1),
 
 887                       WHERE chart_id= (SELECT id
 
 891                       ORDER BY startdate DESC LIMIT 1),
 
 893                      (SELECT link FROM chart WHERE accno = ?))|;
 
 894         @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);
 
 895         do_query($form, $dbh, $query, @values);
 
 896         $form->{amount}{$trans_id}{$accno} = 0;
 
 900     foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
 
 901       $form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2);
 
 903       if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
 
 905           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
 
 906              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
 
 909                       WHERE chart_id= (SELECT id
 
 913                       ORDER BY startdate DESC LIMIT 1),
 
 916                       WHERE chart_id= (SELECT id
 
 920                       ORDER BY startdate DESC LIMIT 1),
 
 922                      (SELECT link FROM chart WHERE accno = ?))|;
 
 923         @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);
 
 924         do_query($form, $dbh, $query, @values);
 
 929   # deduct payment differences from diff
 
 930   for my $i (1 .. $form->{paidaccounts}) {
 
 931     if ($form->{"paid_$i"} != 0) {
 
 933         $form->round_amount($form->{"paid_$i"} * $form->{exchangerate}, 2);
 
 934       $diff -= $amount - $form->{"paid_$i"} * $form->{exchangerate};
 
 938   # record payments and offsetting AR
 
 939   if (!$form->{storno}) {
 
 940     for my $i (1 .. $form->{paidaccounts}) {
 
 942       if ($form->{"acc_trans_id_$i"}
 
 944           && (SL::DB::Default->get->payments_changeable == 0)) {
 
 948       next if ($form->{"paid_$i"} == 0);
 
 950       my ($accno) = split(/--/, $form->{"AR_paid_$i"});
 
 951       $form->{"datepaid_$i"} = $form->{invdate}
 
 952       unless ($form->{"datepaid_$i"});
 
 953       $form->{datepaid} = $form->{"datepaid_$i"};
 
 957       if ($form->{currency} eq $defaultcurrency) {
 
 958         $form->{"exchangerate_$i"} = 1;
 
 960         $exchangerate              = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy');
 
 961         $form->{"exchangerate_$i"} = $exchangerate || $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
 
 965       $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $diff, 2);
 
 967       if ($form->{amount}{ $form->{id} }{ $form->{AR} } != 0) {
 
 969         qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
 
 970            VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
 
 973                     WHERE chart_id= (SELECT id
 
 977                     ORDER BY startdate DESC LIMIT 1),
 
 980                     WHERE chart_id= (SELECT id
 
 984                     ORDER BY startdate DESC LIMIT 1),
 
 986                    (SELECT link FROM chart WHERE accno = ?))|;
 
 987         @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});
 
 988         do_query($form, $dbh, $query, @values);
 
 992       $form->{"paid_$i"} *= -1;
 
 993       my $gldate = (conv_date($form->{"gldate_$i"}))? conv_date($form->{"gldate_$i"}) : conv_date($form->current_date($myconfig));
 
 996       qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, gldate, source, memo, tax_id, taxkey, project_id, chart_link)
 
 997          VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, ?, ?, ?,
 
1000                   WHERE chart_id= (SELECT id
 
1004                   ORDER BY startdate DESC LIMIT 1),
 
1007                   WHERE chart_id= (SELECT id
 
1011                   ORDER BY startdate DESC LIMIT 1),
 
1013                  (SELECT link FROM chart WHERE accno = ?))|;
 
1014       @values = (conv_i($form->{"id"}), $accno, $form->{"paid_$i"}, $form->{"datepaid_$i"},
 
1015                  $gldate, $form->{"source_$i"}, $form->{"memo_$i"}, $accno, conv_date($taxdate), $accno, conv_date($taxdate), $project_id, $accno);
 
1016       do_query($form, $dbh, $query, @values);
 
1018       # exchangerate difference
 
1019       $form->{fx}{$accno}{ $form->{"datepaid_$i"} } +=
 
1020         $form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $diff;
 
1024         $form->{"paid_$i"} * $form->{exchangerate} - $form->{"paid_$i"} *
 
1025         $form->{"exchangerate_$i"};
 
1027         $form->{fx}{ $form->{fxgain_accno} }{ $form->{"datepaid_$i"} } += $amount;
 
1029         $form->{fx}{ $form->{fxloss_accno} }{ $form->{"datepaid_$i"} } += $amount;
 
1034       # update exchange rate
 
1035       if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
 
1036         $form->update_exchangerate($dbh, $form->{currency},
 
1037                                    $form->{"datepaid_$i"},
 
1038                                    $form->{"exchangerate_$i"}, 0);
 
1042   } else {                      # if (!$form->{storno})
 
1043     $form->{marge_total} *= -1;
 
1046   IO->set_datepaid(table => 'ar', id => $form->{id}, dbh => $dbh);
 
1048   # record exchange rate differences and gains/losses
 
1049   foreach my $accno (keys %{ $form->{fx} }) {
 
1050     foreach my $transdate (keys %{ $form->{fx}{$accno} }) {
 
1051       $form->{fx}{$accno}{$transdate} = $form->round_amount($form->{fx}{$accno}{$transdate}, 2);
 
1052       if ( $form->{fx}{$accno}{$transdate} != 0 ) {
 
1055           qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, cleared, fx_transaction, tax_id, taxkey, project_id, chart_link)
 
1056              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, '0', '1',
 
1059                   WHERE chart_id= (SELECT id
 
1063                   ORDER BY startdate DESC LIMIT 1),
 
1066                   WHERE chart_id= (SELECT id
 
1070                   ORDER BY startdate DESC LIMIT 1),
 
1072                  (SELECT link FROM chart WHERE accno = ?))|;
 
1073         @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);
 
1074         do_query($form, $dbh, $query, @values);
 
1079   if ($payments_only) {
 
1080     $query = qq|UPDATE ar SET paid = ? WHERE id = ?|;
 
1081     do_query($form, $dbh, $query,  $form->{paid}, conv_i($form->{id}));
 
1083     $dbh->commit if !$provided_dbh;
 
1085     $main::lxdebug->leave_sub();
 
1089   $amount = $netamount + $tax;
 
1092   #erweiterung fuer lieferscheinnummer (donumber) 12.02.09 jb
 
1094   $query = qq|UPDATE ar set
 
1095                 invnumber   = ?, ordnumber     = ?, quonumber     = ?, cusordnumber  = ?,
 
1096                 transdate   = ?, orddate       = ?, quodate       = ?, customer_id   = ?,
 
1097                 amount      = ?, netamount     = ?, paid          = ?,
 
1098                 duedate     = ?, deliverydate  = ?, invoice       = ?, shippingpoint = ?,
 
1099                 shipvia     = ?, terms         = ?, notes         = ?, intnotes      = ?,
 
1100                 currency_id = (SELECT id FROM currencies WHERE name = ?),
 
1101                 department_id = ?, payment_id    = ?, taxincluded   = ?,
 
1102                 type        = ?, language_id   = ?, taxzone_id    = ?, shipto_id     = ?,
 
1103                 employee_id = ?, salesman_id   = ?, storno_id     = ?, storno        = ?,
 
1104                 cp_id       = ?, marge_total   = ?, marge_percent = ?,
 
1105                 globalproject_id               = ?, delivery_customer_id             = ?,
 
1106                 transaction_description        = ?, delivery_vendor_id               = ?,
 
1107                 donumber    = ?, invnumber_for_credit_note = ?,        direct_debit  = ?
 
1109   @values = (          $form->{"invnumber"},           $form->{"ordnumber"},             $form->{"quonumber"},          $form->{"cusordnumber"},
 
1110              conv_date($form->{"invdate"}),  conv_date($form->{"orddate"}),    conv_date($form->{"quodate"}),    conv_i($form->{"customer_id"}),
 
1111                        $amount,                        $netamount,                       $form->{"paid"},
 
1112              conv_date($form->{"duedate"}),  conv_date($form->{"deliverydate"}),    '1',                                $form->{"shippingpoint"},
 
1113                        $form->{"shipvia"},      conv_i($form->{"terms"}),                $form->{"notes"},              $form->{"intnotes"},
 
1114                        $form->{"currency"},     conv_i($form->{"department_id"}), conv_i($form->{"payment_id"}),        $form->{"taxincluded"} ? 't' : 'f',
 
1115                        $form->{"type"},         conv_i($form->{"language_id"}),   conv_i($form->{"taxzone_id"}), conv_i($form->{"shipto_id"}),
 
1116                 conv_i($form->{"employee_id"}), conv_i($form->{"salesman_id"}),   conv_i($form->{storno_id}),           $form->{"storno"} ? 't' : 'f',
 
1117                 conv_i($form->{"cp_id"}),            1 * $form->{marge_total} ,      1 * $form->{marge_percent},
 
1118                 conv_i($form->{"globalproject_id"}),                              conv_i($form->{"delivery_customer_id"}),
 
1119                        $form->{transaction_description},                          conv_i($form->{"delivery_vendor_id"}),
 
1120                        $form->{"donumber"}, $form->{"invnumber_for_credit_note"},        $form->{direct_debit} ? 't' : 'f',
 
1121                 conv_i($form->{"id"}));
 
1122   do_query($form, $dbh, $query, @values);
 
1125   if ($form->{storno}) {
 
1128            paid = paid + amount,
 
1130            intnotes = ? || intnotes
 
1132     do_query($form, $dbh, $query, "Rechnung storniert am $form->{invdate} ", conv_i($form->{"storno_id"}));
 
1133     do_query($form, $dbh, qq|UPDATE ar SET paid = amount WHERE id = ?|, conv_i($form->{"id"}));
 
1137   $form->{name} = $form->{customer};
 
1138   $form->{name} =~ s/--\Q$form->{customer_id}\E//;
 
1140   if (!$form->{shipto_id}) {
 
1141     $form->add_shipto($dbh, $form->{id}, "AR");
 
1144   # save printed, emailed and queued
 
1145   $form->save_status($dbh);
 
1147   Common::webdav_folder($form);
 
1149   # Link this record to the records it was created from.
 
1150   RecordLinks->create_links('dbh'        => $dbh,
 
1152                             'from_table' => 'oe',
 
1153                             'from_ids'   => $form->{convert_from_oe_ids},
 
1155                             'to_id'      => $form->{id},
 
1157   delete $form->{convert_from_oe_ids};
 
1159   my @convert_from_do_ids = map { $_ * 1 } grep { $_ } split m/\s+/, $form->{convert_from_do_ids};
 
1161   if (scalar @convert_from_do_ids) {
 
1162     DO->close_orders('dbh' => $dbh,
 
1163                      'ids' => \@convert_from_do_ids);
 
1165     RecordLinks->create_links('dbh'        => $dbh,
 
1167                               'from_table' => 'delivery_orders',
 
1168                               'from_ids'   => \@convert_from_do_ids,
 
1170                               'to_id'      => $form->{id},
 
1173   delete $form->{convert_from_do_ids};
 
1175   ARAP->close_orders_if_billed('dbh'     => $dbh,
 
1176                                'arap_id' => $form->{id},
 
1179   # safety check datev export
 
1180   if ($::instance_conf->get_datev_check_on_sales_invoice) {
 
1181     my $transdate = $::form->{invdate} ? DateTime->from_lxoffice($::form->{invdate}) : undef;
 
1182     $transdate  ||= DateTime->today;
 
1184     my $datev = SL::DATEV->new(
 
1185       exporttype => DATEV_ET_BUCHUNGEN,
 
1186       format     => DATEV_FORMAT_KNE,
 
1190       trans_id   => $form->{id},
 
1195     if ($datev->errors) {
 
1197       die join "\n", $::locale->text('DATEV check returned errors:'), $datev->errors;
 
1202   $dbh->commit if !$provided_dbh;
 
1204   $main::lxdebug->leave_sub();
 
1209 sub _delete_payments {
 
1210   $main::lxdebug->enter_sub();
 
1212   my ($self, $form, $dbh) = @_;
 
1214   my @delete_acc_trans_ids;
 
1216   # Delete old payment entries from acc_trans.
 
1218     qq|SELECT acc_trans_id
 
1220        WHERE (trans_id = ?) AND fx_transaction
 
1224        SELECT at.acc_trans_id
 
1226        LEFT JOIN chart c ON (at.chart_id = c.id)
 
1227        WHERE (trans_id = ?) AND (c.link LIKE '%AR_paid%')|;
 
1228   push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}), conv_i($form->{id}));
 
1231     qq|SELECT at.acc_trans_id
 
1233        LEFT JOIN chart c ON (at.chart_id = c.id)
 
1234        WHERE (trans_id = ?)
 
1235          AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
 
1236        ORDER BY at.acc_trans_id
 
1238   push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}));
 
1240   if (@delete_acc_trans_ids) {
 
1241     $query = qq|DELETE FROM acc_trans WHERE acc_trans_id IN (| . join(", ", @delete_acc_trans_ids) . qq|)|;
 
1242     do_query($form, $dbh, $query);
 
1245   $main::lxdebug->leave_sub();
 
1249   $main::lxdebug->enter_sub();
 
1251   my ($self, $myconfig, $form, $locale) = @_;
 
1253   # connect to database, turn off autocommit
 
1254   my $dbh = $form->get_standard_dbh;
 
1256   my (%payments, $old_form, $row, $item, $query, %keep_vars);
 
1258   $old_form = save_form();
 
1260   # Delete all entries in acc_trans from prior payments.
 
1261   if (SL::DB::Default->get->payments_changeable != 0) {
 
1262     $self->_delete_payments($form, $dbh);
 
1265   # Save the new payments the user made before cleaning up $form.
 
1266   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 };
 
1268   # Clean up $form so that old content won't tamper the results.
 
1269   %keep_vars = map { $_, 1 } qw(login password id);
 
1270   map { delete $form->{$_} unless $keep_vars{$_} } keys %{ $form };
 
1272   # Retrieve the invoice from the database.
 
1273   $self->retrieve_invoice($myconfig, $form);
 
1275   # Set up the content of $form in the way that IS::post_invoice() expects.
 
1276   $form->{exchangerate} = $form->format_amount($myconfig, $form->{exchangerate});
 
1278   for $row (1 .. scalar @{ $form->{invoice_details} }) {
 
1279     $item = $form->{invoice_details}->[$row - 1];
 
1281     map { $item->{$_} = $form->format_amount($myconfig, $item->{$_}) } qw(qty sellprice discount);
 
1283     map { $form->{"${_}_${row}"} = $item->{$_} } keys %{ $item };
 
1286   $form->{rowcount} = scalar @{ $form->{invoice_details} };
 
1288   delete @{$form}{qw(invoice_details paidaccounts storno paid)};
 
1290   # Restore the payment options from the user input.
 
1291   map { $form->{$_} = $payments{$_} } keys %payments;
 
1293   # Get the AR accno (which is normally done by Form::create_links()).
 
1297        LEFT JOIN chart c ON (at.chart_id = c.id)
 
1298        WHERE (trans_id = ?)
 
1299          AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
 
1300        ORDER BY at.acc_trans_id
 
1303   ($form->{AR}) = selectfirst_array_query($form, $dbh, $query, conv_i($form->{id}));
 
1305   # Post the new payments.
 
1306   $self->post_invoice($myconfig, $form, $dbh, 1);
 
1308   restore_form($old_form);
 
1310   my $rc = $dbh->commit();
 
1312   $main::lxdebug->leave_sub();
 
1317 sub process_assembly {
 
1318   $main::lxdebug->enter_sub();
 
1320   my ($dbh, $myconfig, $form, $id, $totalqty) = @_;
 
1323     qq|SELECT a.parts_id, a.qty, p.assembly, p.partnumber, p.description, p.unit,
 
1324          p.inventory_accno_id, p.income_accno_id, p.expense_accno_id
 
1326        JOIN parts p ON (a.parts_id = p.id)
 
1328   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
 
1330   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1334     $ref->{inventory_accno_id} *= 1;
 
1335     $ref->{expense_accno_id}   *= 1;
 
1337     # multiply by number of assemblies
 
1338     $ref->{qty} *= $totalqty;
 
1340     if ($ref->{assembly}) {
 
1341       &process_assembly($dbh, $myconfig, $form, $ref->{parts_id}, $ref->{qty});
 
1344       if ($ref->{inventory_accno_id}) {
 
1345         $allocated = &cogs($dbh, $myconfig, $form, $ref->{parts_id}, $ref->{qty});
 
1349     # save detail record for individual assembly item in invoice table
 
1351       qq|INSERT INTO invoice (trans_id, description, parts_id, qty, sellprice, fxsellprice, allocated, assemblyitem, unit)
 
1352          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)|;
 
1353     my @values = (conv_i($form->{id}), $ref->{description}, conv_i($ref->{parts_id}), $ref->{qty}, 0, 0, $allocated, 't', $ref->{unit});
 
1354     do_query($form, $dbh, $query, @values);
 
1360   $main::lxdebug->leave_sub();
 
1364   $main::lxdebug->enter_sub();
 
1366   # adjust allocated in table invoice according to FIFO princicple
 
1367   # for a certain part with part_id $id
 
1369   my ($dbh, $myconfig, $form, $id, $totalqty, $basefactor, $row) = @_;
 
1373   $form->{taxzone_id} *=1;
 
1374   my $transdate  = $form->{invdate} ? $dbh->quote($form->{invdate}) : "current_date";
 
1375   my $taxzone_id = $form->{"taxzone_id"} * 1;
 
1377     qq|SELECT i.id, i.trans_id, i.base_qty, i.allocated, i.sellprice, i.price_factor,
 
1378          c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
 
1379          c2.accno AS    income_accno, c2.new_chart_id AS    income_new_chart, date($transdate) - c2.valid_from AS    income_valid,
 
1380          c3.accno AS   expense_accno, c3.new_chart_id AS   expense_new_chart, date($transdate) - c3.valid_from AS   expense_valid
 
1381        FROM invoice i, parts p
 
1382        LEFT JOIN chart c1 ON ((SELECT inventory_accno_id FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
 
1383        LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
 
1384        LEFT JOIN chart c3 ON ((select expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
 
1385        WHERE (i.parts_id = p.id)
 
1386          AND (i.parts_id = ?)
 
1387          AND ((i.base_qty + i.allocated) < 0)
 
1389   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
 
1394 # all invoice entries of an example part:
 
1396 # id | trans_id | base_qty | allocated | sellprice | inventory_accno | income_accno | expense_accno
 
1397 # ---+----------+----------+-----------+-----------+-----------------+--------------+---------------
 
1398 #  4 |        4 |       -5 |         5 |  20.00000 | 1140            | 4400         | 5400     bought 5 for 20
 
1399 #  5 |        5 |        4 |        -4 |  50.00000 | 1140            | 4400         | 5400     sold   4 for 50
 
1400 #  6 |        6 |        1 |        -1 |  50.00000 | 1140            | 4400         | 5400     sold   1 for 50
 
1401 #  7 |        7 |       -5 |         1 |  20.00000 | 1140            | 4400         | 5400     bought 5 for 20
 
1402 #  8 |        8 |        1 |        -1 |  50.00000 | 1140            | 4400         | 5400     sold   1 for 50
 
1404 # 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
 
1405 # and all parts have been allocated
 
1407 # so transaction 8 only sees transaction 7 with unallocated parts and adjusts allocated for that transaction, before allocated was 0
 
1408 #  7 |        7 |       -5 |         1 |  20.00000 | 1140            | 4400         | 5400     bought 5 for 20
 
1410 # in this example there are still 4 unsold articles
 
1413   # search all invoice entries for the part in question, adjusting "allocated"
 
1414   # until the total number of sold parts has been reached
 
1416   # ORDER BY trans_id ensures FIFO
 
1419   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1420     if (($qty = (($ref->{base_qty} * -1) - $ref->{allocated})) > $totalqty) {
 
1424     # update allocated in invoice
 
1425     $form->update_balance($dbh, "invoice", "allocated", qq|id = $ref->{id}|, $qty);
 
1427     # total expenses and inventory
 
1428     # sellprice is the cost of the item
 
1429     my $linetotal = $form->round_amount(($ref->{sellprice} * $qty) / ( ($ref->{price_factor} || 1) * ( $basefactor || 1 )), 2);
 
1431     if ( $::instance_conf->get_inventory_system eq 'perpetual' ) {
 
1432       # Bestandsmethode: when selling parts, deduct their purchase value from the inventory account
 
1433       $ref->{expense_accno} = ($form->{"expense_accno_$row"}) ? $form->{"expense_accno_$row"} : $ref->{expense_accno};
 
1435       $form->{amount_cogs}{ $form->{id} }{ $ref->{expense_accno} } += -$linetotal;
 
1436       $form->{expense_inventory} .= " " . $ref->{expense_accno};
 
1437       $ref->{inventory_accno} = ($form->{"inventory_accno_$row"}) ? $form->{"inventory_accno_$row"} : $ref->{inventory_accno};
 
1439       $form->{amount_cogs}{ $form->{id} }{ $ref->{inventory_accno} } -= -$linetotal;
 
1440       $form->{expense_inventory} .= " " . $ref->{inventory_accno};
 
1446     last if (($totalqty -= $qty) <= 0);
 
1451   $main::lxdebug->leave_sub();
 
1456 sub reverse_invoice {
 
1457   $main::lxdebug->enter_sub();
 
1459   my ($dbh, $form) = @_;
 
1461   # reverse inventory items
 
1463     qq|SELECT i.id, i.parts_id, i.qty, i.assemblyitem, p.assembly, p.inventory_accno_id
 
1465        JOIN parts p ON (i.parts_id = p.id)
 
1466        WHERE i.trans_id = ?|;
 
1467   my $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id"}));
 
1469   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1471     if ($ref->{inventory_accno_id}) {
 
1472       # de-allocated purchases
 
1474         qq|SELECT i.id, i.trans_id, i.allocated
 
1476            WHERE (i.parts_id = ?) AND (i.allocated > 0)
 
1477            ORDER BY i.trans_id DESC|;
 
1478       my $sth2 = prepare_execute_query($form, $dbh, $query, conv_i($ref->{"parts_id"}));
 
1480       while (my $inhref = $sth2->fetchrow_hashref('NAME_lc')) {
 
1481         my $qty = $ref->{qty};
 
1482         if (($ref->{qty} - $inhref->{allocated}) > 0) {
 
1483           $qty = $inhref->{allocated};
 
1487         $form->update_balance($dbh, "invoice", "allocated", qq|id = $inhref->{id}|, $qty * -1);
 
1489         last if (($ref->{qty} -= $qty) <= 0);
 
1498   my @values = (conv_i($form->{id}));
 
1499   do_query($form, $dbh, qq|DELETE FROM acc_trans WHERE trans_id = ?|, @values);
 
1500   do_query($form, $dbh, qq|DELETE FROM invoice WHERE trans_id = ?|, @values);
 
1501   do_query($form, $dbh, qq|DELETE FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|, @values);
 
1503   $main::lxdebug->leave_sub();
 
1506 sub delete_invoice {
 
1507   $main::lxdebug->enter_sub();
 
1509   my ($self, $myconfig, $form) = @_;
 
1511   # connect to database
 
1512   my $dbh = $form->get_standard_dbh;
 
1514   &reverse_invoice($dbh, $form);
 
1516   my @values = (conv_i($form->{id}));
 
1518   # Falls wir ein Storno haben, müssen zwei Felder in der stornierten Rechnung wieder
 
1519   # zurückgesetzt werden. Vgl:
 
1520   #  id | storno | storno_id |  paid   |  amount
 
1521   #----+--------+-----------+---------+-----------
 
1522   # 18 | f      |           | 0.00000 | 119.00000
 
1524   # 18 | t      |           |  119.00000 |  119.00000
 
1526   if($form->{storno}){
 
1527     # storno_id auslesen und korrigieren
 
1528     my ($invoice_id) = selectfirst_array_query($form, $dbh, qq|SELECT storno_id FROM ar WHERE id = ?|,@values);
 
1529     do_query($form, $dbh, qq|UPDATE ar SET storno = 'f', paid = 0 WHERE id = ?|, $invoice_id);
 
1532   # delete spool files
 
1533   my @spoolfiles = selectall_array_query($form, $dbh, qq|SELECT spoolfile FROM status WHERE trans_id = ?|, @values);
 
1536     qq|DELETE FROM status WHERE trans_id = ?|,
 
1537     qq|DELETE FROM periodic_invoices WHERE ar_id = ?|,
 
1538     qq|DELETE FROM ar WHERE id = ?|,
 
1541   map { do_query($form, $dbh, $_, @values) } @queries;
 
1543   my $rc = $dbh->commit;
 
1546     my $spool = $::lx_office_conf{paths}->{spool};
 
1547     map { unlink "$spool/$_" if -f "$spool/$_"; } @spoolfiles;
 
1550   $main::lxdebug->leave_sub();
 
1555 sub retrieve_invoice {
 
1556   $main::lxdebug->enter_sub();
 
1558   my ($self, $myconfig, $form) = @_;
 
1560   # connect to database
 
1561   my $dbh = $form->get_standard_dbh;
 
1563   my ($sth, $ref, $query);
 
1565   my $query_transdate = !$form->{id} ? ", current_date AS invdate" : '';
 
1569          (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
 
1570          (SELECT c.accno FROM chart c WHERE d.income_accno_id = c.id)    AS income_accno,
 
1571          (SELECT c.accno FROM chart c WHERE d.expense_accno_id = c.id)   AS expense_accno,
 
1572          (SELECT c.accno FROM chart c WHERE d.fxgain_accno_id = c.id)    AS fxgain_accno,
 
1573          (SELECT c.accno FROM chart c WHERE d.fxloss_accno_id = c.id)    AS fxloss_accno
 
1577   $ref = selectfirst_hashref_query($form, $dbh, $query);
 
1578   map { $form->{$_} = $ref->{$_} } keys %{ $ref };
 
1581     my $id = conv_i($form->{id});
 
1584     #erweiterung um das entsprechende feld lieferscheinnummer (a.donumber) in der html-maske anzuzeigen 12.02.2009 jb
 
1588            a.invnumber, a.ordnumber, a.quonumber, a.cusordnumber,
 
1589            a.orddate, a.quodate, a.globalproject_id,
 
1590            a.transdate AS invdate, a.deliverydate, a.paid, a.storno, a.gldate,
 
1591            a.shippingpoint, a.shipvia, a.terms, a.notes, a.intnotes, a.taxzone_id,
 
1592            a.duedate, a.taxincluded, (SELECT cu.name FROM currencies cu WHERE cu.id=a.currency_id) AS currency, a.shipto_id, a.cp_id,
 
1593            a.employee_id, a.salesman_id, a.payment_id,
 
1594            a.language_id, a.delivery_customer_id, a.delivery_vendor_id, a.type,
 
1595            a.transaction_description, a.donumber, a.invnumber_for_credit_note,
 
1596            a.marge_total, a.marge_percent, a.direct_debit,
 
1599          LEFT JOIN employee e ON (e.id = a.employee_id)
 
1601     $ref = selectfirst_hashref_query($form, $dbh, $query, $id);
 
1602     map { $form->{$_} = $ref->{$_} } keys %{ $ref };
 
1604     $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "buy");
 
1607     $query = qq|SELECT * FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|;
 
1608     $ref = selectfirst_hashref_query($form, $dbh, $query, $id);
 
1610     map { $form->{$_} = $ref->{$_} } keys %{ $ref };
 
1612     foreach my $vc (qw(customer vendor)) {
 
1613       next if !$form->{"delivery_${vc}_id"};
 
1614       ($form->{"delivery_${vc}_string"}) = selectrow_query($form, $dbh, qq|SELECT name FROM customer WHERE id = ?|, $id);
 
1617     # get printed, emailed
 
1618     $query = qq|SELECT printed, emailed, spoolfile, formname FROM status WHERE trans_id = ?|;
 
1619     $sth = prepare_execute_query($form, $dbh, $query, $id);
 
1621     while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1622       $form->{printed} .= "$ref->{formname} " if $ref->{printed};
 
1623       $form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
 
1624       $form->{queued} .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
 
1627     map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
 
1629     my $transdate = $form->{deliverydate} ? $dbh->quote($form->{deliverydate})
 
1630                   : $form->{invdate}      ? $dbh->quote($form->{invdate})
 
1634     my $taxzone_id = $form->{taxzone_id} *= 1;
 
1635     $taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
 
1637     # retrieve individual items
 
1640            c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
 
1641            c2.accno AS income_accno,    c2.new_chart_id AS income_new_chart,    date($transdate) - c2.valid_from as income_valid,
 
1642            c3.accno AS expense_accno,   c3.new_chart_id AS expense_new_chart,   date($transdate) - c3.valid_from AS expense_valid,
 
1645            i.description, i.longdescription, i.qty, i.fxsellprice AS sellprice, i.discount, i.parts_id AS id, i.unit, i.deliverydate AS reqdate,
 
1646            i.project_id, i.serialnumber, i.id AS invoice_pos, i.pricegroup_id, i.ordnumber, i.transdate, i.cusordnumber, i.subtotal, i.lastcost,
 
1647            i.price_factor_id, i.price_factor, i.marge_price_factor,
 
1648            p.partnumber, p.assembly, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id, p.formel, p.listprice,
 
1649            pr.projectnumber, pg.partsgroup, prg.pricegroup
 
1652          LEFT JOIN parts p ON (i.parts_id = p.id)
 
1653          LEFT JOIN project pr ON (i.project_id = pr.id)
 
1654          LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
 
1655          LEFT JOIN pricegroup prg ON (i.pricegroup_id = prg.id)
 
1657          LEFT JOIN chart c1 ON ((SELECT inventory_accno_id             FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
 
1658          LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id}  FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
 
1659          LEFT JOIN chart c3 ON ((SELECT expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
 
1661          WHERE (i.trans_id = ?) AND NOT (i.assemblyitem = '1') ORDER BY i.id|;
 
1663     $sth = prepare_execute_query($form, $dbh, $query, $id);
 
1665     while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1666       # Retrieve custom variables.
 
1667       my $cvars = CVar->get_custom_variables(dbh        => $dbh,
 
1669                                              sub_module => 'invoice',
 
1670                                              trans_id   => $ref->{invoice_id},
 
1672       map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
 
1673       delete $ref->{invoice_id};
 
1675       map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid)) if !$ref->{"part_inventory_accno_id"};
 
1676       delete($ref->{"part_inventory_accno_id"});
 
1678       foreach my $type (qw(inventory income expense)) {
 
1679         while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
 
1680           my $query = qq|SELECT accno, new_chart_id, date($transdate) - valid_from FROM chart WHERE id = ?|;
 
1681           @$ref{ map $type.$_, qw(_accno _new_chart _valid) } = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
 
1685       # get tax rates and description
 
1686       my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
 
1688         qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber FROM tax t
 
1689            LEFT JOIN chart c ON (c.id = t.chart_id)
 
1691              (SELECT tk.tax_id FROM taxkeys tk
 
1692               WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?)
 
1693                 AND startdate <= date($transdate)
 
1694               ORDER BY startdate DESC LIMIT 1)
 
1696       my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
 
1697       $ref->{taxaccounts} = "";
 
1699       while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
 
1701         if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
 
1705         $ref->{taxaccounts} .= "$ptr->{accno} ";
 
1707         if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
 
1708           $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
 
1709           $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
 
1710           $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
 
1711           $form->{taxaccounts} .= "$ptr->{accno} ";
 
1716       $ref->{qty} *= -1 if $form->{type} eq "credit_note";
 
1718       chop $ref->{taxaccounts};
 
1719       push @{ $form->{invoice_details} }, $ref;
 
1724     Common::webdav_folder($form);
 
1727   my $rc = $dbh->commit;
 
1729   $main::lxdebug->leave_sub();
 
1735   $main::lxdebug->enter_sub();
 
1737   my ($self, $myconfig, $form) = @_;
 
1739   # connect to database
 
1740   my $dbh = $form->get_standard_dbh;
 
1742   my $dateformat = $myconfig->{dateformat};
 
1743   $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/;
 
1745   my (@values, $duedate, $ref, $query);
 
1747   if ($form->{invdate}) {
 
1748     $duedate = "to_date(?, '$dateformat')";
 
1749     push @values, $form->{invdate};
 
1751     $duedate = "current_date";
 
1754   my $cid = conv_i($form->{customer_id});
 
1757   if ($form->{payment_id}) {
 
1758     $payment_id = "(pt.id = ?) OR";
 
1759     push @values, conv_i($form->{payment_id});
 
1765          c.id AS customer_id, c.name AS customer, c.discount as customer_discount, c.creditlimit, c.terms,
 
1766          c.email, c.cc, c.bcc, c.language_id, c.payment_id,
 
1767          c.street, c.zipcode, c.city, c.country,
 
1768          c.notes AS intnotes, c.klass as customer_klass, c.taxzone_id, c.salesman_id, cu.name AS curr,
 
1769          c.taxincluded_checked, c.direct_debit,
 
1770          $duedate + COALESCE(pt.terms_netto, 0) AS duedate,
 
1771          b.discount AS tradediscount, b.description AS business
 
1773        LEFT JOIN business b ON (b.id = c.business_id)
 
1774        LEFT JOIN payment_terms pt ON ($payment_id (c.payment_id = pt.id))
 
1775        LEFT JOIN currencies cu ON (c.currency_id=cu.id)
 
1778   $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
 
1780   delete $ref->{salesman_id} if !$ref->{salesman_id};
 
1782   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1784   # use customer currency
 
1785   $form->{currency} = $form->{curr};
 
1788     qq|SELECT sum(amount - paid) AS dunning_amount
 
1790        WHERE (paid < amount)
 
1791          AND (customer_id = ?)
 
1792          AND (dunning_config_id IS NOT NULL)|;
 
1793   $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
 
1794   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1797     qq|SELECT dnn.dunning_description AS max_dunning_level
 
1798        FROM dunning_config dnn
 
1799        WHERE id IN (SELECT dunning_config_id
 
1801                     WHERE (paid < amount) AND (customer_id = ?) AND (dunning_config_id IS NOT NULL))
 
1802        ORDER BY dunning_level DESC LIMIT 1|;
 
1803   $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
 
1804   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1806   $form->{creditremaining} = $form->{creditlimit};
 
1807   $query = qq|SELECT SUM(amount - paid) FROM ar WHERE customer_id = ?|;
 
1808   my ($value) = selectrow_query($form, $dbh, $query, $cid);
 
1809   $form->{creditremaining} -= $value;
 
1813          (SELECT e.buy FROM exchangerate e
 
1814           WHERE e.currency_id = o.currency_id
 
1815             AND e.transdate = o.transdate)
 
1817        WHERE o.customer_id = ?
 
1818          AND o.quotation = '0'
 
1819          AND o.closed = '0'|;
 
1820   my $sth = prepare_execute_query($form, $dbh, $query, $cid);
 
1822   while (my ($amount, $exch) = $sth->fetchrow_array) {
 
1823     $exch = 1 unless $exch;
 
1824     $form->{creditremaining} -= $amount * $exch;
 
1828   # get shipto if we did not converted an order or invoice
 
1829   if (!$form->{shipto}) {
 
1830     map { delete $form->{$_} }
 
1831       qw(shiptoname shiptodepartment_1 shiptodepartment_2
 
1832          shiptostreet shiptozipcode shiptocity shiptocountry
 
1833          shiptocontact shiptophone shiptofax shiptoemail);
 
1835     $query = qq|SELECT * FROM shipto WHERE trans_id = ? AND module = 'CT'|;
 
1836     $ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
 
1838     map { $form->{$_} = $ref->{$_} } keys %$ref;
 
1841   # setup last accounts used for this customer
 
1842   if (!$form->{id} && $form->{type} !~ /_(order|quotation)/) {
 
1844       qq|SELECT c.id, c.accno, c.description, c.link, c.category
 
1846          JOIN acc_trans ac ON (ac.chart_id = c.id)
 
1847          JOIN ar a ON (a.id = ac.trans_id)
 
1848          WHERE a.customer_id = ?
 
1849            AND NOT (c.link LIKE '%_tax%' OR c.link LIKE '%_paid%')
 
1850            AND a.id IN (SELECT max(a2.id) FROM ar a2 WHERE a2.customer_id = ?)|;
 
1851     $sth = prepare_execute_query($form, $dbh, $query, $cid, $cid);
 
1854     while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1855       if ($ref->{category} eq 'I') {
 
1857         $form->{"AR_amount_$i"} = "$ref->{accno}--$ref->{description}";
 
1859         if ($form->{initial_transdate}) {
 
1861             qq|SELECT tk.tax_id, t.rate
 
1863                LEFT JOIN tax t ON tk.tax_id = t.id
 
1864                WHERE (tk.chart_id = ?) AND (startdate <= date(?))
 
1865                ORDER BY tk.startdate DESC
 
1867           my ($tax_id, $rate) =
 
1868             selectrow_query($form, $dbh, $tax_query, $ref->{id},
 
1869                             $form->{initial_transdate});
 
1870           $form->{"taxchart_$i"} = "${tax_id}--${rate}";
 
1873       if ($ref->{category} eq 'A') {
 
1874         $form->{ARselected} = $form->{AR_1} = $ref->{accno};
 
1878     $form->{rowcount} = $i if ($i && !$form->{type});
 
1881   $main::lxdebug->leave_sub();
 
1885   $main::lxdebug->enter_sub();
 
1887   my ($self, $myconfig, $form) = @_;
 
1889   # connect to database
 
1890   my $dbh = $form->get_standard_dbh;
 
1892   my $i = $form->{rowcount};
 
1894   my $where = qq|NOT p.obsolete = '1'|;
 
1897   foreach my $column (qw(p.partnumber p.description pgpartsgroup )) {
 
1898     my ($table, $field) = split m/\./, $column;
 
1899     next if !$form->{"${field}_${i}"};
 
1900     $where .= qq| AND lower(${column}) ILIKE ?|;
 
1901     push @values, '%' . $form->{"${field}_${i}"} . '%';
 
1904   #Es soll auch nach EAN gesucht werden, ohne Einschränkung durch Beschreibung
 
1905   if ($form->{"partnumber_$i"} && !$form->{"description_$i"}) {
 
1906     $where .= qq| OR (NOT p.obsolete = '1' AND p.ean = ? )|;
 
1907     push @values, $form->{"partnumber_$i"};
 
1910   # Search for part ID overrides all other criteria.
 
1911   if ($form->{"id_${i}"}) {
 
1912     $where  = qq|p.id = ?|;
 
1913     @values = ($form->{"id_${i}"});
 
1916   if ($form->{"description_$i"}) {
 
1917     $where .= qq| ORDER BY p.description|;
 
1919     $where .= qq| ORDER BY p.partnumber|;
 
1923   if ($form->{type} eq "invoice") {
 
1925       $form->{deliverydate} ? $dbh->quote($form->{deliverydate}) :
 
1926       $form->{invdate}      ? $dbh->quote($form->{invdate}) :
 
1930       $form->{transdate}    ? $dbh->quote($form->{transdate}) :
 
1934   my $taxzone_id = $form->{taxzone_id} * 1;
 
1935   $taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
 
1939          p.id, p.partnumber, p.description, p.sellprice,
 
1940          p.listprice, p.inventory_accno_id, p.lastcost,
 
1942          c1.accno AS inventory_accno,
 
1943          c1.new_chart_id AS inventory_new_chart,
 
1944          date($transdate) - c1.valid_from AS inventory_valid,
 
1946          c2.accno AS income_accno,
 
1947          c2.new_chart_id AS income_new_chart,
 
1948          date($transdate)  - c2.valid_from AS income_valid,
 
1950          c3.accno AS expense_accno,
 
1951          c3.new_chart_id AS expense_new_chart,
 
1952          date($transdate) - c3.valid_from AS expense_valid,
 
1954          p.unit, p.assembly, p.onhand,
 
1955          p.notes AS partnotes, p.notes AS longdescription,
 
1956          p.not_discountable, p.formel, p.payment_id AS part_payment_id,
 
1957          p.price_factor_id, p.weight,
 
1959          pfac.factor AS price_factor,
 
1964        LEFT JOIN chart c1 ON
 
1965          ((SELECT inventory_accno_id
 
1966            FROM buchungsgruppen
 
1967            WHERE id = p.buchungsgruppen_id) = c1.id)
 
1968        LEFT JOIN chart c2 ON
 
1969          ((SELECT income_accno_id_${taxzone_id}
 
1970            FROM buchungsgruppen
 
1971            WHERE id = p.buchungsgruppen_id) = c2.id)
 
1972        LEFT JOIN chart c3 ON
 
1973          ((SELECT expense_accno_id_${taxzone_id}
 
1974            FROM buchungsgruppen
 
1975            WHERE id = p.buchungsgruppen_id) = c3.id)
 
1976        LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
 
1977        LEFT JOIN price_factors pfac ON (pfac.id = p.price_factor_id)
 
1979   my $sth = prepare_execute_query($form, $dbh, $query, @values);
 
1981   my @translation_queries = ( [ qq|SELECT tr.translation, tr.longdescription
 
1983                                    WHERE tr.language_id = ? AND tr.parts_id = ?| ],
 
1984                               [ qq|SELECT tr.translation, tr.longdescription
 
1986                                    WHERE tr.language_id IN
 
1989                                       WHERE article_code = (SELECT article_code FROM language WHERE id = ?))
 
1992   map { push @{ $_ }, prepare_query($form, $dbh, $_->[0]) } @translation_queries;
 
1994   while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
 
1996     # In der Buchungsgruppe ist immer ein Bestandskonto verknuepft, auch wenn
 
1997     # es sich um eine Dienstleistung handelt. Bei Dienstleistungen muss das
 
1998     # Buchungskonto also aus dem Ergebnis rausgenommen werden.
 
1999     if (!$ref->{inventory_accno_id}) {
 
2000       map({ delete($ref->{"inventory_${_}"}); } qw(accno new_chart valid));
 
2002     delete($ref->{inventory_accno_id});
 
2004     foreach my $type (qw(inventory income expense)) {
 
2005       while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
 
2007           qq|SELECT accno, new_chart_id, date($transdate) - valid_from
 
2010         ($ref->{"${type}_accno"},
 
2011          $ref->{"${type}_new_chart"},
 
2012          $ref->{"${type}_valid"})
 
2013           = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
 
2017     if ($form->{payment_id} eq "") {
 
2018       $form->{payment_id} = $form->{part_payment_id};
 
2021     # get tax rates and description
 
2022     my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
 
2024       qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber
 
2026          LEFT JOIN chart c ON (c.id = t.chart_id)
 
2030             WHERE tk.chart_id = (SELECT id from chart WHERE accno = ?)
 
2032             ORDER BY startdate DESC
 
2035     @values = ($accno_id, $transdate eq "current_date" ? "now" : $transdate);
 
2036     my $stw = $dbh->prepare($query);
 
2037     $stw->execute(@values) || $form->dberror($query);
 
2039     $ref->{taxaccounts} = "";
 
2041     while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
 
2043       if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
 
2047       $ref->{taxaccounts} .= "$ptr->{accno} ";
 
2049       if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
 
2050         $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
 
2051         $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
 
2052         $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
 
2053         $form->{taxaccounts} .= "$ptr->{accno} ";
 
2059     chop $ref->{taxaccounts};
 
2061     if ($form->{language_id}) {
 
2062       for my $spec (@translation_queries) {
 
2063         do_statement($form, $spec->[1], $spec->[0], conv_i($form->{language_id}), conv_i($ref->{id}));
 
2064         my ($translation, $longdescription) = $spec->[1]->fetchrow_array;
 
2065         next unless $translation;
 
2066         $ref->{description} = $translation;
 
2067         $ref->{longdescription} = $longdescription;
 
2072     $ref->{onhand} *= 1;
 
2074     push @{ $form->{item_list} }, $ref;
 
2077   $_->[1]->finish for @translation_queries;
 
2079   foreach my $item (@{ $form->{item_list} }) {
 
2080     my $custom_variables = CVar->get_custom_variables(module   => 'IC',
 
2081                                                       trans_id => $item->{id},
 
2085     map { $item->{"ic_cvar_" . $_->{name} } = $_->{value} } @{ $custom_variables };
 
2088   $main::lxdebug->leave_sub();
 
2091 ##########################
 
2092 # get pricegroups from database
 
2093 # build up selected pricegroup
 
2094 # if an exchange rate - change price
 
2097 sub get_pricegroups_for_parts {
 
2099   $main::lxdebug->enter_sub();
 
2101   my ($self, $myconfig, $form) = @_;
 
2103   my $dbh = $form->get_standard_dbh;
 
2105   $form->{"PRICES"} = {};
 
2109   my $all_units = AM->retrieve_units($myconfig, $form);
 
2110   while (($form->{"id_$i"}) or ($form->{"new_id_$i"})) {
 
2111     $form->{"PRICES"}{$i} = [];
 
2113     $id = $form->{"id_$i"};
 
2115     if (!($form->{"id_$i"}) and $form->{"new_id_$i"}) {
 
2116       $id = $form->{"new_id_$i"};
 
2119     my ($price, $selectedpricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
 
2121     my $pricegroup_old = $form->{"pricegroup_old_$i"};
 
2123     # sellprice has format 13,0000 or 0,00000,  can't check for 0 numerically
 
2124     my $sellprice = $form->{"sellprice_$i"};
 
2125     my $pricegroup_id = $form->{"pricegroup_id_$i"};
 
2126     $form->{"new_pricegroup_$i"} = $selectedpricegroup_id;
 
2127     $form->{"old_pricegroup_$i"} = $pricegroup_old;
 
2129     my $price_new = $form->{"price_new_$i"};
 
2130     my $price_old = $form->{"price_old_$i"};
 
2132     if (!$form->{"unit_old_$i"}) {
 
2133       # Neue Ware aus der Datenbank. In diesem Fall ist unit_$i die
 
2134       # Einheit, wie sie in den Stammdaten hinterlegt wurde.
 
2135       # Es sollte also angenommen werden, dass diese ausgewaehlt war.
 
2136       $form->{"unit_old_$i"} = $form->{"unit_$i"};
 
2139     # Die zuletzt ausgewaehlte mit der aktuell ausgewaehlten Einheit
 
2140     # vergleichen und bei Unterschied den Preis entsprechend umrechnen.
 
2141     $form->{"selected_unit_$i"} = $form->{"unit_$i"} unless ($form->{"selected_unit_$i"});
 
2143     if (!$all_units->{$form->{"selected_unit_$i"}} ||
 
2144         ($all_units->{$form->{"selected_unit_$i"}}->{"base_unit"} ne
 
2145          $all_units->{$form->{"unit_old_$i"}}->{"base_unit"})) {
 
2146       # Die ausgewaehlte Einheit ist fuer diesen Artikel nicht gueltig
 
2147       # (z.B. Dimensionseinheit war ausgewaehlt, es handelt sich aber
 
2148       # um eine Dienstleistung). Dann keinerlei Umrechnung vornehmen.
 
2149       $form->{"unit_old_$i"} = $form->{"selected_unit_$i"} = $form->{"unit_$i"};
 
2154     if ($form->{"unit_old_$i"} ne $form->{"selected_unit_$i"}) {
 
2155       if (defined($all_units->{$form->{"unit_old_$i"}}->{"factor"}) &&
 
2156           $all_units->{$form->{"unit_old_$i"}}->{"factor"}) {
 
2157         $basefactor = $all_units->{$form->{"selected_unit_$i"}}->{"factor"} /
 
2158           $all_units->{$form->{"unit_old_$i"}}->{"factor"};
 
2162     if (!$form->{"basefactor_$i"}) {
 
2163       $form->{"basefactor_$i"} = 1;
 
2169             sellprice AS default_sellprice,
 
2172             'selected' AS selected
 
2178            parts.sellprice AS default_sellprice,
 
2179            pricegroup.pricegroup,
 
2183           LEFT JOIN parts ON parts.id = parts_id
 
2184           LEFT JOIN pricegroup ON pricegroup.id = pricegroup_id
 
2186           ORDER BY pricegroup|;
 
2187     my @values = (conv_i($id), conv_i($id));
 
2188     my $pkq = prepare_execute_query($form, $dbh, $query, @values);
 
2190     while (my $pkr = $pkq->fetchrow_hashref('NAME_lc')) {
 
2192       $pkr->{selected} = '';
 
2194       # if there is an exchange rate change price
 
2195       if (($form->{exchangerate} * 1) != 0) {
 
2196         $pkr->{price} /= $form->{exchangerate};
 
2199       $pkr->{price} *= $form->{"basefactor_$i"};
 
2200       $pkr->{price} *= $basefactor;
 
2201       $pkr->{price_ufmt} = $pkr->{price};
 
2202       $pkr->{price} = $form->format_amount($myconfig, $pkr->{price}, 5);
 
2204       if (!defined $selectedpricegroup_id) {
 
2205         # new entries in article list, either old invoice was loaded (edit) or a new article was added
 
2206         # Case A: open old invoice, no pricegroup selected
 
2207         # Case B: add new article to invoice, no pricegroup selected
 
2209         # to distinguish case A and B the variable pricegroup_id_$i is used
 
2210         # for new articles this variable isn't defined, for loaded articles it is
 
2211         # sellprice can't be used, as it already has 0,00 set
 
2213         if ($pkr->{pricegroup_id} eq $form->{"pricegroup_id_$i"} and defined $form->{"pricegroup_id_$i"}) {
 
2215           $pkr->{selected}  = ' selected';
 
2216         } elsif ($pkr->{pricegroup_id} eq $form->{customer_klass}
 
2217                  and not defined $form->{"pricegroup_id_$i"}
 
2218                  and $pkr->{price_ufmt} != 0    # only use customer pricegroup price if it has a value, else use default_sellprice
 
2219                                                 # for the case where pricegroup prices haven't been set
 
2221           # Case B: use default pricegroup of customer
 
2223           $pkr->{selected}  = ' selected'; # unless $form->{selected};
 
2224           # no customer pricesgroup set
 
2225           if ($pkr->{price_ufmt} == $pkr->{default_sellprice}) {
 
2227             $pkr->{price} = $form->{"sellprice_$i"};
 
2231 # this sub should not set anything and only return. --sschoeling, 20090506
 
2232 # is this correct? put in again... -- grichardson 20110119
 
2233             $form->{"sellprice_$i"} = $pkr->{price};
 
2236         } elsif ($pkr->{price_ufmt} == $pkr->{default_sellprice} and $pkr->{default_sellprice} != 0) {
 
2237           $pkr->{price}    = $form->{"sellprice_$i"};
 
2238           $pkr->{selected} = ' selected';
 
2242       # existing article: pricegroup or price changed
 
2243       if ($selectedpricegroup_id or $selectedpricegroup_id == 0) {
 
2244         if ($selectedpricegroup_id ne $pricegroup_old) {
 
2245           # pricegroup has changed
 
2246           if ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
 
2247             $pkr->{selected}  = ' selected';
 
2249         } elsif ( ($form->parse_amount($myconfig, $price_new)
 
2250                  != $form->parse_amount($myconfig, $form->{"sellprice_$i"}))
 
2251                   and ($price_new ne 0) and defined $price_new) {
 
2252           # sellprice has changed
 
2253           # when loading existing invoices $price_new is NULL
 
2254           if ($pkr->{pricegroup_id} == 0) {
 
2255             $pkr->{price}     = $form->{"sellprice_$i"};
 
2256             $pkr->{selected}  = ' selected';
 
2258         } elsif ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
 
2259           # neither sellprice nor pricegroup changed
 
2260           $pkr->{selected}  = ' selected';
 
2261           if (    ($pkr->{pricegroup_id} == 0) and ($pkr->{price} == $form->{"sellprice_$i"})) {
 
2262             # $pkr->{price}                         = $form->{"sellprice_$i"};
 
2264             $pkr->{price} = $form->{"sellprice_$i"};
 
2268       push @{ $form->{PRICES}{$i} }, $pkr;
 
2271     $form->{"basefactor_$i"} *= $basefactor;
 
2278   $main::lxdebug->leave_sub();
 
2282   $main::lxdebug->enter_sub();
 
2284   my ($self, $myconfig, $form, $table) = @_;
 
2286   $main::lxdebug->leave_sub() and return 0 unless ($form->{id});
 
2288   # make sure there's no funny stuff in $table
 
2289   # ToDO: die when this happens and throw an error
 
2290   $main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);
 
2292   my $dbh = $form->get_standard_dbh;
 
2294   my $query = qq|SELECT storno FROM $table WHERE storno_id = ?|;
 
2295   my ($result) = selectrow_query($form, $dbh, $query, $form->{id});
 
2297   $main::lxdebug->leave_sub();
 
2303   $main::lxdebug->enter_sub();
 
2305   my ($self, $myconfig, $form, $table, $id) = @_;
 
2307   $main::lxdebug->leave_sub() and return 0 unless ($id);
 
2309   # make sure there's no funny stuff in $table
 
2310   # ToDO: die when this happens and throw an error
 
2311   $main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);
 
2313   my $dbh = $form->get_standard_dbh;
 
2315   my $query = qq|SELECT storno FROM $table WHERE id = ?|;
 
2316   my ($result) = selectrow_query($form, $dbh, $query, $id);
 
2318   $main::lxdebug->leave_sub();
 
2323 sub get_standard_accno_current_assets {
 
2324   $main::lxdebug->enter_sub();
 
2326   my ($self, $myconfig, $form) = @_;
 
2328   my $dbh = $form->get_standard_dbh;
 
2330   my $query = qq| SELECT accno FROM chart WHERE id = (SELECT ar_paid_accno_id FROM defaults)|;
 
2331   my ($result) = selectrow_query($form, $dbh, $query);
 
2333   $main::lxdebug->leave_sub();