Projekt

Allgemein

Profil

Herunterladen (84 KB) Statistiken
| Zweig: | Markierung: | Revision:
d319704a Moritz Bunkus
#=====================================================================
# LX-Office ERP
# Copyright (C) 2004
# Based on SQL-Ledger Version 2.1.9
# Web http://www.lx-office.org
#
#=====================================================================
# SQL-Ledger Accounting
# Copyright (C) 1998-2002
#
# Author: Dieter Simader
# Email: dsimader@sql-ledger.org
# Web: http://www.sql-ledger.org
#
# Contributors:
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#======================================================================
#
# Inventory invoicing module
#
#======================================================================

package IS;

d9c9bc22 Moritz Bunkus
use List::Util qw(max);

54e4131e Moritz Bunkus
use SL::AM;
247a26dc Moritz Bunkus
use SL::ARAP;
8688e71e Moritz Bunkus
use SL::CVar;
8e206587 Moritz Bunkus
use SL::Common;
7e7a1369 Sven Schöling
use SL::DATEV qw(:CONSTANTS);
5b47ed3e Moritz Bunkus
use SL::DBUtils;
3c1ceacd Moritz Bunkus
use SL::DO;
e09347c8 Geoffrey Richardson
use SL::GenericTranslations;
5fdc44cb Moritz Bunkus
use SL::MoreCommon;
47c3bf62 Moritz Bunkus
use SL::IC;
40c2c37c Moritz Bunkus
use SL::IO;
6dcf04cf Moritz Bunkus
use SL::TransNumber;
97954312 Bernd Bleßmann
use SL::DB::Default;
b3327c52 Sven Schöling
use Data::Dumper;
07d71c33 Stephan Köhler
76c486e3 Sven Schöling
use strict;

d319704a Moritz Bunkus
sub invoice_details {
$main::lxdebug->enter_sub();

my ($self, $myconfig, $form, $locale) = @_;

532b0d4c Moritz Bunkus
$form->{duedate} ||= $form->{invdate};
d319704a Moritz Bunkus
# connect to database
74b9dd67 Sven Schöling
my $dbh = $form->get_standard_dbh;
532b0d4c Moritz Bunkus
my $sth;
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
my $query = qq|SELECT date | . conv_dateq($form->{duedate}) . qq| - date | . conv_dateq($form->{invdate}) . qq| AS terms|;
($form->{terms}) = selectrow_query($form, $dbh, $query);
d319704a Moritz Bunkus
c6867c46 Bernd Bleßmann
my (@project_ids, %projectnumbers, %projectdescriptions);
51649b5b Sven Schöling
$form->{TEMPLATE_ARRAYS} = {};
96d10ecc Moritz Bunkus
push(@project_ids, $form->{"globalproject_id"}) if ($form->{"globalproject_id"});

1e251313 Moritz Bunkus
$form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
my %price_factors;

foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
$price_factors{$pfac->{id}} = $pfac;
$pfac->{factor} *= 1;
$pfac->{formatted_factor} = $form->format_amount($myconfig, $pfac->{factor});
}

96d10ecc Moritz Bunkus
# sort items by partsgroup
b8da8785 Sven Schöling
for my $i (1 .. $form->{rowcount}) {
# $partsgroup = "";
# if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
# $partsgroup = $form->{"partsgroup_$i"};
# }
# push @partsgroup, [$i, $partsgroup];
96d10ecc Moritz Bunkus
push(@project_ids, $form->{"project_id_$i"}) if ($form->{"project_id_$i"});
}

if (@project_ids) {
c6867c46 Bernd Bleßmann
$query = "SELECT id, projectnumber, description FROM project WHERE id IN (" .
96d10ecc Moritz Bunkus
join(", ", map({ "?" } @project_ids)) . ")";
$sth = $dbh->prepare($query);
$sth->execute(@project_ids) ||
$form->dberror($query . " (" . join(", ", @project_ids) . ")");
while (my $ref = $sth->fetchrow_hashref()) {
$projectnumbers{$ref->{id}} = $ref->{projectnumber};
c6867c46 Bernd Bleßmann
$projectdescriptions{$ref->{id}} = $ref->{description};
96d10ecc Moritz Bunkus
}
$sth->finish();
}

$form->{"globalprojectnumber"} =
$projectnumbers{$form->{"globalproject_id"}};
c6867c46 Bernd Bleßmann
$form->{"globalprojectdescription"} =
$projectdescriptions{$form->{"globalproject_id"}};
96d10ecc Moritz Bunkus
d319704a Moritz Bunkus
my $tax = 0;
my $item;
my $i;
my @partsgroup = ();
my $partsgroup;
my %oid = ('Pg' => 'oid',
'Oracle' => 'rowid');

# sort items by partsgroup
for $i (1 .. $form->{rowcount}) {
$partsgroup = "";
if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
$partsgroup = $form->{"partsgroup_$i"};
}
push @partsgroup, [$i, $partsgroup];
}

my $sameitem = "";
my @taxaccounts;
my %taxaccounts;
my %taxbase;
my $taxrate;
my $taxamount;
my $taxbase;
my $taxdiff;
54e4131e Moritz Bunkus
my $nodiscount;
my $yesdiscount;
my $nodiscount_subtotal = 0;
my $discount_subtotal = 0;
my $position = 0;
my $subtotal_header = 0;
my $subposition = 0;

af59820c Moritz Bunkus
$form->{discount} = [];

47c3bf62 Moritz Bunkus
IC->prepare_parts_for_printing();

98452aaa Moritz Bunkus
my $ic_cvar_configs = CVar->get_configs(module => 'IC');

96d10ecc Moritz Bunkus
my @arrays =
qw(runningnumber number description longdescription qty ship unit bin
217d32f3 Moritz Bunkus
deliverydate_oe ordnumber_oe transdate_oe validuntil
96d10ecc Moritz Bunkus
partnotes serialnumber reqdate sellprice listprice netprice
discount p_discount discount_sub nodiscount_sub
c6867c46 Bernd Bleßmann
linetotal nodiscount_linetotal tax_rate projectnumber projectdescription
613c0749 Moritz Bunkus
price_factor price_factor_name partsgroup);
96d10ecc Moritz Bunkus
98452aaa Moritz Bunkus
push @arrays, map { "ic_cvar_$_->{name}" } @{ $ic_cvar_configs };

9c63c160 Moritz Bunkus
my @tax_arrays = qw(taxbase tax taxdescription taxrate taxnumber);

my @payment_arrays = qw(payment paymentaccount paymentdate paymentsource paymentmemo);

fdb14a85 Moritz Bunkus
map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays, @payment_arrays);
96d10ecc Moritz Bunkus
d319704a Moritz Bunkus
foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
$i = $item->[0];

if ($item->[1] ne $sameitem) {
9c63c160 Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, qq|$item->[1]|);
d319704a Moritz Bunkus
$sameitem = $item->[1];

9c63c160 Moritz Bunkus
map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
d319704a Moritz Bunkus
}

$form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});

8c89bb02 Moritz Bunkus
if ($form->{"id_$i"} != 0) {
d319704a Moritz Bunkus
54e4131e Moritz Bunkus
# add number, description and qty to $form->{number},
if ($form->{"subtotal_$i"} && !$subtotal_header) {
$subtotal_header = $i;
$position = int($position);
$subposition = 0;
$position++;
} elsif ($subtotal_header) {
$subposition += 1;
$position = int($position);
$position = $position.".".$subposition;
} else {
$position = int($position);
$position++;
}
d9c9bc22 Moritz Bunkus
1e251313 Moritz Bunkus
my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || { 'factor' => 1 };

9c63c160 Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{runningnumber} }, $position;
push @{ $form->{TEMPLATE_ARRAYS}->{number} }, $form->{"partnumber_$i"};
push @{ $form->{TEMPLATE_ARRAYS}->{serialnumber} }, $form->{"serialnumber_$i"};
push @{ $form->{TEMPLATE_ARRAYS}->{bin} }, $form->{"bin_$i"};
push @{ $form->{TEMPLATE_ARRAYS}->{partnotes} }, $form->{"partnotes_$i"};
push @{ $form->{TEMPLATE_ARRAYS}->{description} }, $form->{"description_$i"};
push @{ $form->{TEMPLATE_ARRAYS}->{longdescription} }, $form->{"longdescription_$i"};
push @{ $form->{TEMPLATE_ARRAYS}->{qty} }, $form->format_amount($myconfig, $form->{"qty_$i"});
8461199d Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{qty_nofmt} }, $form->{"qty_$i"};
9c63c160 Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{unit} }, $form->{"unit_$i"};
103bf7e8 Sven Schöling
push @{ $form->{TEMPLATE_ARRAYS}->{deliverydate_oe} }, $form->{"reqdate_$i"};
9c63c160 Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{sellprice} }, $form->{"sellprice_$i"};
8461199d Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{sellprice_nofmt} }, $form->parse_amount($myconfig, $form->{"sellprice_$i"});
9c63c160 Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{ordnumber_oe} }, $form->{"ordnumber_$i"};
push @{ $form->{TEMPLATE_ARRAYS}->{transdate_oe} }, $form->{"transdate_$i"};
push @{ $form->{TEMPLATE_ARRAYS}->{invnumber} }, $form->{"invnumber"};
push @{ $form->{TEMPLATE_ARRAYS}->{invdate} }, $form->{"invdate"};
push @{ $form->{TEMPLATE_ARRAYS}->{price_factor} }, $price_factor->{formatted_factor};
push @{ $form->{TEMPLATE_ARRAYS}->{price_factor_name} }, $price_factor->{description};
push @{ $form->{TEMPLATE_ARRAYS}->{partsgroup} }, $form->{"partsgroup_$i"};
push @{ $form->{TEMPLATE_ARRAYS}->{reqdate} }, $form->{"reqdate_$i"};
217d32f3 Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{listprice} }, $form->{"listprice_$i"});
d319704a Moritz Bunkus
d9c9bc22 Moritz Bunkus
my $sellprice = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
my ($dec) = ($sellprice =~ /\.(\d+)/);
my $decimalplaces = max 2, length($dec);
d319704a Moritz Bunkus
1ed2662d Moritz Bunkus
my $parsed_discount = $form->parse_amount($myconfig, $form->{"discount_$i"});
21717dcd Moritz Bunkus
my $linetotal_exact = $form->{"qty_$i"} * $sellprice * (100 - $parsed_discount) / 100 / $price_factor->{factor};
my $linetotal = $form->round_amount($linetotal_exact, 2);
my $discount = $form->round_amount($form->{"qty_$i"} * $sellprice * $parsed_discount / 100 / $price_factor->{factor} - ($linetotal - $linetotal_exact),
$decimalplaces);
1e251313 Moritz Bunkus
my $nodiscount_linetotal = $form->round_amount($form->{"qty_$i"} * $sellprice / $price_factor->{factor}, 2);
d9c9bc22 Moritz Bunkus
$form->{"netprice_$i"} = $form->round_amount($form->{"qty_$i"} ? ($linetotal / $form->{"qty_$i"}) : 0, 2);

8461199d Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{netprice} }, ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : '';
push @{ $form->{TEMPLATE_ARRAYS}->{netprice_nofmt} }, ($form->{"netprice_$i"} != 0) ? $form->{"netprice_$i"} : '';
d9c9bc22 Moritz Bunkus
$linetotal = ($linetotal != 0) ? $linetotal : '';

8461199d Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{discount} }, ($discount != 0) ? $form->format_amount($myconfig, $discount * -1, 2) : '';
push @{ $form->{TEMPLATE_ARRAYS}->{discount_nofmt} }, ($discount != 0) ? $discount * -1 : '';
push @{ $form->{TEMPLATE_ARRAYS}->{p_discount} }, $form->{"discount_$i"};
d9c9bc22 Moritz Bunkus
$form->{total} += $linetotal;
54e4131e Moritz Bunkus
$form->{nodiscount_total} += $nodiscount_linetotal;
d9c9bc22 Moritz Bunkus
$form->{discount_total} += $discount;

if ($subtotal_header) {
$discount_subtotal += $linetotal;
$nodiscount_subtotal += $nodiscount_linetotal;
}
54e4131e Moritz Bunkus
if ($form->{"subtotal_$i"} && $subtotal_header && ($subtotal_header != $i)) {
8461199d Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub} }, $form->format_amount($myconfig, $discount_subtotal, 2);
push @{ $form->{TEMPLATE_ARRAYS}->{discount_sub_nofmt} }, $discount_subtotal;
push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub} }, $form->format_amount($myconfig, $nodiscount_subtotal, 2);
push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_sub_nofmt} }, $nodiscount_subtotal;
d9c9bc22 Moritz Bunkus
$discount_subtotal = 0;
54e4131e Moritz Bunkus
$nodiscount_subtotal = 0;
d9c9bc22 Moritz Bunkus
$subtotal_header = 0;

54e4131e Moritz Bunkus
} else {
e1a38ef7 Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{$_} }, "" for qw(discount_sub nodiscount_sub discount_sub_nofmt nodiscount_sub_nofmt);
54e4131e Moritz Bunkus
}

d9c9bc22 Moritz Bunkus
if (!$form->{"discount_$i"}) {
54e4131e Moritz Bunkus
$nodiscount += $linetotal;
}
d319704a Moritz Bunkus
8461199d Moritz Bunkus
push @{ $form->{TEMPLATE_ARRAYS}->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2);
push @{ $form->{TEMPLATE_ARRAYS}->{linetotal_nofmt} }, $linetotal_exact;
push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal} }, $form->format_amount($myconfig, $nodiscount_linetotal, 2);
push @{ $form->{TEMPLATE_ARRAYS}->{nodiscount_linetotal_nofmt} }, $nodiscount_linetotal;
54e4131e Moritz Bunkus
8461199d Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{projectnumber} }, $projectnumbers{$form->{"project_id_$i"}});
push(@{ $form->{TEMPLATE_ARRAYS}->{projectdescription} }, $projectdescriptions{$form->{"project_id_$i"}});
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
@taxaccounts = split(/ /, $form->{"taxaccounts_$i"});
d319704a Moritz Bunkus
$taxrate = 0;
$taxdiff = 0;

map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;

if ($form->{taxincluded}) {

# calculate tax
$taxamount = $linetotal * $taxrate / (1 + $taxrate);
$taxbase = $linetotal - $taxamount;
} else {
$taxamount = $linetotal * $taxrate;
$taxbase = $linetotal;
}

if ($form->round_amount($taxrate, 7) == 0) {
if ($form->{taxincluded}) {
eeb560af Moritz Bunkus
foreach my $accno (@taxaccounts) {
$taxamount = $form->round_amount($linetotal * $form->{"${accno}_rate"} / (1 + abs($form->{"${accno}_rate"})), 2);
d319704a Moritz Bunkus
eeb560af Moritz Bunkus
$taxaccounts{$accno} += $taxamount;
$taxdiff += $taxamount;
d319704a Moritz Bunkus
eeb560af Moritz Bunkus
$taxbase{$accno} += $taxbase;
d319704a Moritz Bunkus
}
$taxaccounts{ $taxaccounts[0] } += $taxdiff;
} else {
eeb560af Moritz Bunkus
foreach my $accno (@taxaccounts) {
$taxaccounts{$accno} += $linetotal * $form->{"${accno}_rate"};
$taxbase{$accno} += $taxbase;
d319704a Moritz Bunkus
}
}
} else {
eeb560af Moritz Bunkus
foreach my $accno (@taxaccounts) {
$taxaccounts{$accno} += $taxamount * $form->{"${accno}_rate"} / $taxrate;
$taxbase{$accno} += $taxbase;
d319704a Moritz Bunkus
}
}
b8da8785 Sven Schöling
my $tax_rate = $taxrate * 100;
9c63c160 Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{tax_rate} }, qq|$tax_rate|);
d319704a Moritz Bunkus
if ($form->{"assembly_$i"}) {
$sameitem = "";

# get parts and push them onto the stack
my $sortorder = "";
if ($form->{groupitems}) {
$sortorder =
qq|ORDER BY pg.partsgroup, a.$oid{$myconfig->{dbdriver}}|;
} else {
$sortorder = qq|ORDER BY a.$oid{$myconfig->{dbdriver}}|;
}

532b0d4c Moritz Bunkus
$query =
qq|SELECT p.partnumber, p.description, p.unit, a.qty, pg.partsgroup
FROM assembly a
JOIN parts p ON (a.parts_id = p.id)
LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
WHERE (a.bom = '1') AND (a.id = ?) $sortorder|;
$sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id_$i"}));
d319704a Moritz Bunkus
b8da8785 Sven Schöling
while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
d319704a Moritz Bunkus
if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
9c63c160 Moritz Bunkus
map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
d319704a Moritz Bunkus
$sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
9c63c160 Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{description} }, $sameitem);
d319704a Moritz Bunkus
}

map { $form->{"a_$_"} = $ref->{$_} } qw(partnumber description);

9c63c160 Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{description} },
d319704a Moritz Bunkus
$form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}
)
. qq| -- $form->{"a_partnumber"}, $form->{"a_description"}|);
9c63c160 Moritz Bunkus
map({ push(@{ $form->{TEMPLATE_ARRAYS}->{$_} }, "") } grep({ $_ ne "description" } @arrays));
d319704a Moritz Bunkus
}
$sth->finish;
}
98452aaa Moritz Bunkus
d729e328 Sven Schöling
push @{ $form->{TEMPLATE_ARRAYS}->{"ic_cvar_$_->{name}"} },
CVar->format_to_template(CVar->parse($form->{"ic_cvar_$_->{name}_$i"}, $_), $_)
for @{ $ic_cvar_configs };
d319704a Moritz Bunkus
}
}

foreach my $item (sort keys %taxaccounts) {
54e4131e Moritz Bunkus
$tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
d319704a Moritz Bunkus
9c63c160 Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase} }, $form->format_amount($myconfig, $taxbase{$item}, 2));
8461199d Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{taxbase_nofmt} }, $taxbase{$item});
9c63c160 Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{tax} }, $form->format_amount($myconfig, $taxamount, 2));
8461199d Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{tax_nofmt} }, $taxamount );
9c63c160 Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate} }, $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
8461199d Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{taxrate_nofmt} }, $form->{"${item}_rate"} * 100);
9c63c160 Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{taxdescription} }, $form->{"${item}_description"} . q{ } . 100 * $form->{"${item}_rate"} . q{%});
push(@{ $form->{TEMPLATE_ARRAYS}->{taxnumber} }, $form->{"${item}_taxnumber"});
d319704a Moritz Bunkus
}

for my $i (1 .. $form->{paidaccounts}) {
if ($form->{"paid_$i"}) {
532b0d4c Moritz Bunkus
my ($accno, $description) = split(/--/, $form->{"AR_paid_$i"});
9c63c160 Moritz Bunkus
push(@{ $form->{TEMPLATE_ARRAYS}->{payment} }, $form->{"paid_$i"});
push(@{ $form->{TEMPLATE_ARRAYS}->{paymentaccount} }, $description);
push(@{ $form->{TEMPLATE_ARRAYS}->{paymentdate} }, $form->{"datepaid_$i"});
push(@{ $form->{TEMPLATE_ARRAYS}->{paymentsource} }, $form->{"source_$i"});
push(@{ $form->{TEMPLATE_ARRAYS}->{paymentmemo} }, $form->{"memo_$i"});
d319704a Moritz Bunkus
$form->{paid} += $form->parse_amount($myconfig, $form->{"paid_$i"});
}
}
02aab73f Thomas Kasulke
if($form->{taxincluded}) {
8461199d Moritz Bunkus
$form->{subtotal} = $form->format_amount($myconfig, $form->{total} - $tax, 2);
1e26c0d4 Wulf Coulmann
$form->{subtotal_nofmt} = $form->{total} - $tax;
02aab73f Thomas Kasulke
}
else {
8461199d Moritz Bunkus
$form->{subtotal} = $form->format_amount($myconfig, $form->{total}, 2);
1e26c0d4 Wulf Coulmann
$form->{subtotal_nofmt} = $form->{total};
02aab73f Thomas Kasulke
}
d9c9bc22 Moritz Bunkus
54e4131e Moritz Bunkus
$form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
d9c9bc22 Moritz Bunkus
$form->{discount_total} = $form->format_amount($myconfig, $form->{discount_total}, 2);
$form->{nodiscount} = $form->format_amount($myconfig, $nodiscount, 2);
$form->{yesdiscount} = $form->format_amount($myconfig, $form->{nodiscount_total} - $nodiscount, 2);
54e4131e Moritz Bunkus
d9c9bc22 Moritz Bunkus
$form->{invtotal} = ($form->{taxincluded}) ? $form->{total} : $form->{total} + $tax;
$form->{total} = $form->format_amount($myconfig, $form->{invtotal} - $form->{paid}, 2);
b9b02c1a Philip Reetz
$form->{invtotal} = $form->format_amount($myconfig, $form->{invtotal}, 2);
d9c9bc22 Moritz Bunkus
$form->{paid} = $form->format_amount($myconfig, $form->{paid}, 2);

54e4131e Moritz Bunkus
$form->set_payment_options($myconfig, $form->{invdate});
d319704a Moritz Bunkus
$form->{username} = $myconfig->{name};

$main::lxdebug->leave_sub();
}

sub project_description {
$main::lxdebug->enter_sub();

my ($self, $dbh, $id) = @_;
b8da8785 Sven Schöling
my $form = \%main::form;
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
my $query = qq|SELECT description FROM project WHERE id = ?|;
my ($description) = selectrow_query($form, $dbh, $query, conv_i($id));
d319704a Moritz Bunkus
$main::lxdebug->leave_sub();

return $_;
}

sub customer_details {
$main::lxdebug->enter_sub();

f83b4aff Moritz Bunkus
my ($self, $myconfig, $form, @wanted_vars) = @_;
d319704a Moritz Bunkus
# connect to database
74b9dd67 Sven Schöling
my $dbh = $form->get_standard_dbh;
d319704a Moritz Bunkus
e09347c8 Geoffrey Richardson
my $language_id = $form->{language_id};

d319704a Moritz Bunkus
# get contact id, set it if nessessary
54e4131e Moritz Bunkus
$form->{cp_id} *= 1;
d319704a Moritz Bunkus
6ed3eaf6 Moritz Bunkus
my @values = (conv_i($form->{customer_id}));
532b0d4c Moritz Bunkus
my $where = "";
d319704a Moritz Bunkus
if ($form->{cp_id}) {
532b0d4c Moritz Bunkus
$where = qq| AND (cp.cp_id = ?) |;
push(@values, conv_i($form->{cp_id}));
d319704a Moritz Bunkus
}

# get rest for the customer
532b0d4c Moritz Bunkus
my $query =
qq|SELECT ct.*, cp.*, ct.notes as customernotes,
94802c79 Bernd Bleßmann
ct.phone AS customerphone, ct.fax AS customerfax, ct.email AS customeremail,
ct.curr AS currency
532b0d4c Moritz Bunkus
FROM customer ct
LEFT JOIN contacts cp on ct.id = cp.cp_cv_id
WHERE (ct.id = ?) $where
ORDER BY cp.cp_id
LIMIT 1|;
my $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
d319704a Moritz Bunkus
54e4131e Moritz Bunkus
# remove id and taxincluded before copy back
delete @$ref{qw(id taxincluded)};
f83b4aff Moritz Bunkus
d416d4c4 Moritz Bunkus
@wanted_vars = grep({ $_ } @wanted_vars);
f83b4aff Moritz Bunkus
if (scalar(@wanted_vars) > 0) {
my %h_wanted_vars;
map({ $h_wanted_vars{$_} = 1; } @wanted_vars);
map({ delete($ref->{$_}) unless ($h_wanted_vars{$_}); } keys(%{$ref}));
}

7d2455cf Stephan Köhler
map { $form->{$_} = $ref->{$_} } keys %$ref;
54e4131e Moritz Bunkus
94802c79 Bernd Bleßmann
# remove any trailing whitespace
$form->{currency} =~ s/\s*$// if ($form->{currency});

54e4131e Moritz Bunkus
if ($form->{delivery_customer_id}) {
532b0d4c Moritz Bunkus
$query =
qq|SELECT *, notes as customernotes
FROM customer
WHERE id = ?
LIMIT 1|;
$ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{delivery_customer_id}));
54e4131e Moritz Bunkus
map { $form->{"dc_$_"} = $ref->{$_} } keys %$ref;
}

if ($form->{delivery_vendor_id}) {
532b0d4c Moritz Bunkus
$query =
qq|SELECT *, notes as customernotes
FROM customer
WHERE id = ?
LIMIT 1|;
$ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{delivery_vendor_id}));
54e4131e Moritz Bunkus
map { $form->{"dv_$_"} = $ref->{$_} } keys %$ref;
}
8688e71e Moritz Bunkus
my $custom_variables = CVar->get_custom_variables('dbh' => $dbh,
'module' => 'CT',
'trans_id' => $form->{customer_id});
map { $form->{"vc_cvar_$_->{name}"} = $_->{value} } @{ $custom_variables };

e09347c8 Geoffrey Richardson
$form->{cp_greeting} = GenericTranslations->get('dbh' => $dbh,
'translation_type' => 'greetings::' . ($form->{cp_gender} eq 'f' ? 'female' : 'male'),
'language_id' => $language_id,
'allow_fallback' => 1);


d319704a Moritz Bunkus
$main::lxdebug->leave_sub();
}

sub post_invoice {
$main::lxdebug->enter_sub();
0bb0eb67 Stephan Köhler
5fdc44cb Moritz Bunkus
my ($self, $myconfig, $form, $provided_dbh, $payments_only) = @_;
d319704a Moritz Bunkus
# connect to database, turn off autocommit
6dcf04cf Moritz Bunkus
my $dbh = $provided_dbh ? $provided_dbh : $form->get_standard_dbh;
d319704a Moritz Bunkus
5fdc44cb Moritz Bunkus
my ($query, $sth, $null, $project_id, @values);
d319704a Moritz Bunkus
my $exchangerate = 0;

98452aaa Moritz Bunkus
my $ic_cvar_configs = CVar->get_configs(module => 'IC',
dbh => $dbh);

820545bc Moritz Bunkus
if (!$form->{employee_id}) {
d319704a Moritz Bunkus
$form->get_employee($dbh);
}
8fa48153 Sven Schöling
fb37acdc Moritz Bunkus
$form->{defaultcurrency} = $form->get_default_currency($myconfig);
0bbfb33b Jan Büren
# Seit neuestem wird die department_id schon übergeben UND $form->department nicht mehr
# korrekt zusammengebaut. Sehr wahrscheinlich beim Umstieg auf T8 kaputt gegangen
# Ich lass den Code von 2005 erstmal noch stehen ;-) jb 03-2011
if (!$form->{department_id}){
($null, $form->{department_id}) = split(/--/, $form->{department});
}
54e4131e Moritz Bunkus
532b0d4c Moritz Bunkus
my $all_units = AM->retrieve_units($myconfig, $form);
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
if (!$payments_only) {
if ($form->{id}) {
&reverse_invoice($dbh, $form);
1c084510 Moritz Bunkus
5fdc44cb Moritz Bunkus
} else {
6dcf04cf Moritz Bunkus
my $trans_number = SL::TransNumber->new(type => $form->{type}, dbh => $dbh, number => $form->{invnumber}, save => 1);
$form->{invnumber} = $trans_number->create_unique unless $trans_number->is_unique;

5fdc44cb Moritz Bunkus
$query = qq|SELECT nextval('glid')|;
($form->{"id"}) = selectrow_query($form, $dbh, $query);
d319704a Moritz Bunkus
5fdc44cb Moritz Bunkus
$query = qq|INSERT INTO ar (id, invnumber) VALUES (?, ?)|;
do_query($form, $dbh, $query, $form->{"id"}, $form->{"id"});
7712480e Moritz Bunkus
5fdc44cb Moritz Bunkus
if (!$form->{invnumber}) {
$form->{invnumber} =
$form->update_defaults($myconfig, $form->{type} eq "credit_note" ?
"cnnumber" : "invnumber", $dbh);
}
7712480e Moritz Bunkus
}
d319704a Moritz Bunkus
}

my ($netamount, $invoicediff) = (0, 0);
my ($amount, $linetotal, $lastincomeaccno);

5fdc44cb Moritz Bunkus
my ($currencies) = selectfirst_array_query($form, $dbh, qq|SELECT curr FROM defaults|);
my $defaultcurrency = (split m/:/, $currencies)[0];

if ($form->{currency} eq $defaultcurrency) {
d319704a Moritz Bunkus
$form->{exchangerate} = 1;
} else {
a2f07c15 Joachim Zach
$exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{invdate}, 'buy');
d319704a Moritz Bunkus
}

$form->{exchangerate} =
($exchangerate)
? $exchangerate
: $form->parse_amount($myconfig, $form->{exchangerate});

$form->{expense_inventory} = "";

532b0d4c Moritz Bunkus
my %baseunits;

1e251313 Moritz Bunkus
$form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
my %price_factors = map { $_->{id} => $_->{factor} } @{ $form->{ALL_PRICE_FACTORS} };
my $price_factor;

6078d376 Moritz Bunkus
$form->{amount} = {};
3b1eaa1a Moritz Bunkus
$form->{amount_cogs} = {};

d319704a Moritz Bunkus
foreach my $i (1 .. $form->{rowcount}) {
54e4131e Moritz Bunkus
if ($form->{type} eq "credit_note") {
$form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}) * -1;
532b0d4c Moritz Bunkus
$form->{shipped} = 1;
54e4131e Moritz Bunkus
} else {
$form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
}
my $basefactor;
b8da8785 Sven Schöling
my $baseqty;
54e4131e Moritz Bunkus
4d8a6515 Philip Reetz
$form->{"marge_percent_$i"} = $form->parse_amount($myconfig, $form->{"marge_percent_$i"}) * 1;
da804bf2 Geoffrey Richardson
$form->{"marge_absolut_$i"} = $form->parse_amount($myconfig, $form->{"marge_absolut_$i"}) * 1;
$form->{"lastcost_$i"} = $form->parse_amount($myconfig, $form->{"lastcost_$i"}) * 1;
4d8a6515 Philip Reetz
54e4131e Moritz Bunkus
if ($form->{storno}) {
$form->{"qty_$i"} *= -1;
}
d319704a Moritz Bunkus
8c89bb02 Moritz Bunkus
if ($form->{"id_$i"}) {
532b0d4c Moritz Bunkus
my $item_unit;
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
if (defined($baseunits{$form->{"id_$i"}})) {
$item_unit = $baseunits{$form->{"id_$i"}};
54e4131e Moritz Bunkus
} else {
532b0d4c Moritz Bunkus
# get item baseunit
$query = qq|SELECT unit FROM parts WHERE id = ?|;
($item_unit) = selectrow_query($form, $dbh, $query, conv_i($form->{"id_$i"}));
$baseunits{$form->{"id_$i"}} = $item_unit;
54e4131e Moritz Bunkus
}

532b0d4c Moritz Bunkus
if (defined($all_units->{$item_unit}->{factor})
&& ($all_units->{$item_unit}->{factor} ne '')
&& ($all_units->{$item_unit}->{factor} != 0)) {
$basefactor = $all_units->{$form->{"unit_$i"}}->{factor} / $all_units->{$item_unit}->{factor};
} else {
$basefactor = 1;
}
$baseqty = $form->{"qty_$i"} * $basefactor;
d319704a Moritz Bunkus
my ($allocated, $taxrate) = (0, 0);
my $taxamount;

d9c9bc22 Moritz Bunkus
# add tax rates
map { $taxrate += $form->{"${_}_rate"} } split(/ /, $form->{"taxaccounts_$i"});

d319704a Moritz Bunkus
# keep entered selling price
my $fxsellprice =
$form->parse_amount($myconfig, $form->{"sellprice_$i"});

my ($dec) = ($fxsellprice =~ /\.(\d+)/);
$dec = length $dec;
my $decimalplaces = ($dec > 2) ? $dec : 2;

d9c9bc22 Moritz Bunkus
# undo discount formatting
$form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
d319704a Moritz Bunkus
d9c9bc22 Moritz Bunkus
# deduct discount
$form->{"sellprice_$i"} = $fxsellprice * (1 - $form->{"discount_$i"});
d319704a Moritz Bunkus
# round linetotal to 2 decimal places
1e251313 Moritz Bunkus
$price_factor = $price_factors{ $form->{"price_factor_id_$i"} } || 1;
$linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2);
d319704a Moritz Bunkus
if ($form->{taxincluded}) {
$taxamount = $linetotal * ($taxrate / (1 + $taxrate));
$form->{"sellprice_$i"} =
$form->{"sellprice_$i"} * (1 / (1 + $taxrate));
} else {
$taxamount = $linetotal * $taxrate;
}

$netamount += $linetotal;

if ($taxamount != 0) {
map {
$form->{amount}{ $form->{id} }{$_} +=
$taxamount * $form->{"${_}_rate"} / $taxrate
532b0d4c Moritz Bunkus
} split(/ /, $form->{"taxaccounts_$i"});
d319704a Moritz Bunkus
}

# add amount to income, $form->{amount}{trans_id}{accno}
1e251313 Moritz Bunkus
$amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate} / $price_factor;
d319704a Moritz Bunkus
1e251313 Moritz Bunkus
$linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / $price_factor, 2) * $form->{exchangerate};
d319704a Moritz Bunkus
$linetotal = $form->round_amount($linetotal, 2);

# this is the difference from the inventory
$invoicediff += ($amount - $linetotal);

$form->{amount}{ $form->{id} }{ $form->{"income_accno_$i"} } +=
$linetotal;

$lastincomeaccno = $form->{"income_accno_$i"};

# adjust and round sellprice
$form->{"sellprice_$i"} =
$form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate},
$decimalplaces);

5fdc44cb Moritz Bunkus
next if $payments_only;

d319704a Moritz Bunkus
if ($form->{"inventory_accno_$i"} || $form->{"assembly_$i"}) {

if ($form->{"assembly_$i"}) {
# record assembly item as allocated
306fad80 Geoffrey Richardson
&process_assembly($dbh, $myconfig, $form, $form->{"id_$i"}, $baseqty);
bb439145 Moritz Bunkus
d319704a Moritz Bunkus
} else {
306fad80 Geoffrey Richardson
$allocated = &cogs($dbh, $myconfig, $form, $form->{"id_$i"}, $baseqty, $basefactor, $i);
d319704a Moritz Bunkus
}
}

604959de Moritz Bunkus
# get pricegroup_id and save it
532b0d4c Moritz Bunkus
($null, my $pricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
07d71c33 Stephan Köhler
$pricegroup_id *= 1;

98452aaa Moritz Bunkus
my ($invoice_id) = selectfirst_array_query($form, $dbh, qq|SELECT nextval('invoiceid')|);

d319704a Moritz Bunkus
# save detail record in invoice table
532b0d4c Moritz Bunkus
$query =
98452aaa Moritz Bunkus
qq|INSERT INTO invoice (id, trans_id, parts_id, description, longdescription, qty,
532b0d4c Moritz Bunkus
sellprice, fxsellprice, discount, allocated, assemblyitem,
unit, deliverydate, project_id, serialnumber, pricegroup_id,
4d8a6515 Philip Reetz
ordnumber, transdate, cusordnumber, base_qty, subtotal,
1e251313 Moritz Bunkus
marge_percent, marge_total, lastcost,
price_factor_id, price_factor, marge_price_factor)
98452aaa Moritz Bunkus
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
1e251313 Moritz Bunkus
(SELECT factor FROM price_factors WHERE id = ?), ?)|;
532b0d4c Moritz Bunkus
98452aaa Moritz Bunkus
@values = ($invoice_id, conv_i($form->{id}), conv_i($form->{"id_$i"}),
532b0d4c Moritz Bunkus
$form->{"description_$i"}, $form->{"longdescription_$i"}, $form->{"qty_$i"},
$form->{"sellprice_$i"}, $fxsellprice,
$form->{"discount_$i"}, $allocated, 'f',
ca57b730 Philip Reetz
$form->{"unit_$i"}, conv_date($form->{"reqdate_$i"}), conv_i($form->{"project_id_$i"}),
532b0d4c Moritz Bunkus
$form->{"serialnumber_$i"}, conv_i($pricegroup_id),
$form->{"ordnumber_$i"}, conv_date($form->{"transdate_$i"}),
33c46114 Moritz Bunkus
$form->{"cusordnumber_$i"}, $baseqty, $form->{"subtotal_$i"} ? 't' : 'f',
9c7c96a8 Sven Schöling
$form->{"marge_percent_$i"}, $form->{"marge_absolut_$i"},
1e251313 Moritz Bunkus
$form->{"lastcost_$i"},
conv_i($form->{"price_factor_id_$i"}), conv_i($form->{"price_factor_id_$i"}),
conv_i($form->{"marge_price_factor_$i"}));
532b0d4c Moritz Bunkus
do_query($form, $dbh, $query, @values);

98452aaa Moritz Bunkus
CVar->save_custom_variables(module => 'IC',
sub_module => 'invoice',
trans_id => $invoice_id,
configs => $ic_cvar_configs,
variables => $form,
name_prefix => 'ic_',
name_postfix => "_$i",
dbh => $dbh);
d319704a Moritz Bunkus
}
}

# total payments, don't move we need it here
for my $i (1 .. $form->{paidaccounts}) {
54e4131e Moritz Bunkus
if ($form->{type} eq "credit_note") {
$form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"}) * -1;
} else {
$form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
}
d319704a Moritz Bunkus
$form->{paid} += $form->{"paid_$i"};
$form->{datepaid} = $form->{"datepaid_$i"} if ($form->{"datepaid_$i"});
}

my ($tax, $diff) = (0, 0);

$netamount = $form->round_amount($netamount, 2);

# figure out rounding errors for total amount vs netamount + taxes
if ($form->{taxincluded}) {

$amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
$diff += $amount - $netamount * $form->{exchangerate};
$netamount = $amount;

532b0d4c Moritz Bunkus
foreach my $item (split(/ /, $form->{taxaccounts})) {
d319704a Moritz Bunkus
$amount = $form->{amount}{ $form->{id} }{$item} * $form->{exchangerate};
$form->{amount}{ $form->{id} }{$item} = $form->round_amount($amount, 2);
$tax += $form->{amount}{ $form->{id} }{$item};
$netamount -= $form->{amount}{ $form->{id} }{$item};
}

$invoicediff += $diff;
######## this only applies to tax included
if ($lastincomeaccno) {
$form->{amount}{ $form->{id} }{$lastincomeaccno} += $invoicediff;
}

} else {
$amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
$diff = $amount - $netamount * $form->{exchangerate};
$netamount = $amount;
532b0d4c Moritz Bunkus
foreach my $item (split(/ /, $form->{taxaccounts})) {
d319704a Moritz Bunkus
$form->{amount}{ $form->{id} }{$item} =
$form->round_amount($form->{amount}{ $form->{id} }{$item}, 2);
$amount =
$form->round_amount(
$form->{amount}{ $form->{id} }{$item} * $form->{exchangerate},
2);
$diff +=
$amount - $form->{amount}{ $form->{id} }{$item} *
$form->{exchangerate};
$form->{amount}{ $form->{id} }{$item} = $form->round_amount($amount, 2);
$tax += $form->{amount}{ $form->{id} }{$item};
}
}

$form->{amount}{ $form->{id} }{ $form->{AR} } = $netamount + $tax;
$form->{paid} =
$form->round_amount($form->{paid} * $form->{exchangerate} + $diff, 2);

# reverse AR
$form->{amount}{ $form->{id} }{ $form->{AR} } *= -1;

# update exchangerate
5fdc44cb Moritz Bunkus
if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
d319704a Moritz Bunkus
$form->update_exchangerate($dbh, $form->{currency}, $form->{invdate},
$form->{exchangerate}, 0);
}

d4651135 Moritz Bunkus
$project_id = conv_i($form->{"globalproject_id"});

3b1eaa1a Moritz Bunkus
foreach my $trans_id (keys %{ $form->{amount_cogs} }) {
foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
next unless ($form->{expense_inventory} =~ /\Q$accno\E/);

$form->{amount_cogs}{$trans_id}{$accno} = $form->round_amount($form->{amount_cogs}{$trans_id}{$accno}, 2);

if (!$payments_only && ($form->{amount_cogs}{$trans_id}{$accno} != 0)) {
$query =
qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, 0, ?)|;
@values = (conv_i($trans_id), $accno, $form->{amount_cogs}{$trans_id}{$accno}, conv_date($form->{invdate}), conv_i($project_id));
do_query($form, $dbh, $query, @values);
$form->{amount_cogs}{$trans_id}{$accno} = 0;
}
}

foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
$form->{amount_cogs}{$trans_id}{$accno} = $form->round_amount($form->{amount_cogs}{$trans_id}{$accno}, 2);

if (!$payments_only && ($form->{amount_cogs}{$trans_id}{$accno} != 0)) {
$query =
qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, 0, ?)|;
@values = (conv_i($trans_id), $accno, $form->{amount_cogs}{$trans_id}{$accno}, conv_date($form->{invdate}), conv_i($project_id));
do_query($form, $dbh, $query, @values);
}
}
}

d319704a Moritz Bunkus
foreach my $trans_id (keys %{ $form->{amount} }) {
foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
5cf977e5 Moritz Bunkus
next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
5fdc44cb Moritz Bunkus
$form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2);

if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
532b0d4c Moritz Bunkus
$query =
qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
(SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
@values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_i($project_id));
do_query($form, $dbh, $query, @values);
d319704a Moritz Bunkus
$form->{amount}{$trans_id}{$accno} = 0;
}
}

foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
5fdc44cb Moritz Bunkus
$form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2);

if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
532b0d4c Moritz Bunkus
$query =
qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
(SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
@values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_i($project_id));
do_query($form, $dbh, $query, @values);
d319704a Moritz Bunkus
}
}
}

# deduct payment differences from diff
for my $i (1 .. $form->{paidaccounts}) {
if ($form->{"paid_$i"} != 0) {
$amount =
$form->round_amount($form->{"paid_$i"} * $form->{exchangerate}, 2);
$diff -= $amount - $form->{"paid_$i"} * $form->{exchangerate};
}
}

# record payments and offsetting AR
54e4131e Moritz Bunkus
if (!$form->{storno}) {
for my $i (1 .. $form->{paidaccounts}) {
d729e328 Sven Schöling
f45b296f Bernd Bleßmann
if ($form->{"acc_trans_id_$i"}
&& $payments_only
97954312 Bernd Bleßmann
&& (SL::DB::Default->get->payments_changeable == 0)) {
f45b296f Bernd Bleßmann
next;
}
532b0d4c Moritz Bunkus
next if ($form->{"paid_$i"} == 0);

my ($accno) = split(/--/, $form->{"AR_paid_$i"});
$form->{"datepaid_$i"} = $form->{invdate}
unless ($form->{"datepaid_$i"});
$form->{datepaid} = $form->{"datepaid_$i"};

$exchangerate = 0;

5fdc44cb Moritz Bunkus
if ($form->{currency} eq $defaultcurrency) {
532b0d4c Moritz Bunkus
$form->{"exchangerate_$i"} = 1;
} else {
a53233e5 Sven Schöling
$exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy');
$form->{"exchangerate_$i"} = $exchangerate || $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
532b0d4c Moritz Bunkus
}

# record AR
$amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $diff, 2);

if ($form->{amount}{ $form->{id} }{ $form->{AR} } != 0) {
$query =
qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
(SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
@values = (conv_i($form->{"id"}), $form->{AR}, $amount, $form->{"datepaid_$i"}, $form->{AR}, $project_id);
do_query($form, $dbh, $query, @values);
}

# record payment
$form->{"paid_$i"} *= -1;
f45b296f Bernd Bleßmann
my $gldate = (conv_date($form->{"gldate_$i"}))? conv_date($form->{"gldate_$i"}) : conv_date($form->current_date($myconfig));
532b0d4c Moritz Bunkus
$query =
f45b296f Bernd Bleßmann
qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, gldate, source, memo, taxkey, project_id)
VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, ?, ?, ?,
532b0d4c Moritz Bunkus
(SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
@values = (conv_i($form->{"id"}), $accno, $form->{"paid_$i"}, $form->{"datepaid_$i"},
f45b296f Bernd Bleßmann
$gldate, $form->{"source_$i"}, $form->{"memo_$i"}, $accno, $project_id);
532b0d4c Moritz Bunkus
do_query($form, $dbh, $query, @values);

# exchangerate difference
$form->{fx}{$accno}{ $form->{"datepaid_$i"} } +=
3ff5da55 Niclas Zimmermann
$form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $diff;
532b0d4c Moritz Bunkus
# gain/loss
$amount =
3ff5da55 Niclas Zimmermann
$form->{"paid_$i"} * $form->{exchangerate} - $form->{"paid_$i"} *
$form->{"exchangerate_$i"};
532b0d4c Moritz Bunkus
if ($amount > 0) {
3ff5da55 Niclas Zimmermann
$form->{fx}{ $form->{fxgain_accno} }{ $form->{"datepaid_$i"} } += $amount;
532b0d4c Moritz Bunkus
} else {
3ff5da55 Niclas Zimmermann
$form->{fx}{ $form->{fxloss_accno} }{ $form->{"datepaid_$i"} } += $amount;
532b0d4c Moritz Bunkus
}

$diff = 0;

# update exchange rate
5fdc44cb Moritz Bunkus
if (($form->{currency} ne $defaultcurrency) && !$exchangerate) {
532b0d4c Moritz Bunkus
$form->update_exchangerate($dbh, $form->{currency},
$form->{"datepaid_$i"},
$form->{"exchangerate_$i"}, 0);
d319704a Moritz Bunkus
}
}
8ca54430 Moritz Bunkus
} else { # if (!$form->{storno})
$form->{marge_total} *= -1;
d319704a Moritz Bunkus
}

40c2c37c Moritz Bunkus
IO->set_datepaid(table => 'ar', id => $form->{id}, dbh => $dbh);

d319704a Moritz Bunkus
# record exchange rate differences and gains/losses
foreach my $accno (keys %{ $form->{fx} }) {
foreach my $transdate (keys %{ $form->{fx}{$accno} }) {
3ff5da55 Niclas Zimmermann
$form->{fx}{$accno}{$transdate} = $form->round_amount($form->{fx}{$accno}{$transdate}, 2);
if ( $form->{fx}{$accno}{$transdate} != 0 ) {
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
$query =
qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, cleared, fx_transaction, taxkey, project_id)
VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, '0', '1',
(SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
3ff5da55 Niclas Zimmermann
@values = (conv_i($form->{"id"}), $accno, $form->{fx}{$accno}{$transdate}, conv_date($transdate), $accno, conv_i($project_id));
532b0d4c Moritz Bunkus
do_query($form, $dbh, $query, @values);
d319704a Moritz Bunkus
}
}
}

3ff5da55 Niclas Zimmermann
if ($payments_only) {
$query = qq|UPDATE ar SET paid = ? WHERE id = ?|;
do_query($form, $dbh, $query, $form->{paid}, conv_i($form->{id}));

$dbh->commit if !$provided_dbh;

$main::lxdebug->leave_sub();
return;
}

d319704a Moritz Bunkus
$amount = $netamount + $tax;

# save AR record
d4bddbd1 Geoffrey Richardson
#erweiterung fuer lieferscheinnummer (donumber) 12.02.09 jb

d319704a Moritz Bunkus
$query = qq|UPDATE ar set
a05eead3 Sven Schöling
invnumber = ?, ordnumber = ?, quonumber = ?, cusordnumber = ?,
transdate = ?, orddate = ?, quodate = ?, customer_id = ?,
40c2c37c Moritz Bunkus
amount = ?, netamount = ?, paid = ?,
a05eead3 Sven Schöling
duedate = ?, deliverydate = ?, invoice = ?, shippingpoint = ?,
shipvia = ?, terms = ?, notes = ?, intnotes = ?,
curr = ?, department_id = ?, payment_id = ?, taxincluded = ?,
type = ?, language_id = ?, taxzone_id = ?, shipto_id = ?,
employee_id = ?, salesman_id = ?, storno_id = ?, storno = ?,
8fa48153 Sven Schöling
cp_id = ?, marge_total = ?, marge_percent = ?,
a05eead3 Sven Schöling
globalproject_id = ?, delivery_customer_id = ?,
d4bddbd1 Geoffrey Richardson
transaction_description = ?, delivery_vendor_id = ?,
2c447b2f Jan Büren
donumber = ?, invnumber_for_credit_note = ?
532b0d4c Moritz Bunkus
WHERE id = ?|;
a05eead3 Sven Schöling
@values = ( $form->{"invnumber"}, $form->{"ordnumber"}, $form->{"quonumber"}, $form->{"cusordnumber"},
8fa48153 Sven Schöling
conv_date($form->{"invdate"}), conv_date($form->{"orddate"}), conv_date($form->{"quodate"}), conv_i($form->{"customer_id"}),
bf042408 Sven Schöling
$amount, $netamount, $form->{"paid"},
a05eead3 Sven Schöling
conv_date($form->{"duedate"}), conv_date($form->{"deliverydate"}), '1', $form->{"shippingpoint"},
$form->{"shipvia"}, conv_i($form->{"terms"}), $form->{"notes"}, $form->{"intnotes"},
$form->{"currency"}, conv_i($form->{"department_id"}), conv_i($form->{"payment_id"}), $form->{"taxincluded"} ? 't' : 'f',
$form->{"type"}, conv_i($form->{"language_id"}), conv_i($form->{"taxzone_id"}), conv_i($form->{"shipto_id"}),
8fa48153 Sven Schöling
conv_i($form->{"employee_id"}), conv_i($form->{"salesman_id"}), conv_i($form->{storno_id}), $form->{"storno"} ? 't' : 'f',
a05eead3 Sven Schöling
conv_i($form->{"cp_id"}), 1 * $form->{marge_total} , 1 * $form->{marge_percent},
8fa48153 Sven Schöling
conv_i($form->{"globalproject_id"}), conv_i($form->{"delivery_customer_id"}),
a05eead3 Sven Schöling
$form->{transaction_description}, conv_i($form->{"delivery_vendor_id"}),
2c447b2f Jan Büren
$form->{"donumber"}, $form->{"invnumber_for_credit_note"},
a05eead3 Sven Schöling
conv_i($form->{"id"}));
532b0d4c Moritz Bunkus
do_query($form, $dbh, $query, @values);
8fa48153 Sven Schöling

54e4131e Moritz Bunkus
if ($form->{storno}) {
532b0d4c Moritz Bunkus
$query =
qq!UPDATE ar SET
paid = paid + amount,
storno = 't',
intnotes = ? || intnotes
WHERE id = ?!;
do_query($form, $dbh, $query, "Rechnung storniert am $form->{invdate} ", conv_i($form->{"storno_id"}));
do_query($form, $dbh, qq|UPDATE ar SET paid = amount WHERE id = ?|, conv_i($form->{"id"}));
54e4131e Moritz Bunkus
}

d319704a Moritz Bunkus
# add shipto
$form->{name} = $form->{customer};
5cf977e5 Moritz Bunkus
$form->{name} =~ s/--\Q$form->{customer_id}\E//;
54e4131e Moritz Bunkus
if (!$form->{shipto_id}) {
$form->add_shipto($dbh, $form->{id}, "AR");
}
d319704a Moritz Bunkus
# save printed, emailed and queued
$form->save_status($dbh);

be6f6cfd Moritz Bunkus
Common::webdav_folder($form);
d319704a Moritz Bunkus
94e11003 Moritz Bunkus
# Link this record to the records it was created from.
RecordLinks->create_links('dbh' => $dbh,
'mode' => 'ids',
'from_table' => 'oe',
'from_ids' => $form->{convert_from_oe_ids},
'to_table' => 'ar',
'to_id' => $form->{id},
);
delete $form->{convert_from_oe_ids};

my @convert_from_do_ids = map { $_ * 1 } grep { $_ } split m/\s+/, $form->{convert_from_do_ids};

if (scalar @convert_from_do_ids) {
3c1ceacd Moritz Bunkus
DO->close_orders('dbh' => $dbh,
94e11003 Moritz Bunkus
'ids' => \@convert_from_do_ids);

RecordLinks->create_links('dbh' => $dbh,
'mode' => 'ids',
'from_table' => 'delivery_orders',
'from_ids' => \@convert_from_do_ids,
'to_table' => 'ar',
'to_id' => $form->{id},
);
3c1ceacd Moritz Bunkus
}
247a26dc Moritz Bunkus
delete $form->{convert_from_do_ids};

ARAP->close_orders_if_billed('dbh' => $dbh,
'arap_id' => $form->{id},
'table' => 'ar',);
3c1ceacd Moritz Bunkus
7e7a1369 Sven Schöling
# safety check datev export
if ($::lx_office_conf{datev_check}{check_on_sales_invoice}) {
my $transdate = $::form->{invdate} ? DateTime->from_lxoffice($::form->{invdate}) : undef;
$transdate ||= DateTime->today;

my $datev = SL::DATEV->new(
exporttype => DATEV_ET_BUCHUNGEN,
format => DATEV_FORMAT_KNE,
dbh => $dbh,
from => $transdate,
to => $transdate,
);

$datev->export;

if ($datev->errors) {
$dbh->rollback;
die join "\n", $::locale->text('DATEV check returned errors:'), $datev->errors;
}
}

5fdc44cb Moritz Bunkus
my $rc = 1;
864a3244 Moritz Bunkus
$dbh->commit if !$provided_dbh;
d319704a Moritz Bunkus
$main::lxdebug->leave_sub();

return $rc;
}

5fdc44cb Moritz Bunkus
sub _delete_payments {
$main::lxdebug->enter_sub();
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
my ($self, $form, $dbh) = @_;
54e4131e Moritz Bunkus
6ff01fdb Moritz Bunkus
my @delete_acc_trans_ids;
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
# Delete old payment entries from acc_trans.
my $query =
6ff01fdb Moritz Bunkus
qq|SELECT acc_trans_id
5fdc44cb Moritz Bunkus
FROM acc_trans
WHERE (trans_id = ?) AND fx_transaction

UNION

6ff01fdb Moritz Bunkus
SELECT at.acc_trans_id
5fdc44cb Moritz Bunkus
FROM acc_trans at
LEFT JOIN chart c ON (at.chart_id = c.id)
WHERE (trans_id = ?) AND (c.link LIKE '%AR_paid%')|;
6ff01fdb Moritz Bunkus
push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}), conv_i($form->{id}));
5fdc44cb Moritz Bunkus
$query =
6ff01fdb Moritz Bunkus
qq|SELECT at.acc_trans_id
5fdc44cb Moritz Bunkus
FROM acc_trans at
LEFT JOIN chart c ON (at.chart_id = c.id)
WHERE (trans_id = ?)
AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
6ff01fdb Moritz Bunkus
ORDER BY at.acc_trans_id
5fdc44cb Moritz Bunkus
OFFSET 1|;
6ff01fdb Moritz Bunkus
push @delete_acc_trans_ids, selectall_array_query($form, $dbh, $query, conv_i($form->{id}));
5fdc44cb Moritz Bunkus
6ff01fdb Moritz Bunkus
if (@delete_acc_trans_ids) {
$query = qq|DELETE FROM acc_trans WHERE acc_trans_id IN (| . join(", ", @delete_acc_trans_ids) . qq|)|;
5fdc44cb Moritz Bunkus
do_query($form, $dbh, $query);
1c084510 Moritz Bunkus
}
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
$main::lxdebug->leave_sub();
}
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
sub post_payment {
$main::lxdebug->enter_sub();
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
my ($self, $myconfig, $form, $locale) = @_;
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
# connect to database, turn off autocommit
74b9dd67 Sven Schöling
my $dbh = $form->get_standard_dbh;
$dbh->begin_work;
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
my (%payments, $old_form, $row, $item, $query, %keep_vars);
532b0d4c Moritz Bunkus
5fdc44cb Moritz Bunkus
$old_form = save_form();
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
# Delete all entries in acc_trans from prior payments.
97954312 Bernd Bleßmann
if (SL::DB::Default->get->payments_changeable != 0) {
f45b296f Bernd Bleßmann
$self->_delete_payments($form, $dbh);
}
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
# Save the new payments the user made before cleaning up $form.
f45b296f Bernd Bleßmann
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 };
529c6ea4 Sven Schöling
5fdc44cb Moritz Bunkus
# Clean up $form so that old content won't tamper the results.
%keep_vars = map { $_, 1 } qw(login password id);
map { delete $form->{$_} unless $keep_vars{$_} } keys %{ $form };
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
# Retrieve the invoice from the database.
$self->retrieve_invoice($myconfig, $form);
529c6ea4 Sven Schöling
9c5108ec Moritz Bunkus
# Set up the content of $form in the way that IS::post_invoice() expects.
5fdc44cb Moritz Bunkus
$form->{exchangerate} = $form->format_amount($myconfig, $form->{exchangerate});
529c6ea4 Sven Schöling
5fdc44cb Moritz Bunkus
for $row (1 .. scalar @{ $form->{invoice_details} }) {
$item = $form->{invoice_details}->[$row - 1];

map { $item->{$_} = $form->format_amount($myconfig, $item->{$_}) } qw(qty sellprice discount);

map { $form->{"${_}_${row}"} = $item->{$_} } keys %{ $item };
1c084510 Moritz Bunkus
}
548f4467 Moritz Bunkus
5fdc44cb Moritz Bunkus
$form->{rowcount} = scalar @{ $form->{invoice_details} };
548f4467 Moritz Bunkus
5fdc44cb Moritz Bunkus
delete @{$form}{qw(invoice_details paidaccounts storno paid)};
548f4467 Moritz Bunkus
5fdc44cb Moritz Bunkus
# Restore the payment options from the user input.
map { $form->{$_} = $payments{$_} } keys %payments;
54e4131e Moritz Bunkus
6bd1a382 Moritz Bunkus
# Get the AR accno (which is normally done by Form::create_links()).
5fdc44cb Moritz Bunkus
$query =
qq|SELECT c.accno
FROM acc_trans at
LEFT JOIN chart c ON (at.chart_id = c.id)
WHERE (trans_id = ?)
AND ((c.link = 'AR') OR (c.link LIKE '%:AR') OR (c.link LIKE 'AR:%'))
6ff01fdb Moritz Bunkus
ORDER BY at.acc_trans_id
5fdc44cb Moritz Bunkus
LIMIT 1|;
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
($form->{AR}) = selectfirst_array_query($form, $dbh, $query, conv_i($form->{id}));
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
# Post the new payments.
$self->post_invoice($myconfig, $form, $dbh, 1);

restore_form($old_form);
54e4131e Moritz Bunkus
5fdc44cb Moritz Bunkus
my $rc = $dbh->commit();

$main::lxdebug->leave_sub();

return $rc;
54e4131e Moritz Bunkus
}

d319704a Moritz Bunkus
sub process_assembly {
$main::lxdebug->enter_sub();

306fad80 Geoffrey Richardson
my ($dbh, $myconfig, $form, $id, $totalqty) = @_;
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
my $query =
qq|SELECT a.parts_id, a.qty, p.assembly, p.partnumber, p.description, p.unit,
p.inventory_accno_id, p.income_accno_id, p.expense_accno_id
FROM assembly a
JOIN parts p ON (a.parts_id = p.id)
WHERE (a.id = ?)|;
my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
d319704a Moritz Bunkus
b8da8785 Sven Schöling
while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
d319704a Moritz Bunkus
my $allocated = 0;

$ref->{inventory_accno_id} *= 1;
$ref->{expense_accno_id} *= 1;

# multiply by number of assemblies
$ref->{qty} *= $totalqty;

if ($ref->{assembly}) {
306fad80 Geoffrey Richardson
&process_assembly($dbh, $myconfig, $form, $ref->{parts_id}, $ref->{qty});
d319704a Moritz Bunkus
next;
} else {
if ($ref->{inventory_accno_id}) {
306fad80 Geoffrey Richardson
$allocated = &cogs($dbh, $myconfig, $form, $ref->{parts_id}, $ref->{qty});
d319704a Moritz Bunkus
}
}

# save detail record for individual assembly item in invoice table
532b0d4c Moritz Bunkus
$query =
qq|INSERT INTO invoice (trans_id, description, parts_id, qty, sellprice, fxsellprice, allocated, assemblyitem, unit)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)|;
b8da8785 Sven Schöling
my @values = (conv_i($form->{id}), $ref->{description}, conv_i($ref->{parts_id}), $ref->{qty}, 0, 0, $allocated, 't', $ref->{unit});
532b0d4c Moritz Bunkus
do_query($form, $dbh, $query, @values);
d319704a Moritz Bunkus
}

$sth->finish;

$main::lxdebug->leave_sub();
}

sub cogs {
$main::lxdebug->enter_sub();

306fad80 Geoffrey Richardson
# adjust allocated in table invoice according to FIFO princicple
# for a certain part with part_id $id

my ($dbh, $myconfig, $form, $id, $totalqty, $basefactor, $row) = @_;
c2f2c60e Sven Schöling
$basefactor ||= 1;

fe3df360 Philip Reetz
$form->{taxzone_id} *=1;
532b0d4c Moritz Bunkus
my $transdate = $form->{invdate} ? $dbh->quote($form->{invdate}) : "current_date";
my $taxzone_id = $form->{"taxzone_id"} * 1;
my $query =
2952e413 Geoffrey Richardson
qq|SELECT i.id, i.trans_id, i.base_qty, i.allocated, i.sellprice, i.price_factor,
b3327c52 Sven Schöling
c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
c2.accno AS income_accno, c2.new_chart_id AS income_new_chart, date($transdate) - c2.valid_from AS income_valid,
c3.accno AS expense_accno, c3.new_chart_id AS expense_new_chart, date($transdate) - c3.valid_from AS expense_valid
532b0d4c Moritz Bunkus
FROM invoice i, parts p
LEFT JOIN chart c1 ON ((SELECT inventory_accno_id FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
LEFT JOIN chart c3 ON ((select expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)
WHERE (i.parts_id = p.id)
AND (i.parts_id = ?)
AND ((i.base_qty + i.allocated) < 0)
ORDER BY trans_id|;
my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
d319704a Moritz Bunkus
my $allocated = 0;
my $qty;

43f9b1c5 Geoffrey Richardson
# all invoice entries of an example part:

5074cc50 Moritz Bunkus
# id | trans_id | base_qty | allocated | sellprice | inventory_accno | income_accno | expense_accno
43f9b1c5 Geoffrey Richardson
# ---+----------+----------+-----------+-----------+-----------------+--------------+---------------
# 4 | 4 | -5 | 5 | 20.00000 | 1140 | 4400 | 5400 bought 5 for 20
# 5 | 5 | 4 | -4 | 50.00000 | 1140 | 4400 | 5400 sold 4 for 50
# 6 | 6 | 1 | -1 | 50.00000 | 1140 | 4400 | 5400 sold 1 for 50
# 7 | 7 | -5 | 1 | 20.00000 | 1140 | 4400 | 5400 bought 5 for 20
# 8 | 8 | 1 | -1 | 50.00000 | 1140 | 4400 | 5400 sold 1 for 50

# 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
# and all parts have been allocated

# so transaction 8 only sees transaction 7 with unallocated parts and adjusts allocated for that transaction, before allocated was 0
# 7 | 7 | -5 | 1 | 20.00000 | 1140 | 4400 | 5400 bought 5 for 20

# in this example there are still 4 unsold articles


# search all invoice entries for the part in question, adjusting "allocated"
# until the total number of sold parts has been reached

# ORDER BY trans_id ensures FIFO


b8da8785 Sven Schöling
while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
54e4131e Moritz Bunkus
if (($qty = (($ref->{base_qty} * -1) - $ref->{allocated})) > $totalqty) {
d319704a Moritz Bunkus
$qty = $totalqty;
}

43f9b1c5 Geoffrey Richardson
# update allocated in invoice
532b0d4c Moritz Bunkus
$form->update_balance($dbh, "invoice", "allocated", qq|id = $ref->{id}|, $qty);
d319704a Moritz Bunkus
# total expenses and inventory
# sellprice is the cost of the item
961adb71 Sven Schöling
my $linetotal = $form->round_amount(($ref->{sellprice} * $qty) / ( ($ref->{price_factor} || 1) * ( $basefactor || 1 )), 2);
d319704a Moritz Bunkus
43f9b1c5 Geoffrey Richardson
if ( $::instance_conf->get_inventory_system eq 'perpetual' ) {
# Bestandsmethode: when selling parts, deduct their purchase value from the inventory account
fe3df360 Philip Reetz
$ref->{expense_accno} = ($form->{"expense_accno_$row"}) ? $form->{"expense_accno_$row"} : $ref->{expense_accno};
d319704a Moritz Bunkus
# add to expense
3b1eaa1a Moritz Bunkus
$form->{amount_cogs}{ $form->{id} }{ $ref->{expense_accno} } += -$linetotal;
d319704a Moritz Bunkus
$form->{expense_inventory} .= " " . $ref->{expense_accno};
fe3df360 Philip Reetz
$ref->{inventory_accno} = ($form->{"inventory_accno_$row"}) ? $form->{"inventory_accno_$row"} : $ref->{inventory_accno};
d319704a Moritz Bunkus
# deduct inventory
3b1eaa1a Moritz Bunkus
$form->{amount_cogs}{ $form->{id} }{ $ref->{inventory_accno} } -= -$linetotal;
d319704a Moritz Bunkus
$form->{expense_inventory} .= " " . $ref->{inventory_accno};
}

# add allocated
532b0d4c Moritz Bunkus
$allocated -= $qty;
d319704a Moritz Bunkus
last if (($totalqty -= $qty) <= 0);
}

$sth->finish;

$main::lxdebug->leave_sub();

return $allocated;
}

sub reverse_invoice {
$main::lxdebug->enter_sub();

my ($dbh, $form) = @_;

# reverse inventory items
532b0d4c Moritz Bunkus
my $query =
qq|SELECT i.id, i.parts_id, i.qty, i.assemblyitem, p.assembly, p.inventory_accno_id
FROM invoice i
JOIN parts p ON (i.parts_id = p.id)
WHERE i.trans_id = ?|;
my $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{"id"}));
d319704a Moritz Bunkus
b8da8785 Sven Schöling
while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
d319704a Moritz Bunkus
83914eeb Moritz Bunkus
if ($ref->{inventory_accno_id}) {
d319704a Moritz Bunkus
# de-allocated purchases
532b0d4c Moritz Bunkus
$query =
qq|SELECT i.id, i.trans_id, i.allocated
FROM invoice i
WHERE (i.parts_id = ?) AND (i.allocated > 0)
ORDER BY i.trans_id DESC|;
my $sth2 = prepare_execute_query($form, $dbh, $query, conv_i($ref->{"parts_id"}));

b8da8785 Sven Schöling
while (my $inhref = $sth2->fetchrow_hashref('NAME_lc')) {
my $qty = $ref->{qty};
d319704a Moritz Bunkus
if (($ref->{qty} - $inhref->{allocated}) > 0) {
$qty = $inhref->{allocated};
}

# update invoice
532b0d4c Moritz Bunkus
$form->update_balance($dbh, "invoice", "allocated", qq|id = $inhref->{id}|, $qty * -1);
d319704a Moritz Bunkus
last if (($ref->{qty} -= $qty) <= 0);
}
532b0d4c Moritz Bunkus
$sth2->finish;
d319704a Moritz Bunkus
}
}

$sth->finish;

# delete acc_trans
b8da8785 Sven Schöling
my @values = (conv_i($form->{id}));
532b0d4c Moritz Bunkus
do_query($form, $dbh, qq|DELETE FROM acc_trans WHERE trans_id = ?|, @values);
do_query($form, $dbh, qq|DELETE FROM invoice WHERE trans_id = ?|, @values);
do_query($form, $dbh, qq|DELETE FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|, @values);
d319704a Moritz Bunkus
$main::lxdebug->leave_sub();
}

sub delete_invoice {
$main::lxdebug->enter_sub();

8cd05ad6 Moritz Bunkus
my ($self, $myconfig, $form) = @_;
d319704a Moritz Bunkus
# connect to database
74b9dd67 Sven Schöling
my $dbh = $form->get_standard_dbh;
$dbh->begin_work;
d319704a Moritz Bunkus
&reverse_invoice($dbh, $form);

532b0d4c Moritz Bunkus
my @values = (conv_i($form->{id}));

dd27c969 Jan Büren
# Falls wir ein Storno haben, müssen zwei Felder in der stornierten Rechnung wieder
# zurückgesetzt werden. Vgl:
864a3244 Moritz Bunkus
# id | storno | storno_id | paid | amount
dd27c969 Jan Büren
#----+--------+-----------+---------+-----------
# 18 | f | | 0.00000 | 119.00000
# ZU:
# 18 | t | | 119.00000 | 119.00000
#
if($form->{storno}){
# storno_id auslesen und korrigieren
my ($invoice_id) = selectfirst_array_query($form, $dbh, qq|SELECT storno_id FROM ar WHERE id = ?|,@values);
do_query($form, $dbh, qq|UPDATE ar SET storno = 'f', paid = 0 WHERE id = ?|, $invoice_id);
}

d319704a Moritz Bunkus
# delete spool files
532b0d4c Moritz Bunkus
my @spoolfiles = selectall_array_query($form, $dbh, qq|SELECT spoolfile FROM status WHERE trans_id = ?|, @values);
d319704a Moritz Bunkus
bc88a0d1 Moritz Bunkus
my @queries = (
qq|DELETE FROM status WHERE trans_id = ?|,
qq|DELETE FROM periodic_invoices WHERE ar_id = ?|,
qq|DELETE FROM ar WHERE id = ?|,
);

map { do_query($form, $dbh, $_, @values) } @queries;
d319704a Moritz Bunkus
my $rc = $dbh->commit;

if ($rc) {
8cd05ad6 Moritz Bunkus
my $spool = $::lx_office_conf{paths}->{spool};
b8da8785 Sven Schöling
map { unlink "$spool/$_" if -f "$spool/$_"; } @spoolfiles;
d319704a Moritz Bunkus
}

$main::lxdebug->leave_sub();

return $rc;
}

sub retrieve_invoice {
$main::lxdebug->enter_sub();
0bb0eb67 Stephan Köhler
d319704a Moritz Bunkus
my ($self, $myconfig, $form) = @_;

# connect to database
9c7c96a8 Sven Schöling
my $dbh = $form->get_standard_dbh;
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
my ($sth, $ref, $query);

74fca575 Sven Schöling
my $query_transdate = !$form->{id} ? ", current_date AS invdate" : '';
532b0d4c Moritz Bunkus
$query =
qq|SELECT
7eae8fac Moritz Bunkus
(SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno,
(SELECT c.accno FROM chart c WHERE d.income_accno_id = c.id) AS income_accno,
(SELECT c.accno FROM chart c WHERE d.expense_accno_id = c.id) AS expense_accno,
(SELECT c.accno FROM chart c WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
(SELECT c.accno FROM chart c WHERE d.fxloss_accno_id = c.id) AS fxloss_accno,
532b0d4c Moritz Bunkus
d.curr AS currencies
${query_transdate}
FROM defaults d|;

$ref = selectfirst_hashref_query($form, $dbh, $query);
map { $form->{$_} = $ref->{$_} } keys %{ $ref };
d319704a Moritz Bunkus
if ($form->{id}) {
532b0d4c Moritz Bunkus
my $id = conv_i($form->{id});
d319704a Moritz Bunkus
# retrieve invoice
d4bddbd1 Geoffrey Richardson
#erweiterung um das entsprechende feld lieferscheinnummer (a.donumber) in der html-maske anzuzeigen 12.02.2009 jb

532b0d4c Moritz Bunkus
$query =
qq|SELECT
a.invnumber, a.ordnumber, a.quonumber, a.cusordnumber,
a.orddate, a.quodate, a.globalproject_id,
a.transdate AS invdate, a.deliverydate, a.paid, a.storno, a.gldate,
a.shippingpoint, a.shipvia, a.terms, a.notes, a.intnotes, a.taxzone_id,
a.duedate, a.taxincluded, a.curr AS currency, a.shipto_id, a.cp_id,
a.employee_id, a.salesman_id, a.payment_id,
a.language_id, a.delivery_customer_id, a.delivery_vendor_id, a.type,
2c447b2f Jan Büren
a.transaction_description, a.donumber, a.invnumber_for_credit_note,
8ca54430 Moritz Bunkus
a.marge_total, a.marge_percent,
2c447b2f Jan Büren
e.name AS employee
532b0d4c Moritz Bunkus
FROM ar a
LEFT JOIN employee e ON (e.id = a.employee_id)
WHERE a.id = ?|;
$ref = selectfirst_hashref_query($form, $dbh, $query, $id);
map { $form->{$_} = $ref->{$_} } keys %{ $ref };
d319704a Moritz Bunkus
8add0ccd Bernd Bleßmann
# remove any trailing whitespace
$form->{currency} =~ s/\s*$//;
d319704a Moritz Bunkus
52983c08 Sven Schöling
$form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "buy");
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
# get shipto
$query = qq|SELECT * FROM shipto WHERE (trans_id = ?) AND (module = 'AR')|;
$ref = selectfirst_hashref_query($form, $dbh, $query, $id);
delete $ref->{id};
map { $form->{$_} = $ref->{$_} } keys %{ $ref };

foreach my $vc (qw(customer vendor)) {
next if !$form->{"delivery_${vc}_id"};
52983c08 Sven Schöling
($form->{"delivery_${vc}_string"}) = selectrow_query($form, $dbh, qq|SELECT name FROM customer WHERE id = ?|, $id);
54e4131e Moritz Bunkus
}

d319704a Moritz Bunkus
# get printed, emailed
52983c08 Sven Schöling
$query = qq|SELECT printed, emailed, spoolfile, formname FROM status WHERE trans_id = ?|;
532b0d4c Moritz Bunkus
$sth = prepare_execute_query($form, $dbh, $query, $id);
d319704a Moritz Bunkus
b8da8785 Sven Schöling
while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
d319704a Moritz Bunkus
$form->{printed} .= "$ref->{formname} " if $ref->{printed};
$form->{emailed} .= "$ref->{formname} " if $ref->{emailed};
52983c08 Sven Schöling
$form->{queued} .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile};
d319704a Moritz Bunkus
}
$sth->finish;
map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);

52983c08 Sven Schöling
my $transdate = $form->{deliverydate} ? $dbh->quote($form->{deliverydate})
: $form->{invdate} ? $dbh->quote($form->{invdate})
: "current_date";
8fa48153 Sven Schöling
532b0d4c Moritz Bunkus
my $taxzone_id = $form->{taxzone_id} *= 1;
$taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);
54e4131e Moritz Bunkus
d319704a Moritz Bunkus
# retrieve individual items
532b0d4c Moritz Bunkus
$query =
qq|SELECT
52983c08 Sven Schöling
c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from AS inventory_valid,
c2.accno AS income_accno, c2.new_chart_id AS income_new_chart, date($transdate) - c2.valid_from as income_valid,
c3.accno AS expense_accno, c3.new_chart_id AS expense_new_chart, date($transdate) - c3.valid_from AS expense_valid,
532b0d4c Moritz Bunkus
98452aaa Moritz Bunkus
i.id AS invoice_id,
ca57b730 Philip Reetz
i.description, i.longdescription, i.qty, i.fxsellprice AS sellprice, i.discount, i.parts_id AS id, i.unit, i.deliverydate AS reqdate,
52983c08 Sven Schöling
i.project_id, i.serialnumber, i.id AS invoice_pos, i.pricegroup_id, i.ordnumber, i.transdate, i.cusordnumber, i.subtotal, i.lastcost,
1e251313 Moritz Bunkus
i.price_factor_id, i.price_factor, i.marge_price_factor,
64515aa9 Bernd Bleßmann
p.partnumber, p.assembly, p.bin, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id, p.formel, p.listprice,
52983c08 Sven Schöling
pr.projectnumber, pg.partsgroup, prg.pricegroup
532b0d4c Moritz Bunkus
FROM invoice i
LEFT JOIN parts p ON (i.parts_id = p.id)
LEFT JOIN project pr ON (i.project_id = pr.id)
LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
LEFT JOIN pricegroup prg ON (i.pricegroup_id = prg.id)

52983c08 Sven Schöling
LEFT JOIN chart c1 ON ((SELECT inventory_accno_id FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c1.id)
LEFT JOIN chart c2 ON ((SELECT income_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c2.id)
LEFT JOIN chart c3 ON ((SELECT expense_accno_id_${taxzone_id} FROM buchungsgruppen WHERE id = p.buchungsgruppen_id) = c3.id)

WHERE (i.trans_id = ?) AND NOT (i.assemblyitem = '1') ORDER BY i.id|;
532b0d4c Moritz Bunkus
$sth = prepare_execute_query($form, $dbh, $query, $id);
54e4131e Moritz Bunkus
b8da8785 Sven Schöling
while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
98452aaa Moritz Bunkus
# Retrieve custom variables.
my $cvars = CVar->get_custom_variables(dbh => $dbh,
module => 'IC',
sub_module => 'invoice',
trans_id => $ref->{invoice_id},
);
map { $ref->{"ic_cvar_$_->{name}"} = $_->{value} } @{ $cvars };
delete $ref->{invoice_id};

52983c08 Sven Schöling
map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid)) if !$ref->{"part_inventory_accno_id"};
54e4131e Moritz Bunkus
delete($ref->{"part_inventory_accno_id"});
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
foreach my $type (qw(inventory income expense)) {
while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
52983c08 Sven Schöling
my $query = qq|SELECT accno, new_chart_id, date($transdate) - valid_from FROM chart WHERE id = ?|;
@$ref{ map $type.$_, qw(_accno _new_chart _valid) } = selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
532b0d4c Moritz Bunkus
}
}
54e4131e Moritz Bunkus
d319704a Moritz Bunkus
# get tax rates and description
52983c08 Sven Schöling
my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
532b0d4c Moritz Bunkus
$query =
52983c08 Sven Schöling
qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber FROM tax t
532b0d4c Moritz Bunkus
LEFT JOIN chart c ON (c.id = t.chart_id)
WHERE t.id IN
52983c08 Sven Schöling
(SELECT tk.tax_id FROM taxkeys tk
8fa48153 Sven Schöling
WHERE tk.chart_id = (SELECT id FROM chart WHERE accno = ?)
6eea36b2 Thomas Kasulke
AND startdate <= date($transdate)
52983c08 Sven Schöling
ORDER BY startdate DESC LIMIT 1)
532b0d4c Moritz Bunkus
ORDER BY c.accno|;
my $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
d319704a Moritz Bunkus
$ref->{taxaccounts} = "";
54e4131e Moritz Bunkus
my $i=0;
b8da8785 Sven Schöling
while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
d319704a Moritz Bunkus
54e4131e Moritz Bunkus
if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
$i++;
$ptr->{accno} = $i;
}
d319704a Moritz Bunkus
$ref->{taxaccounts} .= "$ptr->{accno} ";
54e4131e Moritz Bunkus
5cf977e5 Moritz Bunkus
if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
d319704a Moritz Bunkus
$form->{"$ptr->{accno}_rate"} = $ptr->{rate};
54e4131e Moritz Bunkus
$form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
d319704a Moritz Bunkus
$form->{"$ptr->{accno}_taxnumber"} = $ptr->{taxnumber};
$form->{taxaccounts} .= "$ptr->{accno} ";
}

}

532b0d4c Moritz Bunkus
$ref->{qty} *= -1 if $form->{type} eq "credit_note";

d319704a Moritz Bunkus
chop $ref->{taxaccounts};
push @{ $form->{invoice_details} }, $ref;
$stw->finish;
}
$sth->finish;

be6f6cfd Moritz Bunkus
Common::webdav_folder($form);
d319704a Moritz Bunkus
}

my $rc = $dbh->commit;

$main::lxdebug->leave_sub();

return $rc;
}

sub get_customer {
$main::lxdebug->enter_sub();

my ($self, $myconfig, $form) = @_;

# connect to database
9c7c96a8 Sven Schöling
my $dbh = $form->get_standard_dbh;
d319704a Moritz Bunkus
my $dateformat = $myconfig->{dateformat};
$dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/;

532b0d4c Moritz Bunkus
my (@values, $duedate, $ref, $query);

if ($form->{invdate}) {
$duedate = "to_date(?, '$dateformat')";
push @values, $form->{invdate};
} else {
$duedate = "current_date";
}
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
my $cid = conv_i($form->{customer_id});
cdfebb50 Moritz Bunkus
my $payment_id;

if ($form->{payment_id}) {
$payment_id = "(pt.id = ?) OR";
push @values, conv_i($form->{payment_id});
}

d319704a Moritz Bunkus
# get customer
532b0d4c Moritz Bunkus
$query =
qq|SELECT
82574e78 Geoffrey Richardson
c.id AS customer_id, c.name AS customer, c.discount as customer_discount, c.creditlimit, c.terms,
6216f7b5 Moritz Bunkus
c.email, c.cc, c.bcc, c.language_id, c.payment_id,
532b0d4c Moritz Bunkus
c.street, c.zipcode, c.city, c.country,
94802c79 Bernd Bleßmann
c.notes AS intnotes, c.klass as customer_klass, c.taxzone_id, c.salesman_id, c.curr,
7bff84cb Thomas Heck
c.taxincluded_checked,
532b0d4c Moritz Bunkus
$duedate + COALESCE(pt.terms_netto, 0) AS duedate,
b.discount AS tradediscount, b.description AS business
FROM customer c
LEFT JOIN business b ON (b.id = c.business_id)
a5f409be Philip Reetz
LEFT JOIN payment_terms pt ON ($payment_id (c.payment_id = pt.id))
532b0d4c Moritz Bunkus
WHERE c.id = ?|;
push @values, $cid;
$ref = selectfirst_hashref_query($form, $dbh, $query, @values);
dc9d8764 Moritz Bunkus
delete $ref->{salesman_id} if !$ref->{salesman_id};

d319704a Moritz Bunkus
map { $form->{$_} = $ref->{$_} } keys %$ref;
54e4131e Moritz Bunkus
94802c79 Bernd Bleßmann
# remove any trailing whitespace
$form->{curr} =~ s/\s*$//;

# use customer currency if not empty
$form->{currency} = $form->{curr} if $form->{curr};

532b0d4c Moritz Bunkus
$query =
qq|SELECT sum(amount - paid) AS dunning_amount
FROM ar
WHERE (paid < amount)
AND (customer_id = ?)
AND (dunning_config_id IS NOT NULL)|;
$ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
54e4131e Moritz Bunkus
map { $form->{$_} = $ref->{$_} } keys %$ref;

532b0d4c Moritz Bunkus
$query =
qq|SELECT dnn.dunning_description AS max_dunning_level
FROM dunning_config dnn
WHERE id IN (SELECT dunning_config_id
FROM ar
WHERE (paid < amount) AND (customer_id = ?) AND (dunning_config_id IS NOT NULL))
ORDER BY dunning_level DESC LIMIT 1|;
$ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
54e4131e Moritz Bunkus
map { $form->{$_} = $ref->{$_} } keys %$ref;

d319704a Moritz Bunkus
$form->{creditremaining} = $form->{creditlimit};
532b0d4c Moritz Bunkus
$query = qq|SELECT SUM(amount - paid) FROM ar WHERE customer_id = ?|;
my ($value) = selectrow_query($form, $dbh, $query, $cid);
$form->{creditremaining} -= $value;

$query =
qq|SELECT o.amount,
(SELECT e.buy FROM exchangerate e
WHERE e.curr = o.curr
AND e.transdate = o.transdate)
FROM oe o
WHERE o.customer_id = ?
AND o.quotation = '0'
AND o.closed = '0'|;
b8da8785 Sven Schöling
my $sth = prepare_execute_query($form, $dbh, $query, $cid);
d319704a Moritz Bunkus
while (my ($amount, $exch) = $sth->fetchrow_array) {
$exch = 1 unless $exch;
$form->{creditremaining} -= $amount * $exch;
}
$sth->finish;

# get shipto if we did not converted an order or invoice
if (!$form->{shipto}) {
map { delete $form->{$_} }
532b0d4c Moritz Bunkus
qw(shiptoname shiptodepartment_1 shiptodepartment_2
shiptostreet shiptozipcode shiptocity shiptocountry
shiptocontact shiptophone shiptofax shiptoemail);
d319704a Moritz Bunkus
532b0d4c Moritz Bunkus
$query = qq|SELECT * FROM shipto WHERE trans_id = ? AND module = 'CT'|;
$ref = selectfirst_hashref_query($form, $dbh, $query, $cid);
delete $ref->{id};
d319704a Moritz Bunkus
map { $form->{$_} = $ref->{$_} } keys %$ref;
}

# setup last accounts used for this customer
if (!$form->{id} && $form->{type} !~ /_(order|quotation)/) {
532b0d4c Moritz Bunkus
$query =
qq|SELECT c.id, c.accno, c.description, c.link, c.category
FROM chart c
JOIN acc_trans ac ON (ac.chart_id = c.id)
JOIN ar a ON (a.id = ac.trans_id)
WHERE a.customer_id = ?
AND NOT (c.link LIKE '%_tax%' OR c.link LIKE '%_paid%')
AND a.id IN (SELECT max(a2.id) FROM ar a2 WHERE a2.customer_id = ?)|;
$sth = prepare_execute_query($form, $dbh, $query, $cid, $cid);
d319704a Moritz Bunkus
my $i = 0;
b8da8785 Sven Schöling
while ($ref = $sth->fetchrow_hashref('NAME_lc')) {
d319704a Moritz Bunkus
if ($ref->{category} eq 'I') {
$i++;
$form->{"AR_amount_$i"} = "$ref->{accno}--$ref->{description}";
f1c1921d Moritz Bunkus
if ($form->{initial_transdate}) {
my $tax_query =
532b0d4c Moritz Bunkus
qq|SELECT tk.tax_id, t.rate
FROM taxkeys tk
LEFT JOIN tax t ON tk.tax_id = t.id
6eea36b2 Thomas Kasulke
WHERE (tk.chart_id = ?) AND (startdate <= date(?))
532b0d4c Moritz Bunkus
ORDER BY tk.startdate DESC
LIMIT 1|;
f1c1921d Moritz Bunkus
my ($tax_id, $rate) =
selectrow_query($form, $dbh, $tax_query, $ref->{id},
$form->{initial_transdate});
$form->{"taxchart_$i"} = "${tax_id}--${rate}";
}
d319704a Moritz Bunkus
}
if ($ref->{category} eq 'A') {
3253777d Moritz Bunkus
$form->{ARselected} = $form->{AR_1} = $ref->{accno};
d319704a Moritz Bunkus
}
}
$sth->finish;
$form->{rowcount} = $i if ($i && !$form->{type});
}

$main::lxdebug->leave_sub();
}

sub retrieve_item {
$main::lxdebug->enter_sub();

my ($self, $myconfig, $form) = @_;

2e5a8be3 Moritz Bunkus
# connect to database
74b9dd67 Sven Schöling
my $dbh = $form->get_standard_dbh;
2e5a8be3 Moritz Bunkus
d319704a Moritz Bunkus
my $i = $form->{rowcount};

532b0d4c Moritz Bunkus
my $where = qq|NOT p.obsolete = '1'|;
my @values;
d319704a Moritz Bunkus
4b47dbd9 Holger Lindemann
foreach my $column (qw(p.partnumber p.description pgpartsgroup )) {
532b0d4c Moritz Bunkus
my ($table, $field) = split m/\./, $column;
next if !$form->{"${field}_${i}"};
$where .= qq| AND lower(${column}) ILIKE ?|;
push @values, '%' . $form->{"${field}_${i}"} . '%';
d319704a Moritz Bunkus
}

4b47dbd9 Holger Lindemann
#Es soll auch nach EAN gesucht werden, ohne Einschränkung durch Beschreibung
if ($form->{"partnumber_$i"} && !$form->{"description_$i"}) {
c09536f4 Sven Schöling
$where .= qq| OR (NOT p.obsolete = '1' AND p.ean = ? )|;
push @values, $form->{"partnumber_$i"};
4b47dbd9 Holger Lindemann
}

5074cc50 Moritz Bunkus
# Search for part ID overrides all other criteria.
cb253140 Moritz Bunkus
if ($form->{"id_${i}"}) {
5074cc50 Moritz Bunkus
$where = qq|p.id = ?|;
@values = ($form->{"id_${i}"});
cb253140 Moritz Bunkus
}

d319704a Moritz Bunkus
if ($form->{"description_$i"}) {
532b0d4c Moritz Bunkus
$where .= qq| ORDER BY p.description|;
d319704a Moritz Bunkus
} else {
532b0d4c Moritz Bunkus
$where .= qq| ORDER BY p.partnumber|;
d319704a Moritz Bunkus
}

2e5a8be3 Moritz Bunkus
my $transdate;
54e4131e Moritz Bunkus
if ($form->{type} eq "invoice") {
2e5a8be3 Moritz Bunkus
$transdate =
$form->{deliverydate} ? $dbh->quote($form->{deliverydate}) :
532b0d4c Moritz Bunkus
$form->{invdate} ? $dbh->quote($form->{invdate}) :
"current_date";
2e5a8be3 Moritz Bunkus
} else {
$transdate =
532b0d4c Moritz Bunkus
$form->{transdate} ? $dbh->quote($form->{transdate}) :
"current_date";
54e4131e Moritz Bunkus
}

532b0d4c Moritz Bunkus
my $taxzone_id = $form->{taxzone_id} * 1;
$taxzone_id = 0 if (0 > $taxzone_id) || (3 < $taxzone_id);

my $query =
qq|SELECT
p.id, p.partnumber, p.description, p.sellprice,
c9b8ad08 Philip Reetz
p.listprice, p.inventory_accno_id, p.lastcost,
532b0d4c Moritz Bunkus
c1.accno AS inventory_accno,
c1.new_chart_id AS inventory_new_chart,
date($transdate) - c1.valid_from AS inventory_valid,

c2.accno AS income_accno,
c2.new_chart_id AS income_new_chart,
date($transdate) - c2.valid_from AS income_valid,

c3.accno AS expense_accno,
c3.new_chart_id AS expense_new_chart,
date($transdate) - c3.valid_from AS expense_valid,

p.unit, p.assembly, p.bin, p.onhand,
p.notes AS partnotes, p.notes AS longdescription,
p.not_discountable, p.formel, p.payment_id AS part_payment_id,
1e251313 Moritz Bunkus
p.price_factor_id,

pfac.factor AS price_factor,
532b0d4c Moritz Bunkus
pg.partsgroup

FROM parts p
LEFT JOIN chart c1 ON
((SELECT inventory_accno_id
FROM buchungsgruppen
WHERE id = p.buchungsgruppen_id) = c1.id)
LEFT JOIN chart c2 ON
((SELECT income_accno_id_${taxzone_id}
FROM buchungsgruppen
WHERE id = p.buchungsgruppen_id) = c2.id)
LEFT JOIN chart c3 ON
((SELECT expense_accno_id_${taxzone_id}
FROM buchungsgruppen
WHERE id = p.buchungsgruppen_id) = c3.id)
LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
1e251313 Moritz Bunkus
LEFT JOIN price_factors pfac ON (pfac.id = p.price_factor_id)
532b0d4c Moritz Bunkus
WHERE $where|;
my $sth = prepare_execute_query($form, $dbh, $query, @values);
d319704a Moritz Bunkus
165a97b3 Moritz Bunkus
my @translation_queries = ( [ qq|SELECT tr.translation, tr.longdescription
FROM translation tr
WHERE tr.language_id = ? AND tr.parts_id = ?| ],
[ qq|SELECT tr.translation, tr.longdescription
FROM translation tr
WHERE tr.language_id IN
(SELECT id
FROM language
WHERE article_code = (SELECT article_code FROM language WHERE id = ?))
AND tr.parts_id = ?
LIMIT 1| ] );
map { push @{ $_ }, prepare_query($form, $dbh, $_->[0]) } @translation_queries;

b8da8785 Sven Schöling
while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
d319704a Moritz Bunkus
54e4131e Moritz Bunkus
# In der Buchungsgruppe ist immer ein Bestandskonto verknuepft, auch wenn
# es sich um eine Dienstleistung handelt. Bei Dienstleistungen muss das
# Buchungskonto also aus dem Ergebnis rausgenommen werden.
if (!$ref->{inventory_accno_id}) {
map({ delete($ref->{"inventory_${_}"}); } qw(accno new_chart valid));
}
delete($ref->{inventory_accno_id});

532b0d4c Moritz Bunkus
foreach my $type (qw(inventory income expense)) {
while ($ref->{"${type}_new_chart"} && ($ref->{"${type}_valid"} >=0)) {
my $query =
qq|SELECT accno, new_chart_id, date($transdate) - valid_from
FROM chart
WHERE id = ?|;
($ref->{"${type}_accno"},
$ref->{"${type}_new_chart"},
$ref->{"${type}_valid"})
= selectrow_query($form, $dbh, $query, $ref->{"${type}_new_chart"});
}
54e4131e Moritz Bunkus
}

532b0d4c Moritz Bunkus
if ($form->{payment_id} eq "") {
$form->{payment_id} = $form->{part_payment_id};
}

d319704a Moritz Bunkus
# get tax rates and description
b8da8785 Sven Schöling
my $accno_id = ($form->{vc} eq "customer") ? $ref->{income_accno} : $ref->{expense_accno};
532b0d4c Moritz Bunkus
$query =
qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber
FROM tax t
LEFT JOIN chart c ON (c.id = t.chart_id)
WHERE t.id in
(SELECT tk.tax_id
FROM taxkeys tk
WHERE tk.chart_id = (SELECT id from chart WHERE accno = ?)
AND startdate <= ?
ORDER BY startdate DESC
LIMIT 1)
ORDER BY c.accno|;
6eea36b2 Thomas Kasulke
@values = ($accno_id, $transdate eq "current_date" ? "now" : $transdate);
b8da8785 Sven Schöling
my $stw = $dbh->prepare($query);
532b0d4c Moritz Bunkus
$stw->execute(@values) || $form->dberror($query);
d319704a Moritz Bunkus
$ref->{taxaccounts} = "";
54e4131e Moritz Bunkus
my $i = 0;
b8da8785 Sven Schöling
while (my $ptr = $stw->fetchrow_hashref('NAME_lc')) {
d319704a Moritz Bunkus
8fa48153 Sven Schöling
# if ($customertax{$ref->{accno}})
54e4131e Moritz Bunkus
if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
$i++;
$ptr->{accno} = $i;
}
d319704a Moritz Bunkus
$ref->{taxaccounts} .= "$ptr->{accno} ";
54e4131e Moritz Bunkus
5cf977e5 Moritz Bunkus
if (!($form->{taxaccounts} =~ /\Q$ptr->{accno}\E/)) {
d319704a Moritz Bunkus
$form->{"$ptr->{accno}_rate"} = $ptr->{rate};
54e4131e Moritz Bunkus
$form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
d319704a Moritz Bunkus
$form->{"$ptr->{accno}_taxnumber"} = $ptr->{taxnumber};
$form->{taxaccounts} .= "$ptr->{accno} ";
}

}

$stw->finish;
chop $ref->{taxaccounts};
165a97b3 Moritz Bunkus
54e4131e Moritz Bunkus
if ($form->{language_id}) {
165a97b3 Moritz Bunkus
for my $spec (@translation_queries) {
do_statement($form, $spec->[1], $spec->[0], conv_i($form->{language_id}), conv_i($ref->{id}));
my ($translation, $longdescription) = $spec->[1]->fetchrow_array;
next unless $translation;
54e4131e Moritz Bunkus
$ref->{description} = $translation;
$ref->{longdescription} = $longdescription;
165a97b3 Moritz Bunkus
last;
54e4131e Moritz Bunkus
}
}
d319704a Moritz Bunkus
83914eeb Moritz Bunkus
$ref->{onhand} *= 1;

d319704a Moritz Bunkus
push @{ $form->{item_list} }, $ref;
}
$sth->finish;
165a97b3 Moritz Bunkus
$_->[1]->finish for @translation_queries;
ef220490 Moritz Bunkus
foreach my $item (@{ $form->{item_list} }) {
my $custom_variables = CVar->get_custom_variables(module => 'IC',
trans_id => $item->{id},
dbh => $dbh,
);

map { $item->{"ic_cvar_" . $_->{name} } = $_->{value} } @{ $custom_variables };
}

d319704a Moritz Bunkus
$main::lxdebug->leave_sub();
}

07d71c33 Stephan Köhler
##########################
# get pricegroups from database
# build up selected pricegroup
0bb0eb67 Stephan Köhler
# if an exchange rate - change price
07d71c33 Stephan Köhler
# for each part
#
sub get_pricegroups_for_parts {
0bb0eb67 Stephan Köhler
07d71c33 Stephan Köhler
$main::lxdebug->enter_sub();

my ($self, $myconfig, $form) = @_;

74b9dd67 Sven Schöling
my $dbh = $form->get_standard_dbh;
07d71c33 Stephan Köhler
604959de Moritz Bunkus
$form->{"PRICES"} = {};

07d71c33 Stephan Köhler
my $i = 1;
my $id = 0;
54e4131e Moritz Bunkus
my $all_units = AM->retrieve_units($myconfig, $form);
07d71c33 Stephan Köhler
while (($form->{"id_$i"}) or ($form->{"new_id_$i"})) {
604959de Moritz Bunkus
$form->{"PRICES"}{$i} = [];
07d71c33 Stephan Köhler
$id = $form->{"id_$i"};

if (!($form->{"id_$i"}) and $form->{"new_id_$i"}) {
$id = $form->{"new_id_$i"};
}

59f7af73 Sven Schöling
my ($price, $selectedpricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
07d71c33 Stephan Köhler
b8da8785 Sven Schöling
my $pricegroup_old = $form->{"pricegroup_old_$i"};
ef92528c Geoffrey Richardson
# sellprice has format 13,0000 or 0,00000, can't check for 0 numerically
my $sellprice = $form->{"sellprice_$i"};
my $pricegroup_id = $form->{"pricegroup_id_$i"};
54e4131e Moritz Bunkus
$form->{"new_pricegroup_$i"} = $selectedpricegroup_id;
$form->{"old_pricegroup_$i"} = $pricegroup_old;
07d71c33 Stephan Köhler
b8da8785 Sven Schöling
my $price_new = $form->{"price_new_$i"};
my $price_old = $form->{"price_old_$i"};
07d71c33 Stephan Köhler
54e4131e Moritz Bunkus
if (!$form->{"unit_old_$i"}) {
# Neue Ware aus der Datenbank. In diesem Fall ist unit_$i die
# Einheit, wie sie in den Stammdaten hinterlegt wurde.
# Es sollte also angenommen werden, dass diese ausgewaehlt war.
$form->{"unit_old_$i"} = $form->{"unit_$i"};
}
532b0d4c Moritz Bunkus
54e4131e Moritz Bunkus
# Die zuletzt ausgewaehlte mit der aktuell ausgewaehlten Einheit
# vergleichen und bei Unterschied den Preis entsprechend umrechnen.
$form->{"selected_unit_$i"} = $form->{"unit_$i"} unless ($form->{"selected_unit_$i"});

07948c34 Moritz Bunkus
if (!$all_units->{$form->{"selected_unit_$i"}} ||
($all_units->{$form->{"selected_unit_$i"}}->{"base_unit"} ne
54e4131e Moritz Bunkus
$all_units->{$form->{"unit_old_$i"}}->{"base_unit"})) {
# Die ausgewaehlte Einheit ist fuer diesen Artikel nicht gueltig
# (z.B. Dimensionseinheit war ausgewaehlt, es handelt sich aber
# um eine Dienstleistung). Dann keinerlei Umrechnung vornehmen.
$form->{"unit_old_$i"} = $form->{"selected_unit_$i"} = $form->{"unit_$i"};
}
532b0d4c Moritz Bunkus
54e4131e Moritz Bunkus
my $basefactor = 1;
532b0d4c Moritz Bunkus
54e4131e Moritz Bunkus
if ($form->{"unit_old_$i"} ne $form->{"selected_unit_$i"}) {
if (defined($all_units->{$form->{"unit_old_$i"}}->{"factor"}) &&
$all_units->{$form->{"unit_old_$i"}}->{"factor"}) {
$basefactor = $all_units->{$form->{"selected_unit_$i"}}->{"factor"} /
$all_units->{$form->{"unit_old_$i"}}->{"factor"};
}
}
532b0d4c Moritz Bunkus
54e4131e Moritz Bunkus
if (!$form->{"basefactor_$i"}) {
$form->{"basefactor_$i"} = 1;
}
07d71c33 Stephan Köhler
b8da8785 Sven Schöling
my $query =
0d3d9d8e Sven Schöling
qq|SELECT
0 as pricegroup_id,
sellprice AS default_sellprice,
'' AS pricegroup,
sellprice AS price,
'selected' AS selected
FROM parts
WHERE id = ?
UNION ALL
SELECT
532b0d4c Moritz Bunkus
pricegroup_id,
0d3d9d8e Sven Schöling
parts.sellprice AS default_sellprice,
pricegroup.pricegroup,
532b0d4c Moritz Bunkus
price,
'' AS selected
FROM prices
0d3d9d8e Sven Schöling
LEFT JOIN parts ON parts.id = parts_id
LEFT JOIN pricegroup ON pricegroup.id = pricegroup_id
532b0d4c Moritz Bunkus
WHERE parts_id = ?
ORDER BY pricegroup|;
0d3d9d8e Sven Schöling
my @values = (conv_i($id), conv_i($id));
532b0d4c Moritz Bunkus
my $pkq = prepare_execute_query($form, $dbh, $query, @values);

b8da8785 Sven Schöling
while (my $pkr = $pkq->fetchrow_hashref('NAME_lc')) {
0bb0eb67 Stephan Köhler
$pkr->{id} = $id;
$pkr->{selected} = '';

# if there is an exchange rate change price
07d71c33 Stephan Köhler
if (($form->{exchangerate} * 1) != 0) {
$pkr->{price} /= $form->{exchangerate};
}
54e4131e Moritz Bunkus
$pkr->{price} *= $form->{"basefactor_$i"};
$pkr->{price} *= $basefactor;
12c24c2a Bernd Bleßmann
$pkr->{price_ufmt} = $pkr->{price};
0bb0eb67 Stephan Köhler
$pkr->{price} = $form->format_amount($myconfig, $pkr->{price}, 5);
07d71c33 Stephan Köhler
da4d7cff Sven Schöling
if (!defined $selectedpricegroup_id) {
ef92528c Geoffrey Richardson
# new entries in article list, either old invoice was loaded (edit) or a new article was added
# Case A: open old invoice, no pricegroup selected
# Case B: add new article to invoice, no pricegroup selected

# to distinguish case A and B the variable pricegroup_id_$i is used
# for new articles this variable isn't defined, for loaded articles it is
# sellprice can't be used, as it already has 0,00 set
8cd05ad6 Moritz Bunkus
ef92528c Geoffrey Richardson
if ($pkr->{pricegroup_id} eq $form->{"pricegroup_id_$i"} and defined $form->{"pricegroup_id_$i"}) {
# Case A
07d71c33 Stephan Köhler
$pkr->{selected} = ' selected';
8cd05ad6 Moritz Bunkus
} elsif ($pkr->{pricegroup_id} eq $form->{customer_klass}
and not defined $form->{"pricegroup_id_$i"}
12c24c2a Bernd Bleßmann
and $pkr->{price_ufmt} != 0 # only use customer pricegroup price if it has a value, else use default_sellprice
# for the case where pricegroup prices haven't been set
ef92528c Geoffrey Richardson
) {
# Case B: use default pricegroup of customer

$pkr->{selected} = ' selected'; # unless $form->{selected};
0bb0eb67 Stephan Köhler
# no customer pricesgroup set
12c24c2a Bernd Bleßmann
if ($pkr->{price_unfmt} == $pkr->{default_sellprice}) {
07d71c33 Stephan Köhler
0bb0eb67 Stephan Köhler
$pkr->{price} = $form->{"sellprice_$i"};
07d71c33 Stephan Köhler
} else {
0bb0eb67 Stephan Köhler
c1a32d62 Sven Schöling
# this sub should not set anything and only return. --sschoeling, 20090506
ef92528c Geoffrey Richardson
# is this correct? put in again... -- grichardson 20110119
$form->{"sellprice_$i"} = $pkr->{price};
07d71c33 Stephan Köhler
}

12c24c2a Bernd Bleßmann
} elsif ($pkr->{price_unfmt} == $pkr->{default_sellprice} and $pkr->{default_sellprice} != 0) {
532b0d4c Moritz Bunkus
$pkr->{price} = $form->{"sellprice_$i"};
$pkr->{selected} = ' selected';
07d71c33 Stephan Köhler
}
ef92528c Geoffrey Richardson
}

# existing article: pricegroup or price changed
if ($selectedpricegroup_id or $selectedpricegroup_id == 0) {
07d71c33 Stephan Köhler
if ($selectedpricegroup_id ne $pricegroup_old) {
ef92528c Geoffrey Richardson
# pricegroup has changed
07d71c33 Stephan Köhler
if ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
54e4131e Moritz Bunkus
$pkr->{selected} = ' selected';
07d71c33 Stephan Köhler
}
806a4de7 Geoffrey Richardson
} elsif ( ($form->parse_amount($myconfig, $price_new)
74b9dd67 Sven Schöling
!= $form->parse_amount($myconfig, $form->{"sellprice_$i"}))
806a4de7 Geoffrey Richardson
and ($price_new ne 0) and defined $price_new) {
ef92528c Geoffrey Richardson
# sellprice has changed
# when loading existing invoices $price_new is NULL
532b0d4c Moritz Bunkus
if ($pkr->{pricegroup_id} == 0) {
$pkr->{price} = $form->{"sellprice_$i"};
$pkr->{selected} = ' selected';
}
} elsif ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
ef92528c Geoffrey Richardson
# neither sellprice nor pricegroup changed
532b0d4c Moritz Bunkus
$pkr->{selected} = ' selected';
ef92528c Geoffrey Richardson
if ( ($pkr->{pricegroup_id} == 0) and ($pkr->{price} == $form->{"sellprice_$i"})) {
532b0d4c Moritz Bunkus
# $pkr->{price} = $form->{"sellprice_$i"};
07d71c33 Stephan Köhler
} else {
532b0d4c Moritz Bunkus
$pkr->{price} = $form->{"sellprice_$i"};
07d71c33 Stephan Köhler
}
}
}
54e4131e Moritz Bunkus
push @{ $form->{PRICES}{$i} }, $pkr;

07d71c33 Stephan Köhler
}
54e4131e Moritz Bunkus
$form->{"basefactor_$i"} *= $basefactor;

07d71c33 Stephan Köhler
$i++;

$pkq->finish;
}

$main::lxdebug->leave_sub();
}

95155b0d Moritz Bunkus
sub has_storno {
$main::lxdebug->enter_sub();

a1a3bfd8 Moritz Bunkus
my ($self, $myconfig, $form, $table) = @_;
95155b0d Moritz Bunkus
$main::lxdebug->leave_sub() and return 0 unless ($form->{id});

1fa91538 Sven Schöling
# make sure there's no funny stuff in $table
# ToDO: die when this happens and throw an error
$main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);

74b9dd67 Sven Schöling
my $dbh = $form->get_standard_dbh;
95155b0d Moritz Bunkus
805e8da4 Sven Schöling
my $query = qq|SELECT storno FROM $table WHERE storno_id = ?|;
my ($result) = selectrow_query($form, $dbh, $query, $form->{id});

$main::lxdebug->leave_sub();

return $result;
}

sub is_storno {
$main::lxdebug->enter_sub();

077ebb6c Moritz Bunkus
my ($self, $myconfig, $form, $table, $id) = @_;
805e8da4 Sven Schöling
077ebb6c Moritz Bunkus
$main::lxdebug->leave_sub() and return 0 unless ($id);
805e8da4 Sven Schöling
# make sure there's no funny stuff in $table
# ToDO: die when this happens and throw an error
$main::lxdebug->leave_sub() and return 0 if ($table =~ /\W/);

74b9dd67 Sven Schöling
my $dbh = $form->get_standard_dbh;
805e8da4 Sven Schöling
a1a3bfd8 Moritz Bunkus
my $query = qq|SELECT storno FROM $table WHERE id = ?|;
077ebb6c Moritz Bunkus
my ($result) = selectrow_query($form, $dbh, $query, $id);
95155b0d Moritz Bunkus
$main::lxdebug->leave_sub();

return $result;
}

0e0ff150 Jan Büren
sub get_standard_accno_current_assets {
$main::lxdebug->enter_sub();

my ($self, $myconfig, $form) = @_;

74b9dd67 Sven Schöling
my $dbh = $form->get_standard_dbh;
0e0ff150 Jan Büren
my $query = qq| SELECT accno FROM chart WHERE id = (SELECT ar_paid_accno_id FROM defaults)|;
my ($result) = selectrow_query($form, $dbh, $query);

$main::lxdebug->leave_sub();

return $result;
}

d319704a Moritz Bunkus
1;