From: ivan Date: Mon, 15 Nov 2004 10:35:56 +0000 (+0000) Subject: import sql-ledger 2.4.4 X-Git-Tag: BEFORE_RT_3_4_5~2 X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=32306b5f8ffe4ce594409aa6e89626740b225a39 import sql-ledger 2.4.4 --- diff --git a/sql-ledger/SL/AM.pm b/sql-ledger/SL/AM.pm index d691b3ce6..dbdd61111 100644 --- a/sql-ledger/SL/AM.pm +++ b/sql-ledger/SL/AM.pm @@ -1,12 +1,12 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org # Web: http://www.sql-ledger.org # -# Contributors: +# Contributors: Jim Rawlings # # 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 @@ -51,9 +51,6 @@ sub get_account { $form->{"$key"} = $ref->{"$key"}; } - $sth->finish; - - # get default accounts $query = qq|SELECT inventory_accno_id, income_accno_id, expense_accno_id FROM defaults|; @@ -61,10 +58,15 @@ sub get_account { $sth->execute || $form->dberror($query); $ref = $sth->fetchrow_hashref(NAME_lc); - map { $form->{$_} = $ref->{$_} } keys %ref; - $sth->finish; + + # check if we have any transactions + $query = qq|SELECT trans_id FROM acc_trans + WHERE chart_id = $form->{id}|; + ($form->{orphaned}) = $dbh->selectrow_array($query); + $form->{orphaned} = !$form->{orphaned}; + $dbh->disconnect; } @@ -76,11 +78,6 @@ sub save_account { # connect to database, turn off AutoCommit my $dbh = $form->dbconnect_noauto($myconfig); - # sanity check, can't have AR with AR_... - if ($form->{AR} || $form->{AP} || $form->{IC}) { - map { delete $form->{$_} } qw(AR_amount AR_tax AR_paid AP_amount AP_tax AP_paid IC_sale IC_cogs IC_taxpart IC_income IC_expense IC_taxservice); - } - $form->{link} = ""; foreach my $item ($form->{AR}, $form->{AR_amount}, @@ -103,18 +100,22 @@ sub save_account { } chop $form->{link}; - # if we have an id then replace the old record - $form->{description} =~ s/'/''/g; - # strip blanks from accno - map { $form->{$_} =~ s/ //g; } qw(accno gifi_accno); + map { $form->{$_} =~ s/( |')//g } qw(accno gifi_accno); - my ($query, $sth); + foreach my $item (qw(accno gifi_accno description)) { + $form->{$item} =~ s/-(-+)/-/g; + $form->{$item} =~ s/ ( )+/ /g; + } + my $query; + my $sth; + + # if we have an id then replace the old record if ($form->{id}) { $query = qq|UPDATE chart SET accno = '$form->{accno}', - description = '$form->{description}', + description = |.$dbh->quote($form->{description}).qq|, charttype = '$form->{charttype}', gifi_accno = '$form->{gifi_accno}', category = '$form->{category}', @@ -123,38 +124,31 @@ sub save_account { } else { $query = qq|INSERT INTO chart (accno, description, charttype, gifi_accno, category, link) - VALUES ('$form->{accno}', '$form->{description}', + VALUES ('$form->{accno}',| + .$dbh->quote($form->{description}).qq|, '$form->{charttype}', '$form->{gifi_accno}', '$form->{category}', '$form->{link}')|; } $dbh->do($query) || $form->dberror($query); - - if ($form->{IC_taxpart} || $form->{IC_taxservice} || $form->{CT_tax}) { - my $chart_id = $form->{id}; - - unless ($form->{id}) { - # get id from chart - $query = qq|SELECT id - FROM chart - WHERE accno = '$form->{accno}'|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - ($chart_id) = $sth->fetchrow_array; - $sth->finish; - } - + $chart_id = $form->{id}; + + if (! $form->{id}) { + # get id from chart + $query = qq|SELECT id + FROM chart + WHERE accno = '$form->{accno}'|; + ($chart_id) = $dbh->selectrow_array($query); + } + + if ($form->{IC_taxpart} || $form->{IC_taxservice} || $form->{CT_tax}) { + # add account if it doesn't exist in tax $query = qq|SELECT chart_id FROM tax WHERE chart_id = $chart_id|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - my ($tax_id) = $sth->fetchrow_array; - $sth->finish; + my ($tax_id) = $dbh->selectrow_array($query); # add tax if it doesn't exist unless ($tax_id) { @@ -171,7 +165,6 @@ sub save_account { } } - # commit my $rc = $dbh->commit; $dbh->disconnect; @@ -187,6 +180,14 @@ sub delete_account { # connect to database, turn off AutoCommit my $dbh = $form->dbconnect_noauto($myconfig); + + my $query = qq|SELECT * FROM acc_trans + WHERE chart_id = $form->{id}|; + if ($dbh->selectrow_array($query)) { + $dbh->disconnect; + return; + } + # delete chart of account record $query = qq|DELETE FROM chart @@ -244,22 +245,479 @@ sub gifi_accounts { push @{ $form->{ALL} }, $ref; } - $sth->finish; $dbh->disconnect; } -sub get_gifi { +sub get_gifi { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT accno, description + FROM gifi + WHERE accno = '$form->{accno}'|; + + ($form->{accno}, $form->{description}) = $dbh->selectrow_array($query); + + # check for transactions + $query = qq|SELECT * FROM acc_trans a + JOIN chart c ON (a.chart_id = c.id) + JOIN gifi g ON (c.gifi_accno = g.accno) + WHERE g.accno = '$form->{accno}'|; + ($form->{orphaned}) = $dbh->selectrow_array($query); + $form->{orphaned} = !$form->{orphaned}; + + $dbh->disconnect; + +} + + +sub save_gifi { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $form->{accno} =~ s/( |')//g; + + foreach my $item (qw(accno description)) { + $form->{$item} =~ s/-(-+)/-/g; + $form->{$item} =~ s/ ( )+/ /g; + } + + # id is the old account number! + if ($form->{id}) { + $query = qq|UPDATE gifi SET + accno = '$form->{accno}', + description = |.$dbh->quote($form->{description}).qq| + WHERE accno = '$form->{id}'|; + } else { + $query = qq|INSERT INTO gifi + (accno, description) + VALUES ('$form->{accno}',| + .$dbh->quote($form->{description}).qq|)|; + } + $dbh->do($query) || $form->dberror; + + $dbh->disconnect; + +} + + +sub delete_gifi { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + # id is the old account number! + $query = qq|DELETE FROM gifi + WHERE accno = '$form->{id}'|; + $dbh->do($query) || $form->dberror($query); + + $dbh->disconnect; + +} + + +sub warehouses { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $form->sort_order(); + my $query = qq|SELECT id, description + FROM warehouse + ORDER BY 2 $form->{direction}|; + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{ALL} }, $ref; + } + + $dbh->disconnect; + +} + + + +sub get_warehouse { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT description + FROM warehouse + WHERE id = $form->{id}|; + ($form->{description}) = $dbh->selectrow_array($query); + + # see if it is in use + $query = qq|SELECT * FROM inventory + WHERE warehouse_id = $form->{id}|; + ($form->{orphaned}) = $dbh->selectrow_array($query); + $form->{orphaned} = !$form->{orphaned}; + + $dbh->disconnect; + +} + + +sub save_warehouse { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $form->{description} =~ s/-(-)+/-/g; + $form->{description} =~ s/ ( )+/ /g; + + if ($form->{id}) { + $query = qq|UPDATE warehouse SET + description = |.$dbh->quote($form->{description}).qq| + WHERE id = $form->{id}|; + } else { + $query = qq|INSERT INTO warehouse + (description) + VALUES (|.$dbh->quote($form->{description}).qq|)|; + } + $dbh->do($query) || $form->dberror($query); + + $dbh->disconnect; + +} + + +sub delete_warehouse { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $query = qq|DELETE FROM warehouse + WHERE id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $dbh->disconnect; + +} + + + +sub departments { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $form->sort_order(); + my $query = qq|SELECT id, description, role + FROM department + ORDER BY 2 $form->{direction}|; + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{ALL} }, $ref; + } + + $dbh->disconnect; + +} + + + +sub get_department { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT description, role + FROM department + WHERE id = $form->{id}|; + ($form->{description}, $form->{role}) = $dbh->selectrow_array($query); + + map { $form->{$_} = $ref->{$_} } keys %$ref; + + # see if it is in use + $query = qq|SELECT * FROM dpt_trans + WHERE department_id = $form->{id}|; + ($form->{orphaned}) = $dbh->selectrow_array($query); + $form->{orphaned} = !$form->{orphaned}; + + $dbh->disconnect; + +} + + +sub save_department { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $form->{description} =~ s/-(-)+/-/g; + $form->{description} =~ s/ ( )+/ /g; + + if ($form->{id}) { + $query = qq|UPDATE department SET + description = |.$dbh->quote($form->{description}).qq|, + role = '$form->{role}' + WHERE id = $form->{id}|; + } else { + $query = qq|INSERT INTO department + (description, role) + VALUES (| + .$dbh->quote($form->{description}).qq|, '$form->{role}')|; + } + $dbh->do($query) || $form->dberror($query); + + $dbh->disconnect; + +} + + +sub delete_department { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $query = qq|DELETE FROM department + WHERE id = $form->{id}|; + $dbh->do($query); + + $dbh->disconnect; + +} + + +sub business { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $form->sort_order(); + my $query = qq|SELECT id, description, discount + FROM business + ORDER BY 2 $form->{direction}|; + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{ALL} }, $ref; + } + + $dbh->disconnect; + +} + + + +sub get_business { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT description, discount + FROM business + WHERE id = $form->{id}|; + ($form->{description}, $form->{discount}) = $dbh->selectrow_array($query); + + $dbh->disconnect; + +} + + +sub save_business { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $form->{description} =~ s/-(-)+/-/g; + $form->{description} =~ s/ ( )+/ /g; + $form->{discount} /= 100; + + if ($form->{id}) { + $query = qq|UPDATE business SET + description = |.$dbh->quote($form->{description}).qq|, + discount = $form->{discount} + WHERE id = $form->{id}|; + } else { + $query = qq|INSERT INTO business + (description, discount) + VALUES (| + .$dbh->quote($form->{description}).qq|, $form->{discount})|; + } + $dbh->do($query) || $form->dberror($query); + + $dbh->disconnect; + +} + + +sub delete_business { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $query = qq|DELETE FROM business + WHERE id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $dbh->disconnect; + +} + + +sub sic { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $form->{sort} = "code" unless $form->{sort}; + my @a = qw(code description); + my %ordinal = ( code => 1, + description => 3 ); + my $sortorder = $form->sort_order(\@a, \%ordinal); + my $query = qq|SELECT code, sictype, description + FROM sic + ORDER BY $sortorder|; + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{ALL} }, $ref; + } + + $dbh->disconnect; + +} + + + +sub get_sic { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT code, sictype, description + FROM sic + WHERE code = |.$dbh->quote($form->{code}); + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my $ref = $sth->fetchrow_hashref(NAME_lc); + + map { $form->{$_} = $ref->{$_} } keys %$ref; + + $sth->finish; + $dbh->disconnect; + +} + + +sub save_sic { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + foreach my $item (qw(code description)) { + $form->{$item} =~ s/-(-)+/-/g; + } + + # if there is an id + if ($form->{id}) { + $query = qq|UPDATE sic SET + code = |.$dbh->quote($form->{code}).qq|, + sictype = '$form->{sictype}', + description = |.$dbh->quote($form->{description}).qq| + WHERE code = |.$dbh->quote($form->{id}); + } else { + $query = qq|INSERT INTO sic + (code, sictype, description) + VALUES (| + .$dbh->quote($form->{code}).qq|, + '$form->{sictype}',| + .$dbh->quote($form->{description}).qq|)|; + } + $dbh->do($query) || $form->dberror($query); + + $dbh->disconnect; + +} + + +sub delete_sic { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $query = qq|DELETE FROM sic + WHERE code = |.$dbh->quote($form->{code}); + $dbh->do($query); + + $dbh->disconnect; + +} + + +sub language { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $form->{sort} = "code" unless $form->{sort}; + my @a = qw(code description); + my %ordinal = ( code => 1, + description => 2 ); + my $sortorder = $form->sort_order(\@a, \%ordinal); + + my $query = qq|SELECT code, description + FROM language + ORDER BY $sortorder|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{ALL} }, $ref; + } + + $dbh->disconnect; + +} + + + +sub get_language { my ($self, $myconfig, $form) = @_; # connect to database my $dbh = $form->dbconnect($myconfig); - my $query = qq|SELECT accno, description - FROM gifi - WHERE accno = '$form->{accno}'|; + my $query = qq|SELECT * + FROM language + WHERE code = |.$dbh->quote($form->{code}); my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -268,30 +726,36 @@ sub get_gifi { map { $form->{$_} = $ref->{$_} } keys %$ref; $sth->finish; + $dbh->disconnect; } -sub save_gifi { +sub save_language { my ($self, $myconfig, $form) = @_; # connect to database my $dbh = $form->dbconnect($myconfig); - - $form->{description} =~ s/'/''/g; - $form->{accno} =~ s/ //g; - # id is the old account number! + $form->{code} =~ s/ //g; + foreach my $item (qw(code description)) { + $form->{$item} =~ s/-(-)+/-/g; + $form->{$item} =~ s/ ( )+/-/g; + } + + # if there is an id if ($form->{id}) { - $query = qq|UPDATE gifi SET - accno = '$form->{accno}', - description = '$form->{description}' - WHERE accno = '$form->{id}'|; + $query = qq|UPDATE language SET + code = |.$dbh->quote($form->{code}).qq|, + description = |.$dbh->quote($form->{description}).qq| + WHERE code = |.$dbh->quote($form->{id}); } else { - $query = qq|INSERT INTO gifi - (accno, description) - VALUES ('$form->{accno}', '$form->{description}')|; + $query = qq|INSERT INTO language + (code, description) + VALUES (| + .$dbh->quote($form->{code}).qq|,| + .$dbh->quote($form->{description}).qq|)|; } $dbh->do($query) || $form->dberror($query); @@ -300,15 +764,14 @@ sub save_gifi { } -sub delete_gifi { +sub delete_language { my ($self, $myconfig, $form) = @_; # connect to database my $dbh = $form->dbconnect($myconfig); - # id is the old account number! - $query = qq|DELETE FROM gifi - WHERE accno = '$form->{id}'|; + $query = qq|DELETE FROM language + WHERE code = |.$dbh->quote($form->{code}); $dbh->do($query) || $form->dberror($query); $dbh->disconnect; @@ -316,6 +779,7 @@ sub delete_gifi { } + sub load_template { my ($self, $form) = @_; @@ -348,6 +812,42 @@ sub save_template { sub save_preferences { my ($self, $myconfig, $form, $memberfile, $userspath) = @_; + # connect to database + my $dbh = $form->dbconnect($myconfig); + + # update name + my $query = qq|UPDATE employee + SET name = |.$dbh->quote($form->{name}).qq|, + role = '$form->{role}' + WHERE login = '$form->{login}'|; + $dbh->do($query) || $form->dberror($query); + + # get default currency + $query = qq|SELECT curr, businessnumber + FROM defaults|; + ($form->{currency}, $form->{businessnumber}) = $dbh->selectrow_array($query); + $form->{currency} =~ s/:.*//; + + $dbh->disconnect; + + my $myconfig = new User "$memberfile", "$form->{login}"; + + foreach my $item (keys %$form) { + $myconfig->{$item} = $form->{$item}; + } + + $myconfig->{password} = $form->{new_password} if ($form->{old_password} ne $form->{new_password}); + + $myconfig->save_member($memberfile, $userspath); + + 1; + +} + + +sub save_defaults { + my ($self, $myconfig, $form) = @_; + map { ($form->{$_}) = split /--/, $form->{$_} } qw(inventory_accno income_accno expense_accno fxgain_accno fxloss_accno); my @a; @@ -358,8 +858,6 @@ sub save_preferences { # connect to database my $dbh = $form->dbconnect_noauto($myconfig); - # these defaults are database wide - # user specific variables are in myconfig # save defaults my $query = qq|UPDATE defaults SET inventory_accno_id = @@ -377,28 +875,27 @@ sub save_preferences { fxloss_accno_id = (SELECT id FROM chart WHERE accno = '$form->{fxloss_accno}'), - invnumber = '$form->{invnumber}', + sinumber = '$form->{sinumber}', + vinumber = '$form->{vinumber}', sonumber = '$form->{sonumber}', ponumber = '$form->{ponumber}', + sqnumber = '$form->{sqnumber}', + rfqnumber = '$form->{rfqnumber}', + partnumber = '$form->{partnumber}', + employeenumber = '$form->{employeenumber}', + customernumber = '$form->{customernumber}', + vendornumber = '$form->{vendornumber}', yearend = '$form->{yearend}', curr = '$form->{curr}', - weightunit = '$form->{weightunit}', - businessnumber = '$form->{businessnumber}' - |; + weightunit = |.$dbh->quote($form->{weightunit}).qq|, + businessnumber = |.$dbh->quote($form->{businessnumber}); $dbh->do($query) || $form->dberror($query); - # update name - my $name = $form->{name}; - $name =~ s/'/''/g; - $query = qq|UPDATE employee - SET name = '$name' - WHERE login = '$form->{login}'|; - $dbh->do($query) || $form->dberror($query); - foreach my $item (split / /, $form->{taxaccounts}) { + $form->{$item} = $form->parse_amount($myconfig, $form->{$item}) / 100; $query = qq|UPDATE tax - SET rate = |.($form->{$item} / 100).qq|, - taxnumber = '$form->{"taxnumber_$item"}' + SET rate = $form->{$item}, + taxnumber = |.$dbh->quote($form->{"taxnumber_$item"}).qq| WHERE chart_id = $item|; $dbh->do($query) || $form->dberror($query); } @@ -406,17 +903,6 @@ sub save_preferences { my $rc = $dbh->commit; $dbh->disconnect; - # save first currency in myconfig - $form->{currency} = substr($form->{curr},0,3); - - my $myconfig = new User "$memberfile", "$form->{login}"; - - foreach my $item (keys %$form) { - $myconfig->{$item} = $form->{$item}; - } - - $myconfig->save_member($memberfile, $userspath); - $rc; } @@ -449,7 +935,7 @@ sub defaultaccounts { WHERE link LIKE '%IC%' ORDER BY accno|; $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); + $sth->execute || $form->dberror($query); while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { foreach my $key (split(/:/, $ref->{link})) { @@ -475,7 +961,7 @@ sub defaultaccounts { AND charttype = 'A' ORDER BY accno|; $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); + $sth->execute || $form->dberror($query); while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { %{ $form->{IC}{FX_gain}{$ref->{accno}} } = ( id => $ref->{id}, @@ -489,7 +975,7 @@ sub defaultaccounts { AND charttype = 'A' ORDER BY accno|; $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); + $sth->execute || $form->dberror($query); while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { %{ $form->{IC}{FX_loss}{$ref->{accno}} } = ( id => $ref->{id}, @@ -521,51 +1007,138 @@ sub defaultaccounts { sub backup { - my ($self, $myconfig, $form, $userspath) = @_; + my ($self, $myconfig, $form, $userspath, $gzip) = @_; - my ($tmpfile, $out, $mail); + my $mail; + my $err; - if ($form->{media} eq 'email') { + my @t = localtime(time); + $t[4]++; + $t[5] += 1900; + $t[3] = substr("0$t[3]", -2); + $t[4] = substr("0$t[4]", -2); + + my $boundary = time; + my $tmpfile = "$userspath/$boundary.$myconfig->{dbname}-$form->{dbversion}-$t[5]$t[4]$t[3].sql"; + my $out = $form->{OUT}; + $form->{OUT} = ">$tmpfile"; + + open(OUT, "$form->{OUT}") or $form->error("$form->{OUT} : $!"); + + # get sequences, functions and triggers + my @tables = (); + my @sequences = (); + my @functions = (); + my @triggers = (); + my @schema = (); + + # get dbversion from -tables.sql + my $file = "$myconfig->{dbdriver}-tables.sql"; - my $boundary = time; - $tmpfile = "$userspath/$boundary.$myconfig->{dbname}-$form->{dbversion}.sql"; - $out = $form->{OUT}; - $form->{OUT} = ">$tmpfile"; - - use SL::Mailer; - $mail = new Mailer; + open(FH, "sql/$file") or $form->error("sql/$file : $!"); - $mail->{to} = qq|"$myconfig->{name}" <$myconfig->{email}>|; - $mail->{from} = qq|"$myconfig->{name}" <$myconfig->{email}>|; - $mail->{subject} = "SQL-Ledger Backup / $myconfig->{dbname}-$form->{dbversion}.sql"; - @{ $mail->{attachments} } = ($tmpfile); - $mail->{version} = $form->{version}; - $mail->{fileid} = "$boundary."; + my @a = ; + close(FH); - $myconfig->{signature} =~ s/\\n/\r\n/g; - $mail->{message} = "--\n$myconfig->{signature}"; + @dbversion = grep /defaults \(version\)/, @a; + + $dbversion = "@dbversion"; + $dbversion =~ /(\d+\.\d+\.\d+)/; + $dbversion = User::calc_version($1); + + opendir SQLDIR, "sql/." or $form->error($!); + @a = grep /$myconfig->{dbdriver}-upgrade-.*?\.sql$/, readdir SQLDIR; + closedir SQLDIR; + + my $mindb; + my $maxdb; + + foreach my $line (@a) { + + $upgradescript = $line; + $line =~ s/(^$myconfig->{dbdriver}-upgrade-|\.sql$)//g; - } + ($mindb, $maxdb) = split /-/, $line; + $mindb = User::calc_version($mindb); + + next if $mindb < $dbversion; - if ($form->{OUT}) { - open(OUT, "$form->{OUT}") or $form->error("$form->{OUT} : $!"); - } else { - open(OUT, ">-") or $form->error("STDOUT : $!"); + $maxdb = User::calc_version($maxdb); + + $upgradescripts{$maxdb} = $upgradescript; } - if ($form->{media} eq 'file') { - print OUT qq|Content-Type: Application/File; -Content-Disposition: filename="$myconfig->{dbname}-$form->{dbversion}.sql"\n\n|; + + $upgradescripts{$dbversion} = "$myconfig->{dbdriver}-tables.sql"; + $upgradescripts{functions} = "$myconfig->{dbdriver}-functions.sql"; + + if (-f "sql/$myconfig->{dbdriver}-custom_tables.sql") { + $upgradescripts{customtables} = "$myconfig->{dbdriver}-custom_tables.sql"; + } + if (-f "sql/$myconfig->{dbdriver}-custom_functions.sql") { + $upgradescripts{customfunctions} = "$myconfig->{dbdriver}-custom_functions.sql"; + } + + foreach my $key (sort keys %upgradescripts) { + + $file = $upgradescripts{$key}; + + open(FH, "sql/$file") or $form->error("sql/$file : $!"); + + push @schema, qq|-- $file\n|; + + while () { + + if (/create table (\w+)/i) { + push @tables, $1; + } + + if (/create sequence (\w+)/i) { + push @sequences, $1; + } + + if (/end function/i) { + push @functions, $_; + $function = 0; + next; + } + + if (/create function /i) { + $function = 1; + } + + if ($function) { + push @functions, $_; + next; + } + + if (/end trigger/i) { + push @triggers, $_; + $trigger = 0; + next; + } + + if (/create trigger/i) { + $trigger = 1; + } + + if ($trigger) { + push @triggers, $_; + next; + } + + push @schema, $_ if $_ !~ /^(insert|--)/i; + + } + close(FH); + } + # connect to database my $dbh = $form->dbconnect($myconfig); - # get all the tables - my @tables = $dbh->tables; - my $today = scalar localtime; - $myconfig->{dbhost} = 'localhost' unless $myconfig->{dbhost}; @@ -577,39 +1150,56 @@ Content-Disposition: filename="$myconfig->{dbname}-$form->{dbversion}.sql"\n\n|; -- User: $myconfig->{name} -- Date: $today -- --- set options +|; + + + my $restrict = ($myconfig->{dbdriver} eq 'DB2') ? "RESTRICT" : ""; + + @tables = grep !/^temp/, @tables; + # drop tables and sequences + map { print OUT qq|DROP TABLE $_;\n| } @tables; + map { print OUT qq|DROP SEQUENCE $_ $restrict;\n| } @sequences; + + print OUT "--\n"; + + # triggers and index files are dropped with the tables + + # drop functions + foreach $item (@functions) { + if ($item =~ /create function (.*\))/i) { + print OUT qq|DROP FUNCTION $1;\n|; + } + } + + # add schema + print OUT @schema; + print OUT "\n"; + + print OUT qq|-- set options $myconfig->{dboptions}; -- |; + my $query; + my $sth; + my @arr; + my $fields; + foreach $table (@tables) { - my $query = qq|SELECT * FROM $table|; - - my $sth = $dbh->prepare($query); + + $query = qq|SELECT * FROM $table|; + $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); $query = qq|INSERT INTO $table (|; - map { $query .= qq|$sth->{NAME}->[$_],| } (0 .. $sth->{NUM_OF_FIELDS} - 1); - chop $query; - + $query .= join ',', (map { $sth->{NAME}->[$_] } (0 .. $sth->{NUM_OF_FIELDS} - 1)); $query .= qq|) VALUES|; - print OUT qq|-- -DELETE FROM $table; -|; - while (my @arr = $sth->fetchrow_array) { + while (@arr = $sth->fetchrow_array) { $fields = "("; - foreach my $item (@arr) { - if (defined $item) { - $item =~ s/'/''/g; - $fields .= qq|'$item',|; - } else { - $fields .= 'NULL,'; - } - } - - chop $fields; + + $fields .= join ',', map { $dbh->quote($_) } @arr; $fields .= ")"; print OUT qq|$query $fields;\n|; @@ -618,28 +1208,103 @@ DELETE FROM $table; $sth->finish; } - $query = qq|SELECT last_value FROM id|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - my ($id) = $sth->fetchrow_array; - $sth->finish; + # create sequences and triggers + foreach $item (@sequences) { + if ($myconfig->{dbdriver} eq 'DB2') { + $query = qq|SELECT NEXTVAL FOR $item FROM sysibm.sysdummy1|; + } else { + $query = qq|SELECT last_value FROM $item|; + } + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + my ($id) = $sth->fetchrow_array; + $sth->finish; + $id++; - print OUT qq|-- -DROP SEQUENCE id; -CREATE SEQUENCE id START $id; -|; + print OUT qq|-- +DROP SEQUENCE $item $restrict;\n|; + + if ($myconfig->{dbdriver} eq 'DB2') { + print OUT qq|CREATE SEQUENCE $item AS INTEGER START WITH $id INCREMENT BY 1 MAXVALUE 2147483647 MINVALUE 1 CACHE 5;\n|; + } else { + print OUT qq|CREATE SEQUENCE $item START $id;\n|; + } + } + + print OUT "--\n"; + + # functions + map { print OUT $_ } @functions; + + # triggers + map { print OUT $_ } @triggers; + + # add the index files + open(FH, "sql/$myconfig->{dbdriver}-indices.sql"); + @a = ; + close(FH); + print OUT @a; close(OUT); $dbh->disconnect; + # compress backup if gzip defined + my $suffix = ""; + if ($gzip) { + my @args = split / /, $gzip; + my @s = @args; + + push @args, "$tmpfile"; + system(@args) == 0 or $form->error("$args[0] : $?"); + + shift @s; + my %s = @s; + $suffix = ${-S} || ".gz"; + $tmpfile .= $suffix; + } + if ($form->{media} eq 'email') { - my $err = $mail->send($out); - $_ = $tmpfile; - unlink; + + use SL::Mailer; + $mail = new Mailer; + + $mail->{to} = qq|"$myconfig->{name}" <$myconfig->{email}>|; + $mail->{from} = qq|"$myconfig->{name}" <$myconfig->{email}>|; + $mail->{subject} = "SQL-Ledger Backup / $myconfig->{dbname}-$form->{dbversion}-$t[5]$t[4]$t[3].sql$suffix"; + @{ $mail->{attachments} } = ($tmpfile); + $mail->{version} = $form->{version}; + $mail->{fileid} = "$boundary."; + + $myconfig->{signature} =~ s/\\n/\r\n/g; + $mail->{message} = "-- \n$myconfig->{signature}"; + + $err = $mail->send($out); } + + if ($form->{media} eq 'file') { + + open(IN, "$tmpfile") or $form->error("$tmpfile : $!"); + open(OUT, ">-") or $form->error("STDOUT : $!"); + + print OUT qq|Content-Type: application/file; +Content-Disposition: attachment; filename="$myconfig->{dbname}-$form->{dbversion}-$t[5]$t[4]$t[3].sql$suffix" + +|; + + while () { + print OUT $_; + } + + close(IN); + close(OUT); + } + + unlink "$tmpfile"; + } @@ -648,13 +1313,9 @@ sub closedto { my $dbh = $form->dbconnect($myconfig); - my $query = qq|SELECT closedto, revtrans FROM defaults|; - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - ($form->{closedto}, $form->{revtrans}) = $sth->fetchrow_array; - - $sth->finish; + my $query = qq|SELECT closedto, revtrans, audittrail + FROM defaults|; + ($form->{closedto}, $form->{revtrans}, $form->{audittrail}) = $dbh->selectrow_array($query); $dbh->disconnect; @@ -664,15 +1325,15 @@ sub closedto { sub closebooks { my ($self, $myconfig, $form) = @_; - my $dbh = $form->dbconnect($myconfig); + my $dbh = $form->dbconnect_noauto($myconfig); if ($form->{revtrans}) { - + $query = qq|UPDATE defaults SET closedto = NULL, revtrans = '1'|; } else { if ($form->{closedto}) { - + $query = qq|UPDATE defaults SET closedto = '$form->{closedto}', revtrans = '0'|; } else { @@ -682,11 +1343,134 @@ sub closebooks { } } + if ($form->{audittrail}) { + $query .= qq|, audittrail = '1'|; + } else { + $query .= qq|, audittrail = '0'|; + } + # set close in defaults $dbh->do($query) || $form->dberror($query); + + if ($form->{removeaudittrail}) { + $query = qq|DELETE FROM audittrail + WHERE transdate < '$form->{removeaudittrail}'|; + $dbh->do($query) || $form->dberror($query); + } + + + $dbh->commit; + $dbh->disconnect; +} + + +sub earningsaccounts { + my ($self, $myconfig, $form) = @_; + + my ($query, $sth, $ref); + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + # get chart of accounts + $query = qq|SELECT accno,description + FROM chart + WHERE charttype = 'A' + AND category = 'Q' + ORDER by accno|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + $form->{chart} = ""; + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{chart} }, $ref; + } + $sth->finish; + $dbh->disconnect; + +} + + +sub post_yearend { + my ($self, $myconfig, $form) = @_; + + # connect to database, turn off AutoCommit + my $dbh = $form->dbconnect_noauto($myconfig); + + my $query; + my $uid = time; + $uid .= $form->{login}; + + $query = qq|INSERT INTO gl (reference, employee_id) + VALUES ('$uid', (SELECT id FROM employee + WHERE login = '$form->{login}'))|; + $dbh->do($query) || $form->dberror($query); + + $query = qq|SELECT id FROM gl + WHERE reference = '$uid'|; + ($form->{id}) = $dbh->selectrow_array($query); + + $query = qq|UPDATE gl SET + reference = |.$dbh->quote($form->{reference}).qq|, + description = |.$dbh->quote($form->{description}).qq|, + notes = |.$dbh->quote($form->{notes}).qq|, + transdate = '$form->{transdate}', + department_id = 0 + WHERE id = $form->{id}|; + + $dbh->do($query) || $form->dberror($query); + + my $amount; + my $accno; + + # insert acc_trans transactions + for my $i (1 .. $form->{rowcount}) { + # extract accno + ($accno) = split(/--/, $form->{"accno_$i"}); + $amount = 0; + + if ($form->{"credit_$i"} != 0) { + $amount = $form->{"credit_$i"}; + } + if ($form->{"debit_$i"} != 0) { + $amount = $form->{"debit_$i"} * -1; + } + + + # if there is an amount, add the record + if ($amount != 0) { + $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, + source) + VALUES + ($form->{id}, (SELECT id + FROM chart + WHERE accno = '$accno'), + $amount, '$form->{transdate}', | + .$dbh->quote($form->{reference}).qq|)|; + + $dbh->do($query) || $form->dberror($query); + } + } + + $query = qq|INSERT INTO yearend (trans_id, transdate) + VALUES ($form->{id}, '$form->{transdate}')|; + $dbh->do($query) || $form->dberror($query); + + my %audittrail = ( tablename => 'gl', + reference => $form->{reference}, + formname => 'yearend', + action => 'posted', + id => $form->{id} ); + $form->audittrail($dbh, "", \%audittrail); + # commit and redirect + my $rc = $dbh->commit; + $dbh->disconnect; + + $rc; + } diff --git a/sql-ledger/SL/AP.pm b/sql-ledger/SL/AP.pm index e1870f872..05bc77a3a 100644 --- a/sql-ledger/SL/AP.pm +++ b/sql-ledger/SL/AP.pm @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -36,12 +36,17 @@ sub post_transaction { # connect to database my $dbh = $form->dbconnect_noauto($myconfig); - my ($null, $taxrate, $amount); + my $null; + my $taxrate; + my $amount; my $exchangerate = 0; # split and store id numbers in link accounts - ($form->{AP}{payables}) = split(/--/, $form->{AP}); - map { ($form->{AP}{"amount_$_"}) = split(/--/, $form->{"AP_amount_$_"}) } (1 .. $form->{rowcount}); + map { ($form->{AP_amounts}{"amount_$_"}) = split(/--/, $form->{"AP_amount_$_"}) } (1 .. $form->{rowcount}); + ($form->{AP_amounts}{payables}) = split(/--/, $form->{AP}); + + ($null, $form->{department_id}) = split(/--/, $form->{department}); + $form->{department_id} *= 1; if ($form->{currency} eq $form->{defaultcurrency}) { $form->{exchangerate} = 1; @@ -54,71 +59,59 @@ sub post_transaction { # reverse and parse amounts for my $i (1 .. $form->{rowcount}) { $form->{"amount_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"amount_$i"}) * $form->{exchangerate} * -1, 2); - $amount += ($form->{"amount_$i"} * -1); + $form->{netamount} += ($form->{"amount_$i"} * -1); } - # this is for ap - $form->{amount} = $amount; # taxincluded doesn't make sense if there is no amount - $form->{taxincluded} = 0 if ($form->{amount} == 0); + $form->{taxincluded} = 0 if ($form->{netamount} == 0); for my $item (split / /, $form->{taxaccounts}) { - $form->{AP}{"tax_$item"} = $item; + $form->{AP_amounts}{"tax_$item"} = $item; - $amount = $form->round_amount($form->parse_amount($myconfig, $form->{"tax_$item"}), 2); - - $form->{"tax_$item"} = $form->round_amount($amount * $form->{exchangerate}, 2) * -1; - $form->{total_tax} += ($form->{"tax_$item"} * -1); + $form->{"tax_$item"} = $form->round_amount($form->parse_amount($myconfig, $form->{"tax_$item"}) * $form->{exchangerate}, 2) * -1; + $form->{tax} += ($form->{"tax_$item"} * -1); } # adjust paidaccounts if there is no date in the last row $form->{paidaccounts}-- unless ($form->{"datepaid_$form->{paidaccounts}"}); - $form->{invpaid} = 0; + $form->{paid} = 0; # add payments for my $i (1 .. $form->{paidaccounts}) { $form->{"paid_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"paid_$i"}), 2); - $form->{invpaid} += $form->{"paid_$i"}; + $form->{paid} += $form->{"paid_$i"}; $form->{datepaid} = $form->{"datepaid_$i"}; } - $form->{invpaid} = $form->round_amount($form->{invpaid} * $form->{exchangerate}, 2); if ($form->{taxincluded} *= 1) { for $i (1 .. $form->{rowcount}) { - $tax = $form->{total_tax} * $form->{"amount_$i"} / $form->{amount}; + $tax = ($form->{netamount}) ? $form->{tax} * $form->{"amount_$i"} / $form->{netamount} : 0; $amount = $form->{"amount_$i"} - $tax; $form->{"amount_$i"} = $form->round_amount($amount, 2); $diff += $amount - $form->{"amount_$i"}; } - # deduct taxes from amount - $form->{amount} -= $form->{total_tax}; + $form->{netamount} -= $form->{tax}; # deduct difference from amount_1 $form->{amount_1} += $form->round_amount($diff, 2); } - $form->{netamount} = $form->{amount}; + $form->{amount} = $form->{netamount} + $form->{tax}; + $form->{paid} = $form->round_amount($form->{paid} * $form->{exchangerate}, 2); - # store invoice total, this goes into ap table - $form->{invtotal} = $form->{amount} + $form->{total_tax}; - - # amount for total AP - $form->{payables} = $form->{invtotal}; - - - my ($query, $sth); + my $query; + my $sth; # if we have an id delete old records if ($form->{id}) { # delete detail records $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|; - $dbh->do($query) || $form->dberror($query); } else { @@ -132,37 +125,33 @@ sub post_transaction { $query = qq|SELECT id FROM ap WHERE invnumber = '$uid'|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - ($form->{id}) = $sth->fetchrow_array; - $sth->finish; - + ($form->{id}) = $dbh->selectrow_array($query); } - # escape ' - $form->{notes} =~ s/'/''/g; - $form->{datepaid} = $form->{transdate} unless ($form->{datepaid}); - my $datepaid = ($form->{invpaid} != 0) ? qq|'$form->{datepaid}'| : 'NULL'; + my $datepaid = ($form->{paid} != 0) ? qq|'$form->{datepaid}'| : 'NULL'; $query = qq|UPDATE ap SET - invnumber = '$form->{invnumber}', + invnumber = |.$dbh->quote($form->{invnumber}).qq|, transdate = '$form->{transdate}', - ordnumber = '$form->{ordnumber}', + ordnumber = |.$dbh->quote($form->{ordnumber}).qq|, vendor_id = $form->{vendor_id}, taxincluded = '$form->{taxincluded}', - amount = $form->{invtotal}, - duedate = '$form->{duedate}', - paid = $form->{invpaid}, + amount = $form->{amount}, + duedate = |.$form->dbquote($form->{duedate}, SQL_DATE).qq|, + paid = $form->{paid}, datepaid = $datepaid, netamount = $form->{netamount}, - curr = '$form->{currency}', - notes = '$form->{notes}' + curr = |.$dbh->quote($form->{currency}).qq|, + notes = |.$dbh->quote($form->{notes}).qq|, + department_id = $form->{department_id} WHERE id = $form->{id} |; $dbh->do($query) || $form->dberror($query); + # amount for AP account + $form->{payables} = $form->{amount}; + # update exchangerate if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) { @@ -170,12 +159,14 @@ sub post_transaction { } # add individual transactions - foreach my $item (keys %{ $form->{AP} }) { + foreach my $item (keys %{ $form->{AP_amounts} }) { + if ($form->{$item} != 0) { + $project_id = 'NULL'; if ($item =~ /amount_/) { - if ($form->{"project_id_$'"} && $form->{"projectnumber_$'"}) { - $project_id = $form->{"project_id_$'"}; + if ($form->{"projectnumber_$'"}) { + ($null, $project_id) = split /--/, $form->{"projectnumber_$'"} } } @@ -183,20 +174,25 @@ sub post_transaction { $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, project_id) VALUES ($form->{id}, (SELECT id FROM chart - WHERE accno = '$form->{AP}{$item}'), + WHERE accno = '$form->{AP_amounts}{$item}'), $form->{$item}, '$form->{transdate}', $project_id)|; $dbh->do($query) || $form->dberror($query); } } # if there is no amount but a payment record a payable - if ($form->{amount} == 0 && $form->{invtotal} == 0) { - $form->{payables} = $form->{invpaid}; + if ($form->{amount} == 0) { + $form->{payables} = $form->{paid}; + $form->{payables} -= $form->{paid_1} if $form->{amount_1} != 0; } # add paid transactions for my $i (1 .. $form->{paidaccounts}) { if ($form->{"paid_$i"} != 0) { + + # get paid account + ($form->{AP_amounts}{"paid_$i"}) = split(/--/, $form->{"AP_paid_$i"}); + $form->{"datepaid_$i"} = $form->{transdate} unless ($form->{"datepaid_$i"}); $exchangerate = 0; if ($form->{currency} eq $form->{defaultcurrency}) { @@ -208,22 +204,18 @@ sub post_transaction { } - # get paid account - ($form->{AP}{"paid_$i"}) = split(/--/, $form->{"AP_paid_$i"}); - $form->{"datepaid_$i"} = $form->{transdate} unless ($form->{"datepaid_$i"}); - - # if there is no amount and invtotal is zero there is no exchangerate - if ($form->{amount} == 0 && $form->{invtotal} == 0) { + # if there is no amount + if ($form->{amount} == 0 && $form->{netamount} == 0) { $form->{exchangerate} = $form->{"exchangerate_$i"}; } $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} * -1, 2); - if ($form->{payables}) { + if ($form->{payables} != 0) { $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate) VALUES ($form->{id}, - (SELECT id FROM chart - WHERE accno = '$form->{AP}{payables}'), + (SELECT id FROM chart + WHERE accno = '$form->{AP_amounts}{payables}'), $amount, '$form->{"datepaid_$i"}')|; $dbh->do($query) || $form->dberror($query); } @@ -231,12 +223,13 @@ sub post_transaction { # add payment $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, - transdate, source) + transdate, source, memo) VALUES ($form->{id}, - (SELECT id FROM chart - WHERE accno = '$form->{AP}{"paid_$i"}'), - $form->{"paid_$i"}, '$form->{"datepaid_$i"}', - '$form->{"source_$i"}')|; + (SELECT id FROM chart + WHERE accno = '$form->{AP_amounts}{"paid_$i"}'), + $form->{"paid_$i"}, '$form->{"datepaid_$i"}', | + .$dbh->quote($form->{"source_$i"}).qq|, | + .$dbh->quote($form->{"memo_$i"}).qq|)|; $dbh->do($query) || $form->dberror($query); # add exchange rate difference @@ -245,8 +238,8 @@ sub post_transaction { $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, fx_transaction, cleared) VALUES ($form->{id}, - (SELECT id FROM chart - WHERE accno = '$form->{AP}{"paid_$i"}'), + (SELECT id FROM chart + WHERE accno = '$form->{AP_amounts}{"paid_$i"}'), $amount, '$form->{"datepaid_$i"}', '1', '0')|; $dbh->do($query) || $form->dberror($query); @@ -260,7 +253,7 @@ sub post_transaction { $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, fx_transaction, cleared) VALUES ($form->{id}, (SELECT id FROM chart - WHERE accno = '$accno'), + WHERE accno = '$accno'), $amount, '$form->{"datepaid_$i"}', '1', '0')|; $dbh->do($query) || $form->dberror($query); } @@ -271,6 +264,16 @@ sub post_transaction { } } } + + # save printed and queued + $form->save_status($dbh); + + my %audittrail = ( tablename => 'ap', + reference => $form->{invnumber}, + formname => 'transaction', + action => 'posted', + id => $form->{id} ); + $form->audittrail($dbh, "", \%audittrail); my $rc = $dbh->commit; $dbh->disconnect; @@ -283,24 +286,52 @@ sub post_transaction { sub delete_transaction { - my ($self, $myconfig, $form) = @_; + my ($self, $myconfig, $form, $spool) = @_; # connect to database my $dbh = $form->dbconnect_noauto($myconfig); - # check for other foreign currency transactions - $form->delete_exchangerate($dbh) if ($form->{currency} ne $form->{defaultcurrency}); - + my %audittrail = ( tablename => 'ap', + reference => $form->{invnumber}, + formname => 'transaction', + action => 'deleted', + id => $form->{id} ); + $form->audittrail($dbh, "", \%audittrail); + my $query = qq|DELETE FROM ap WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|; $dbh->do($query) || $form->dberror($query); + + # delete spool files + $query = qq|SELECT spoolfile FROM status + WHERE trans_id = $form->{id} + AND spoolfile IS NOT NULL|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my $spoolfile; + my @spoolfiles = (); + + while (($spoolfile) = $sth->fetchrow_array) { + push @spoolfiles, $spoolfile; + } + $sth->finish; + + $query = qq|DELETE FROM status WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); # commit and redirect my $rc = $dbh->commit; $dbh->disconnect; + if ($rc) { + foreach $spoolfile (@spoolfiles) { + unlink "$spool/$spoolfile" if $spoolfile; + } + } + $rc; } @@ -313,62 +344,114 @@ sub ap_transactions { # connect to database my $dbh = $form->dbconnect($myconfig); - - my $incemp = qq|, (SELECT e.name FROM employee e - WHERE a.employee_id = e.id) AS employee - | if ($form->{l_employee}); - + my $var; + + my $paid = "a.paid"; + + if ($form->{outstanding}) { + $paid = qq|SELECT SUM(ac.amount) + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + WHERE ac.trans_id = a.id + AND (c.link LIKE '%AP_paid%' OR c.link = '')|; + $paid .= qq| + AND ac.transdate <= '$form->{transdateto}'| if $form->{transdateto}; + } + my $query = qq|SELECT a.id, a.invnumber, a.transdate, a.duedate, - a.amount, a.paid, a.ordnumber, v.name, a.invoice, - a.netamount, a.datepaid, a.notes - - $incemp - - FROM ap a, vendor v - WHERE a.vendor_id = v.id|; - + a.amount, ($paid) AS paid, a.ordnumber, v.name, + a.invoice, a.netamount, a.datepaid, a.notes, + a.vendor_id, e.name AS employee, m.name AS manager, + a.curr, ex.sell AS exchangerate + FROM ap a + JOIN vendor v ON (a.vendor_id = v.id) + LEFT JOIN employee e ON (a.employee_id = e.id) + LEFT JOIN employee m ON (e.managerid = m.id) + LEFT JOIN exchangerate ex ON (ex.curr = a.curr + AND ex.transdate = a.transdate) + |; + + my %ordinal = ( 'id' => 1, + 'invnumber' => 2, + 'transdate' => 3, + 'duedate' => 4, + 'ordnumber' => 7, + 'name' => 8, + 'datepaid' => 11, + 'employee' => 14, + 'manager' => 15, + 'curr' => 16 + ); + + my @a = (transdate, invnumber, name); + push @a, "employee" if $form->{l_employee}; + push @a, "manager" if $form->{l_manager}; + my $sortorder = $form->sort_order(\@a, \%ordinal); + + my $where = "1 = 1"; + if ($form->{vendor_id}) { - $query .= " AND a.vendor_id = $form->{vendor_id}"; + $where .= " AND a.vendor_id = $form->{vendor_id}"; } else { if ($form->{vendor}) { - my $vendor = $form->like(lc $form->{vendor}); - $query .= " AND lower(v.name) LIKE '$vendor'"; + $var = $form->like(lc $form->{vendor}); + $where .= " AND lower(v.name) LIKE '$var'"; } } + if ($form->{department}) { + my ($null, $department_id) = split /--/, $form->{department}; + $where .= " AND a.department_id = $department_id"; + } if ($form->{invnumber}) { - my $invnumber = $form->like(lc $form->{invnumber}); - $query .= " AND lower(a.invnumber) LIKE '$invnumber'"; + $var = $form->like(lc $form->{invnumber}); + $where .= " AND lower(a.invnumber) LIKE '$var'"; + $form->{open} = $form->{closed} = 0; } if ($form->{ordnumber}) { - my $ordnumber = $form->like(lc $form->{ordnumber}); - $query .= " AND lower(a.ordnumber) LIKE '$ordnumber'"; + $var = $form->like(lc $form->{ordnumber}); + $where .= " AND lower(a.ordnumber) LIKE '$var'"; + $form->{open} = $form->{closed} = 0; } if ($form->{notes}) { - my $notes = $form->like(lc $form->{notes}); - $query .= " AND lower(a.notes) LIKE '$notes'"; + $var = $form->like(lc $form->{notes}); + $where .= " AND lower(a.notes) LIKE '$var'"; } - $query .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; - $query .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + ($form->{transdatefrom}, $form->{transdateto}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month}; + + $where .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $where .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; if ($form->{open} || $form->{closed}) { unless ($form->{open} && $form->{closed}) { - $query .= " AND a.amount <> a.paid" if ($form->{open}); - $query .= " AND a.amount = a.paid" if ($form->{closed}); + $where .= " AND a.amount != a.paid" if ($form->{open}); + $where .= " AND a.amount = a.paid" if ($form->{closed}); } } - my @a = (transdate, invnumber, name); - push @a, "employee" if $self->{l_employee}; - my $sortorder = join ', ', $form->sort_columns(@a); - $sortorder = $form->{sort} unless $sortorder; - $query .= " ORDER by $sortorder"; + if ($form->{AP}) { + my ($accno) = split /--/, $form->{AP}; + $where .= qq| + AND a.id IN (SELECT ac.trans_id + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + WHERE a.id = ac.trans_id + AND c.accno = '$accno') + |; + } + + $query .= "WHERE $where + ORDER by $sortorder"; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $ap = $sth->fetchrow_hashref(NAME_lc)) { - push @{ $form->{AP} }, $ap; + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + $ref->{exchangerate} = 1 unless $ref->{exchangerate}; + if ($form->{outstanding}) { + next if $form->round_amount($ref->{amount}, 2) == $form->round_amount($ref->{paid}, 2); + } + push @{ $form->{transactions} }, $ref; } $sth->finish; diff --git a/sql-ledger/SL/AR.pm b/sql-ledger/SL/AR.pm index 4ea3d82c3..80487e406 100644 --- a/sql-ledger/SL/AR.pm +++ b/sql-ledger/SL/AR.pm @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -32,81 +32,87 @@ package AR; sub post_transaction { my ($self, $myconfig, $form) = @_; - my ($null, $taxrate, $amount, $tax, $diff); + my $null; + my $taxrate; + my $amount; + my $tax; + my $diff; my $exchangerate = 0; my $i; # split and store id numbers in link accounts - map { ($form->{AR}{"amount_$_"}) = split(/--/, $form->{"AR_amount_$_"}) } (1 .. $form->{rowcount}); - ($form->{AR}{receivables}) = split(/--/, $form->{AR}); - + map { ($form->{AR_amounts}{"amount_$_"}) = split(/--/, $form->{"AR_amount_$_"}) } (1 .. $form->{rowcount}); + ($form->{AR_amounts}{receivables}) = split(/--/, $form->{AR}); + + ($null, $form->{department_id}) = split(/--/, $form->{department}); + $form->{department_id} *= 1; + if ($form->{currency} eq $form->{defaultcurrency}) { $form->{exchangerate} = 1; } else { $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'buy'); + + $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate}); } - - $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate}); for $i (1 .. $form->{rowcount}) { $form->{"amount_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"amount_$i"}) * $form->{exchangerate}, 2); - $amount += $form->{"amount_$i"}; + + $form->{netamount} += $form->{"amount_$i"}; + } - # this is for ar - $form->{amount} = $amount; - + # taxincluded doesn't make sense if there is no amount - $form->{taxincluded} = 0 if ($form->{amount} == 0); + $form->{taxincluded} = 0 if ($form->{netamount} == 0); foreach my $item (split / /, $form->{taxaccounts}) { - $form->{AR}{"tax_$item"} = $item; - - $amount = $form->round_amount($form->parse_amount($myconfig, $form->{"tax_$item"}), 2); - - $form->{"tax_$item"} = $form->round_amount($amount * $form->{exchangerate}, 2); - $form->{total_tax} += $form->{"tax_$item"}; + $form->{AR_amounts}{"tax_$item"} = $item; + $form->{"tax_$item"} = $form->round_amount($form->parse_amount($myconfig, $form->{"tax_$item"}) * $form->{exchangerate}, 2); + $form->{tax} += $form->{"tax_$item"}; } # adjust paidaccounts if there is no date in the last row $form->{paidaccounts}-- unless ($form->{"datepaid_$form->{paidaccounts}"}); - $form->{invpaid} = 0; + $form->{paid} = 0; # add payments for $i (1 .. $form->{paidaccounts}) { $form->{"paid_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"paid_$i"}), 2); - $form->{invpaid} += $form->{"paid_$i"}; + $form->{paid} += $form->{"paid_$i"}; $form->{datepaid} = $form->{"datepaid_$i"}; - # reverse payment - $form->{"paid_$i"} *= -1; - } - - $form->{invpaid} = $form->round_amount($form->{invpaid} * $form->{exchangerate}, 2); + if ($form->{taxincluded} *= 1) { for $i (1 .. $form->{rowcount}) { - $tax = $form->{total_tax} * $form->{"amount_$i"} / $form->{amount}; + $tax = ($form->{netamount}) ? $form->{tax} * $form->{"amount_$i"} / $form->{netamount} : 0; $amount = $form->{"amount_$i"} - $tax; $form->{"amount_$i"} = $form->round_amount($amount, 2); $diff += $amount - $form->{"amount_$i"}; } - $form->{amount} -= $form->{total_tax}; + $form->{netamount} -= $form->{tax}; # deduct difference from amount_1 $form->{amount_1} += $form->round_amount($diff, 2); } - # store invoice total, this goes into ar table - $form->{invtotal} = $form->{amount} + $form->{total_tax}; + $form->{amount} = $form->{netamount} + $form->{tax}; + $form->{paid} = $form->round_amount($form->{paid} * $form->{exchangerate}, 2); # connect to database my $dbh = $form->dbconnect_noauto($myconfig); - my ($query, $sth); + my $query; + my $sth; + + ($null, $form->{employee_id}) = split /--/, $form->{employee}; + unless ($form->{employee_id}) { + ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh); + } # if we have an id delete old records if ($form->{id}) { @@ -119,47 +125,41 @@ sub post_transaction { my $uid = time; $uid .= $form->{login}; - $query = qq|INSERT INTO ar (invnumber, employee_id) - VALUES ('$uid', (SELECT id FROM employee - WHERE login = '$form->{login}') )|; + $query = qq|INSERT INTO ar (invnumber) + VALUES ('$uid')|; $dbh->do($query) || $form->dberror($query); $query = qq|SELECT id FROM ar WHERE invnumber = '$uid'|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - ($form->{id}) = $sth->fetchrow_array; - $sth->finish; - + ($form->{id}) = $dbh->selectrow_array($query); } - # escape ' - $form->{notes} =~ s/'/''/g; - + # record last payment date in ar table $form->{datepaid} = $form->{transdate} unless $form->{datepaid}; - my $datepaid = ($form->{invpaid} != 0) ? qq|'$form->{datepaid}'| : 'NULL'; - + my $datepaid = ($form->{paid} != 0) ? qq|'$form->{datepaid}'| : 'NULL'; + $query = qq|UPDATE ar set - invnumber = '$form->{invnumber}', - ordnumber = '$form->{ordnumber}', + invnumber = |.$dbh->quote($form->{invnumber}).qq|, + ordnumber = |.$dbh->quote($form->{ordnumber}).qq|, transdate = '$form->{transdate}', customer_id = $form->{customer_id}, taxincluded = '$form->{taxincluded}', - amount = $form->{invtotal}, + amount = $form->{amount}, duedate = '$form->{duedate}', - paid = $form->{invpaid}, + paid = $form->{paid}, datepaid = $datepaid, - netamount = $form->{amount}, + netamount = $form->{netamount}, curr = '$form->{currency}', - notes = '$form->{notes}' + notes = |.$dbh->quote($form->{notes}).qq|, + department_id = $form->{department_id}, + employee_id = $form->{employee_id} WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); # amount for AR account - $form->{receivables} = $form->round_amount($form->{invtotal} * -1, 2); + $form->{receivables} = $form->{amount} * -1; # update exchangerate @@ -168,12 +168,14 @@ sub post_transaction { } # add individual transactions for AR, amount and taxes - foreach my $item (keys %{ $form->{AR} }) { + foreach my $item (keys %{ $form->{AR_amounts} }) { + if ($form->{$item} != 0) { + $project_id = 'NULL'; if ($item =~ /amount_/) { - if ($form->{"project_id_$'"} && $form->{"projectnumber_$'"}) { - $project_id = $form->{"project_id_$'"}; + if ($form->{"projectnumber_$'"}) { + ($null, $project_id) = split /--/, $form->{"projectnumber_$'"}; } } @@ -181,22 +183,22 @@ sub post_transaction { $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, project_id) VALUES ($form->{id}, (SELECT id FROM chart - WHERE accno = '$form->{AR}{$item}'), + WHERE accno = '$form->{AR_amounts}{$item}'), $form->{$item}, '$form->{transdate}', $project_id)|; $dbh->do($query) || $form->dberror($query); } } - # if there is no amount but a payment record a receivables - if ($form->{amount} == 0 && $form->{invtotal} == 0) { - $form->{receivables} = $form->{invpaid} * -1; + if ($form->{amount} == 0) { + $form->{receivables} = $form->{paid}; + $form->{receivables} -= $form->{paid_1} if $form->{amount_1} != 0; } - + # add paid transactions for my $i (1 .. $form->{paidaccounts}) { if ($form->{"paid_$i"} != 0) { - ($form->{AR}{"paid_$i"}) = split(/--/, $form->{"AR_paid_$i"}); + ($form->{AR_amounts}{"paid_$i"}) = split(/--/, $form->{"AR_paid_$i"}); $form->{"datepaid_$i"} = $form->{transdate} unless ($form->{"datepaid_$i"}); $exchangerate = 0; @@ -208,14 +210,14 @@ sub post_transaction { $form->{"exchangerate_$i"} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{"exchangerate_$i"}); } - - # if there is no amount and invtotal is zero there is no exchangerate - if ($form->{amount} == 0 && $form->{invtotal} == 0) { + + # if there is no amount + if ($form->{amount} == 0 && $form->{netamount} == 0) { $form->{exchangerate} = $form->{"exchangerate_$i"}; } # receivables amount - $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} * -1, 2); + $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate}, 2); if ($form->{receivables} != 0) { # add receivable @@ -223,47 +225,51 @@ sub post_transaction { transdate) VALUES ($form->{id}, (SELECT id FROM chart - WHERE accno = '$form->{AR}{receivables}'), + WHERE accno = '$form->{AR_amounts}{receivables}'), $amount, '$form->{"datepaid_$i"}')|; $dbh->do($query) || $form->dberror($query); } $form->{receivables} = $amount; - # add payment - $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, - transdate, source) - VALUES ($form->{id}, - (SELECT id FROM chart - WHERE accno = '$form->{AR}{"paid_$i"}'), - $form->{"paid_$i"}, '$form->{"datepaid_$i"}', - '$form->{"source_$i"}')|; - $dbh->do($query) || $form->dberror($query); - - - # exchangerate difference for payment - $amount = $form->round_amount($form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1), 2); - - if ($amount != 0) { + if ($form->{"paid_$i"} != 0) { + # add payment + $amount = $form->{"paid_$i"} * -1; $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, - transdate, fx_transaction, cleared) + transdate, source, memo) VALUES ($form->{id}, - (SELECT id FROM chart - WHERE accno = '$form->{AR}{"paid_$i"}'), - $amount, '$form->{"datepaid_$i"}', '1', '0')|; + (SELECT id FROM chart + WHERE accno = '$form->{AR_amounts}{"paid_$i"}'), + $amount, '$form->{"datepaid_$i"}', | + .$dbh->quote($form->{"source_$i"}).qq|, | + .$dbh->quote($form->{"memo_$i"}).qq|)|; $dbh->do($query) || $form->dberror($query); - } - # exchangerate gain/loss - $amount = $form->round_amount($form->{"paid_$i"} * ($form->{exchangerate} - $form->{"exchangerate_$i"}), 2); - - if ($amount != 0) { - $accno = ($amount > 0) ? $form->{fxgain_accno} : $form->{fxloss_accno}; - $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, - transdate, fx_transaction, cleared) - VALUES ($form->{id}, (SELECT id FROM chart - WHERE accno = '$accno'), - $amount, '$form->{"datepaid_$i"}', '1', '0')|; - $dbh->do($query) || $form->dberror($query); + + # exchangerate difference for payment + $amount = $form->round_amount($form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) * -1, 2); + + if ($amount != 0) { + $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, + transdate, fx_transaction, cleared) + VALUES ($form->{id}, + (SELECT id FROM chart + WHERE accno = '$form->{AR_amounts}{"paid_$i"}'), + $amount, '$form->{"datepaid_$i"}', '1', '0')|; + $dbh->do($query) || $form->dberror($query); + } + + # exchangerate gain/loss + $amount = $form->round_amount($form->{"paid_$i"} * ($form->{exchangerate} - $form->{"exchangerate_$i"}) * -1, 2); + + if ($amount != 0) { + $accno = ($amount > 0) ? $form->{fxgain_accno} : $form->{fxloss_accno}; + $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, + transdate, fx_transaction, cleared) + VALUES ($form->{id}, (SELECT id FROM chart + WHERE accno = '$accno'), + $amount, '$form->{"datepaid_$i"}', '1', '0')|; + $dbh->do($query) || $form->dberror($query); + } } # update exchangerate record @@ -273,7 +279,17 @@ sub post_transaction { } } - + # save printed and queued + $form->save_status($dbh); + + my %audittrail = ( tablename => 'ar', + reference => $form->{invnumber}, + formname => 'transaction', + action => 'posted', + id => $form->{id} ); + + $form->audittrail($dbh, "", \%audittrail); + my $rc = $dbh->commit; $dbh->disconnect; @@ -288,19 +304,48 @@ sub delete_transaction { # connect to database, turn AutoCommit off my $dbh = $form->dbconnect_noauto($myconfig); + + my %audittrail = ( tablename => 'ar', + reference => $form->{invnumber}, + formname => 'transaction', + action => 'deleted', + id => $form->{id} ); - # check for other foreign currency transactions - $form->delete_exchangerate($dbh) if ($form->{currency} ne $form->{defaultcurrency}); - + $form->audittrail($dbh, "", \%audittrail); + my $query = qq|DELETE FROM ar WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|; $dbh->do($query) || $form->dberror($query); + + # delete spool files + $query = qq|SELECT spoolfile FROM status + WHERE trans_id = $form->{id} + AND spoolfile IS NOT NULL|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my $spoolfile; + my @spoolfiles = (); + + while (($spoolfile) = $sth->fetchrow_array) { + push @spoolfiles, $spoolfile; + } + $sth->finish; + + $query = qq|DELETE FROM status WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); # commit my $rc = $dbh->commit; $dbh->disconnect; + + if ($rc) { + foreach $spoolfile (@spoolfiles) { + unlink "$spool/$spoolfile" if $spoolfile; + } + } $rc; @@ -313,62 +358,128 @@ sub ar_transactions { # connect to database my $dbh = $form->dbconnect($myconfig); + my $var; + + my $paid = "a.paid"; + + ($form->{transdatefrom}, $form->{transdateto}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month}; + + if ($form->{outstanding}) { + $paid = qq|SELECT SUM(ac.amount) * -1 + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + WHERE ac.trans_id = a.id + AND (c.link LIKE '%AR_paid%' OR c.link = '')|; + $paid .= qq| + AND ac.transdate <= '$form->{transdateto}'| if $form->{transdateto}; + } - my $incemp = qq|, (SELECT e.name FROM employee e - WHERE a.employee_id = e.id) AS employee - | if ($form->{l_employee}); - my $query = qq|SELECT a.id, a.invnumber, a.ordnumber, a.transdate, - a.duedate, a.netamount, a.amount, a.paid, c.name, - a.invoice, a.datepaid, a.terms, a.notes, a.shippingpoint - - $incemp - - FROM ar a, customer c - WHERE a.customer_id = c.id|; + a.duedate, a.netamount, a.amount, ($paid) AS paid, + a.invoice, a.datepaid, a.terms, a.notes, + a.shipvia, a.shippingpoint, e.name AS employee, c.name, + a.customer_id, a.till, m.name AS manager, a.curr, + ex.buy AS exchangerate + FROM ar a + JOIN customer c ON (a.customer_id = c.id) + LEFT JOIN employee e ON (a.employee_id = e.id) + LEFT JOIN employee m ON (e.managerid = m.id) + LEFT JOIN exchangerate ex ON (ex.curr = a.curr + AND ex.transdate = a.transdate) + |; + + my %ordinal = ( 'id' => 1, + 'invnumber' => 2, + 'ordnumber' => 3, + 'transdate' => 4, + 'duedate' => 5, + 'datepaid' => 10, + 'shipvia' => 13, + 'shippingpoint' => 14, + 'employee' => 15, + 'name' => 16, + 'manager' => 19, + 'curr' => 20 + ); + + + my @a = (transdate, invnumber, name); + push @a, "employee" if $form->{l_employee}; + push @a, "manager" if $form->{l_manager}; + my $sortorder = $form->sort_order(\@a, \%ordinal); + my $where = "1 = 1"; if ($form->{customer_id}) { - $query .= " AND a.customer_id = $form->{customer_id}"; + $where .= " AND a.customer_id = $form->{customer_id}"; } else { if ($form->{customer}) { - my $customer = $form->like(lc $form->{customer}); - $query .= " AND lower(c.name) LIKE '$customer'"; + $var = $form->like(lc $form->{customer}); + $where .= " AND lower(c.name) LIKE '$var'"; } } + if ($form->{department}) { + my ($null, $department_id) = split /--/, $form->{department}; + $where .= " AND a.department_id = $department_id"; + } if ($form->{invnumber}) { - my $invnumber = $form->like(lc $form->{invnumber}); - $query .= " AND lower(a.invnumber) LIKE '$invnumber'"; + $var = $form->like(lc $form->{invnumber}); + $where .= " AND lower(a.invnumber) LIKE '$var'"; + $form->{open} = $form->{closed} = 0; } if ($form->{ordnumber}) { - my $ordnumber = $form->like(lc $form->{ordnumber}); - $query .= " AND lower(a.ordnumber) LIKE '$ordnumber'"; + $var = $form->like(lc $form->{ordnumber}); + $where .= " AND lower(a.ordnumber) LIKE '$var'"; + $form->{open} = $form->{closed} = 0; + } + if ($form->{shipvia}) { + $var = $form->like(lc $form->{shipvia}); + $where .= " AND lower(a.shipvia) LIKE '$var'"; } if ($form->{notes}) { - my $notes = $form->like(lc $form->{notes}); - $query .= " AND lower(a.notes) LIKE '$notes'"; + $var = $form->like(lc $form->{notes}); + $where .= " AND lower(a.notes) LIKE '$var'"; } - - $query .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; - $query .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + + $where .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $where .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; if ($form->{open} || $form->{closed}) { unless ($form->{open} && $form->{closed}) { - $query .= " AND a.amount <> a.paid" if ($form->{open}); - $query .= " AND a.amount = a.paid" if ($form->{closed}); + $where .= " AND a.amount != a.paid" if ($form->{open}); + $where .= " AND a.amount = a.paid" if ($form->{closed}); } } - my @a = (transdate, invnumber, name); - push @a, "employee" if $form->{l_employee}; - my $sortorder = join ', ', $form->sort_columns(@a); - $sortorder = $form->{sort} unless $sortorder; - - $query .= " ORDER by $sortorder"; + if ($form->{till}) { + $where .= " AND a.invoice = '1' + AND NOT a.till IS NULL"; + if ($myconfig->{role} eq 'user') { + $where .= " AND e.login = '$form->{login}'"; + } + } + + if ($form->{AR}) { + my ($accno) = split /--/, $form->{AR}; + $where .= qq| + AND a.id IN (SELECT ac.trans_id + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + WHERE a.id = ac.trans_id + AND c.accno = '$accno') + |; + } + $query .= "WHERE $where + ORDER by $sortorder"; + my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $ar = $sth->fetchrow_hashref(NAME_lc)) { - push @{ $form->{AR} }, $ar; + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + $ref->{exchangerate} = 1 unless $ref->{exchangerate}; + if ($form->{outstanding}) { + next if $form->round_amount($ref->{amount}, 2) == $form->round_amount($ref->{paid}, 2); + } + push @{ $form->{transactions} }, $ref; } $sth->finish; diff --git a/sql-ledger/SL/BP.pm b/sql-ledger/SL/BP.pm new file mode 100644 index 000000000..d85077db2 --- /dev/null +++ b/sql-ledger/SL/BP.pm @@ -0,0 +1,371 @@ +#===================================================================== +# SQL-Ledger Accounting +# Copyright (C) 2003 +# +# 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. +#====================================================================== +# +# Batch printing module backend routines +# +#====================================================================== + +package BP; + + +sub get_vc { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my %arap = ( invoice => ['ar'], + packing_list => ['oe', 'ar'], + sales_order => ['oe'], + work_order => ['oe'], + pick_list => ['oe', 'ar'], + purchase_order => ['oe'], + bin_list => ['oe'], + sales_quotation => ['oe'], + request_quotation => ['oe'], + check => ['ap'], + receipt => ['ar'] + ); + + my $query = ""; + my $sth; + my $n; + my $count; + my $item; + + foreach $item (@{ $arap{$form->{type}} }) { + $query = qq| + SELECT count(*) + FROM (SELECT DISTINCT vc.id + FROM $form->{vc} vc, $item a, status s + WHERE a.$form->{vc}_id = vc.id + AND s.trans_id = a.id + AND s.formname = '$form->{type}' + AND s.spoolfile IS NOT NULL) AS total|; + ($n) = $dbh->selectrow_array($query); + $count += $n; + } + + + # build selection list + my $union = ""; + $query = ""; + if ($count < $myconfig->{vclimit}) { + foreach $item (@{ $arap{$form->{type}} }) { + $query .= qq| + $union + SELECT DISTINCT vc.id, vc.name + FROM $form->{vc} vc, $item a, status s + WHERE a.$form->{vc}_id = vc.id + AND s.trans_id = a.id + AND s.formname = '$form->{type}' + AND s.spoolfile IS NOT NULL|; + $union = "UNION"; + } + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{"all_$form->{vc}"} }, $ref; + } + $sth->finish; + } + + $form->all_years($dbh, $myconfig); + + $dbh->disconnect; + +} + + + +sub payment_accounts { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT DISTINCT c.accno, c.description + FROM status s, chart c + WHERE s.chart_id = c.id + AND s.formname = '$form->{type}'|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{accounts} }, $ref; + } + + $sth->finish; + $dbh->disconnect; + +} + + +sub get_spoolfiles { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $query; + my $invnumber = "invnumber"; + my $item; + + my %arap = ( invoice => ['ar'], + packing_list => ['oe', 'ar'], + sales_order => ['oe'], + work_order => ['oe'], + pick_list => ['oe', 'ar'], + purchase_order => ['oe'], + bin_list => ['oe'], + sales_quotation => ['oe'], + request_quotation => ['oe'], + check => ['ap'], + receipt => ['ar'] + ); + + + if ($form->{type} eq 'check' || $form->{type} eq 'receipt') { + + my ($accno) = split /--/, $form->{account}; + + $query = qq|SELECT a.id, vc.name, a.invnumber, ac.transdate, s.spoolfile, + a.invoice, '$arap{$form->{type}}[0]' AS module + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + JOIN $arap{$form->{type}}[0] a ON (a.id = ac.trans_id) + JOIN status s ON (s.trans_id = a.id) + JOIN $form->{vc} vc ON (vc.id = a.$form->{vc}_id) + WHERE s.formname = '$form->{type}' + AND c.accno = '$accno' + AND NOT ac.fx_transaction|; + + if ($form->{"$form->{vc}_id"}) { + $query .= qq| AND a.$form->{vc}_id = $form->{"$form->{vc}_id"}|; + } else { + if ($form->{$form->{vc}}) { + $item = $form->like(lc $form->{$form->{vc}}); + $query .= " AND lower(vc.name) LIKE '$item'"; + } + } + if ($form->{invnumber}) { + $item = $form->like(lc $form->{invnumber}); + $query .= " AND lower(a.invnumber) LIKE '$item'"; + } + if ($form->{ordnumber}) { + $item = $form->like(lc $form->{ordnumber}); + $query .= " AND lower(a.ordnumber) LIKE '$item'"; + } + if ($form->{quonumber}) { + $item = $form->like(lc $form->{quonumber}); + $query .= " AND lower(a.quonumber) LIKE '$item'"; + } + + $query .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $query .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + + + } else { + + foreach $item (@{ $arap{$form->{type}} }) { + + $invoice = "a.invoice"; + $invnumber = "invnumber"; + + if ($item eq 'oe') { + $invnumber = "ordnumber"; + $invoice = "'0'"; + } + + $query .= qq| + $union + SELECT a.id, vc.name, a.$invnumber AS invnumber, a.transdate, + a.ordnumber, a.quonumber, $invoice AS invoice, + '$item' AS module, s.spoolfile + FROM $item a, $form->{vc} vc, status s + WHERE s.trans_id = a.id + AND s.spoolfile IS NOT NULL + AND s.formname = '$form->{type}' + AND a.$form->{vc}_id = vc.id|; + + if ($form->{"$form->{vc}_id"}) { + $query .= qq| AND a.$form->{vc}_id = $form->{"$form->{vc}_id"}|; + } else { + if ($form->{$form->{vc}}) { + $item = $form->like(lc $form->{$form->{vc}}); + $query .= " AND lower(vc.name) LIKE '$item'"; + } + } + if ($form->{invnumber}) { + $item = $form->like(lc $form->{invnumber}); + $query .= " AND lower(a.invnumber) LIKE '$item'"; + } + if ($form->{ordnumber}) { + $item = $form->like(lc $form->{ordnumber}); + $query .= " AND lower(a.ordnumber) LIKE '$item'"; + } + if ($form->{quonumber}) { + $item = $form->like(lc $form->{quonumber}); + $query .= " AND lower(a.quonumber) LIKE '$item'"; + } + + $query .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $query .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + + $union = "UNION"; + + } + } + + my %ordinal = ( 'name' => 2, + 'invnumber' => 3, + 'transdate' => 4, + 'ordnumber' => 5, + 'quonumber' => 6 + ); + my @a = (transdate, $invnumber, name); + my $sortorder = $form->sort_order(\@a, \%ordinal); + + $query .= " ORDER by $sortorder"; + + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{SPOOL} }, $ref; + } + + $sth->finish; + $dbh->disconnect; + +} + + +sub delete_spool { + my ($self, $myconfig, $form, $spool) = @_; + + # connect to database, turn AutoCommit off + my $dbh = $form->dbconnect_noauto($myconfig); + + my $query; + my %audittrail; + + if ($form->{type} =~ /(check|receipt)/) { + $query = qq|DELETE FROM status + WHERE spoolfile = ?|; + } else { + $query = qq|UPDATE status SET + spoolfile = NULL, + printed = '1' + WHERE spoolfile = ?|; + } + my $sth = $dbh->prepare($query) || $form->dberror($query); + + + foreach my $i (1 .. $form->{rowcount}) { + if ($form->{"checked_$i"}) { + $sth->execute($form->{"spoolfile_$i"}) || $form->dberror($query); + $sth->finish; + + %audittrail = ( tablename => $form->{module}, + reference => $form->{"reference_$i"}, + formname => $form->{type}, + action => 'dequeued', + id => $form->{"id_$i"} ); + + $form->audittrail($dbh, "", \%audittrail); + } + } + + # commit + my $rc = $dbh->commit; + $dbh->disconnect; + + if ($rc) { + foreach my $i (1 .. $form->{rowcount}) { + $_ = qq|$spool/$form->{"spoolfile_$i"}|; + if ($form->{"checked_$i"}) { + unlink; + } + } + } + + $rc; + +} + + +sub print_spool { + my ($self, $myconfig, $form, $spool) = @_; + + # connect to database + my $dbh = $form->dbconnect_noauto($myconfig); + + my %audittrail; + + my $query = qq|UPDATE status SET + printed = '1' + WHERE formname = '$form->{type}' + AND spoolfile = ?|; + my $sth = $dbh->prepare($query) || $form->dberror($query); + + foreach my $i (1 .. $form->{rowcount}) { + if ($form->{"checked_$i"}) { + open(OUT, $form->{OUT}) or $form->error("$form->{OUT} : $!"); + + $spoolfile = qq|$spool/$form->{"spoolfile_$i"}|; + + # send file to printer + open(IN, $spoolfile) or $form->error("$spoolfile : $!"); + + while () { + print OUT $_; + } + close(IN); + close(OUT); + + $sth->execute($form->{"spoolfile_$i"}) || $form->dberror($query); + $sth->finish; + + %audittrail = ( tablename => $form->{module}, + reference => $form->{"reference_$i"}, + formname => $form->{type}, + action => 'printed', + id => $form->{"id_$i"} ); + + $form->audittrail($dbh, "", \%audittrail); + + $dbh->commit; + } + } + + $dbh->disconnect; + +} + + +1; + diff --git a/sql-ledger/SL/CA.pm b/sql-ledger/SL/CA.pm index b71749d7c..2ae78bd5c 100644 --- a/sql-ledger/SL/CA.pm +++ b/sql-ledger/SL/CA.pm @@ -21,10 +21,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #====================================================================== -# chart of accounts # -# CHANGE LOG: -# DS. 2000-07-04 Created +# chart of accounts # #====================================================================== @@ -107,117 +105,339 @@ sub all_transactions { while (my ($id) = $sth->fetchrow_array) { push @id, $id; } - $sth->finish; - my $where = '1 = 1'; - # build WHERE clause from dates if any + my $fromdate_where; + my $todate_where; + + ($form->{fromdate}, $form->{todate}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month}; + if ($form->{fromdate}) { - $where .= " AND ac.transdate >= '$form->{fromdate}'"; + $fromdate_where = qq| + AND ac.transdate >= '$form->{fromdate}' + |; } if ($form->{todate}) { - $where .= " AND ac.transdate <= '$form->{todate}'"; + $todate_where .= qq| + AND ac.transdate <= '$form->{todate}' + |; } + - my $sortorder = join ', ', $form->sort_columns(qw(transdate reference description)); - my $false = ($myconfig->{dbdriver} eq 'Pg') ? FALSE : q|'0'|; + my $false = ($myconfig->{dbdriver} =~ /Pg/) ? FALSE : q|'0'|; # Oracle workaround, use ordinal positions my %ordinal = ( transdate => 4, reference => 2, description => 3 ); - map { $sortorder =~ s/$_/$ordinal{$_}/ } keys %ordinal; - - if ($form->{accno}) { + my @a = qw(transdate reference description); + my $sortorder = $form->sort_order(\@a, \%ordinal); + + my $null; + my $department_id; + my $dpt_where; + my $dpt_join; + + ($null, $department_id) = split /--/, $form->{department}; + + if ($department_id) { + $dpt_join = qq| + JOIN department t ON (t.id = a.department_id) + |; + $dpt_where = qq| + AND t.id = $department_id + |; + } + + my $project; + my $project_id; + if ($form->{projectnumber}) { + ($null, $project_id) = split /--/, $form->{projectnumber}; + $project = qq| + AND ac.project_id = $project_id + |; + } + + if ($form->{accno} || $form->{gifi_accno}) { # get category for account - $query = qq|SELECT category + $query = qq|SELECT category, link FROM chart WHERE accno = '$form->{accno}'|; + + if ($form->{accounttype} eq 'gifi') { + $query = qq|SELECT category, link + FROM chart + WHERE gifi_accno = '$form->{gifi_accno}' + AND charttype = 'A'|; + } + $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - ($form->{category}) = $sth->fetchrow_array; + ($form->{category}, $form->{link}) = $sth->fetchrow_array; $sth->finish; if ($form->{fromdate}) { + # get beginning balance $query = qq|SELECT SUM(ac.amount) - FROM acc_trans ac, chart c - WHERE ac.chart_id = c.id - AND c.accno = '$form->{accno}' - AND ac.transdate < date '$form->{fromdate}' + FROM acc_trans ac + JOIN chart c ON (ac.chart_id = c.id) + $dpt_join + WHERE c.accno = '$form->{accno}' + AND ac.transdate < '$form->{fromdate}' + $dpt_where + $project |; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - ($form->{balance}) = $sth->fetchrow_array; - $sth->finish; - } - } - - if ($form->{accounttype} eq 'gifi' && $form->{gifi_accno}) { - # get category for account - $query = qq|SELECT category - FROM chart - WHERE gifi_accno = '$form->{gifi_accno}'|; - $sth = $dbh->prepare($query); + if ($project_id) { + + $query .= qq| + + UNION + + SELECT SUM(ac.sellprice * ac.qty) + FROM invoice ac + JOIN ar a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.income_accno_id = c.id) + $dpt_join + WHERE c.accno = '$form->{accno}' + AND a.transdate < '$form->{fromdate}' + AND c.category = 'I' + $dpt_where + $project + + UNION + + SELECT SUM(ac.sellprice * ac.qty) + FROM invoice ac + JOIN ap a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.expense_accno_id = c.id) + $dpt_join + WHERE c.accno = '$form->{accno}' + AND p.inventory_accno_id IS NULL + AND p.assembly = '0' + AND a.transdate < '$form->{fromdate}' + AND c.category = 'E' + $dpt_where + $project + + UNION + + SELECT SUM(ac.sellprice * ac.allocated) * -1 + FROM invoice ac + JOIN ap a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.expense_accno_id = c.id) + $dpt_join + WHERE c.accno = '$form->{accno}' + AND ac.assemblyitem = '0' + AND a.transdate < '$form->{fromdate}' + AND c.category = 'E' + $dpt_where + $project + |; - $sth->execute || $form->dberror($query); - ($form->{category}) = $sth->fetchrow_array; - $sth->finish; - - if ($form->{fromdate}) { - # get beginning balance - $query = qq|SELECT SUM(ac.amount) - FROM acc_trans ac, chart c - WHERE ac.chart_id = c.id - AND c.gifi_accno = '$form->{gifi_accno}' - AND ac.transdate < date '$form->{fromdate}' + } + + if ($form->{accounttype} eq 'gifi') { + $query = qq|SELECT SUM(ac.amount) + FROM acc_trans ac + JOIN chart c ON (ac.chart_id = c.id) + $dpt_join + WHERE c.gifi_accno = '$form->{gifi_accno}' + AND ac.transdate < '$form->{fromdate}' + $dpt_where + $project + |; + + if ($project_id) { + + $query .= qq| + + UNION + + SELECT SUM(ac.sellprice * ac.qty) + FROM invoice ac + JOIN ar a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.income_accno_id = c.id) + $dpt_join + WHERE c.gifi_accno = '$form->{gifi_accno}' + AND a.transdate < '$form->{fromdate}' + AND c.category = 'I' + $dpt_where + $project + + UNION + + SELECT SUM(ac.sellprice * ac.qty) + FROM invoice ac + JOIN ap a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.expense_accno_id = c.id) + $dpt_join + WHERE c.gifi_accno = '$form->{gifi_accno}' + AND p.inventory_accno_id IS NULL + AND p.assembly = '0' + AND a.transdate < '$form->{fromdate}' + AND c.category = 'E' + $dpt_where + $project + + UNION + + SELECT SUM(ac.sellprice * ac.allocated) * -1 + FROM invoice ac + JOIN ap a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.expense_accno_id = c.id) + $dpt_join + WHERE c.gifi_accno = '$form->{gifi_accno}' + AND ac.assemblyitem = '0' + AND a.transdate < '$form->{fromdate}' + AND c.category = 'E' + $dpt_where + $project |; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - ($form->{balance}) = $sth->fetchrow_array; - $sth->finish; + } + } + + ($form->{balance}) = $dbh->selectrow_array($query); + } } - + $query = ""; - + my $union = ""; + foreach my $id (@id) { # get all transactions - $query .= qq| - SELECT g.id, g.reference, g.description, ac.transdate, - $false AS invoice, - ac.amount, 'gl' as charttype - FROM gl g, acc_trans ac - WHERE $where - AND ac.chart_id = $id - AND ac.trans_id = g.id - UNION ALL - SELECT a.id, a.invnumber, c.name, ac.transdate, - a.invoice, - ac.amount, 'ar' as charttype - FROM ar a, acc_trans ac, customer c - WHERE $where - AND ac.chart_id = $id - AND ac.trans_id = a.id - AND a.customer_id = c.id - UNION ALL - SELECT a.id, a.invnumber, v.name, ac.transdate, - a.invoice, - ac.amount, 'ap' as charttype - FROM ap a, acc_trans ac, vendor v - WHERE $where - AND ac.chart_id = $id - AND ac.trans_id = a.id - AND a.vendor_id = v.id - UNION ALL|; + $query .= qq|$union + SELECT a.id, a.reference, a.description, ac.transdate, + $false AS invoice, ac.amount, 'gl' as module, ac.cleared, + '' AS till + FROM gl a + JOIN acc_trans ac ON (ac.trans_id = a.id) + $dpt_join + WHERE ac.chart_id = $id + $fromdate_where + $todate_where + $dpt_where + $project + + UNION ALL + + SELECT a.id, a.invnumber, c.name, ac.transdate, + a.invoice, ac.amount, 'ar' as module, ac.cleared, + a.till + FROM ar a + JOIN acc_trans ac ON (ac.trans_id = a.id) + JOIN customer c ON (a.customer_id = c.id) + $dpt_join + WHERE ac.chart_id = $id + $fromdate_where + $todate_where + $dpt_where + $project + + UNION ALL + + SELECT a.id, a.invnumber, v.name, ac.transdate, + a.invoice, ac.amount, 'ap' as module, ac.cleared, + a.till + FROM ap a + JOIN acc_trans ac ON (ac.trans_id = a.id) + JOIN vendor v ON (a.vendor_id = v.id) + $dpt_join + WHERE ac.chart_id = $id + $fromdate_where + $todate_where + $dpt_where + $project + |; + + if ($project_id) { + + $fromdate_where =~ s/ac\./a\./; + $todate_where =~ s/ac\./a\./; + + $query .= qq| + + UNION ALL + + -- sold items + + SELECT a.id, a.invnumber, c.name, a.transdate, + a.invoice, ac.sellprice * ac.qty, 'ar' as module, '0' AS cleared, + a.till + FROM ar a + JOIN invoice ac ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN customer c ON (a.customer_id = c.id) + $dpt_join + WHERE p.income_accno_id = $id + $fromdate_where + $todate_where + $dpt_where + $project + + UNION ALL + + -- bought services + + SELECT a.id, a.invnumber, v.name, a.transdate, + a.invoice, ac.sellprice * ac.qty, 'ap' as module, '0' AS cleared, + a.till + FROM ap a + JOIN invoice ac ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN vendor v ON (a.vendor_id = v.id) + $dpt_join + WHERE p.expense_accno_id = $id + AND p.inventory_accno_id IS NULL + AND p.assembly = '0' + $fromdate_where + $todate_where + $dpt_where + $project + + UNION ALL + + -- cogs + + SELECT a.id, a.invnumber, v.name, a.transdate, + a.invoice, ac.sellprice * ac.allocated * -1, 'ap' as module, '0' AS cleared, + a.till + FROM ap a + JOIN invoice ac ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN vendor v ON (a.vendor_id = v.id) + $dpt_join + WHERE p.expense_accno_id = $id + AND ac.assemblyitem = '0' + $fromdate_where + $todate_where + $dpt_where + $project + + |; + + $fromdate_where =~ s/a\./ac\./; + $todate_where =~ s/a\./ac\./; + + } + + $union = qq| + UNION ALL + |; } - $query =~ s/UNION ALL$//; $query .= qq| ORDER BY $sortorder|; @@ -225,32 +445,36 @@ sub all_transactions { $sth->execute || $form->dberror($query); while (my $ca = $sth->fetchrow_hashref(NAME_lc)) { - + # gl - if ($ca->{charttype} eq "gl") { + if ($ca->{module} eq "gl") { $ca->{module} = "gl"; } # ap - if ($ca->{charttype} eq "ap") { + if ($ca->{module} eq "ap") { $ca->{module} = ($ca->{invoice}) ? 'ir' : 'ap'; + $ca->{module} = 'ps' if $ca->{till}; } # ar - if ($ca->{charttype} eq "ar") { + if ($ca->{module} eq "ar") { $ca->{module} = ($ca->{invoice}) ? 'is' : 'ar'; + $ca->{module} = 'ps' if $ca->{till}; } - if ($ca->{amount} < 0) { - $ca->{debit} = $ca->{amount} * -1; - $ca->{credit} = 0; - } else { - $ca->{credit} = $ca->{amount}; - $ca->{debit} = 0; - } - - push @{ $form->{CA} }, $ca; + if ($ca->{amount}) { + if ($ca->{amount} < 0) { + $ca->{debit} = $ca->{amount} * -1; + $ca->{credit} = 0; + } else { + $ca->{credit} = $ca->{amount}; + $ca->{debit} = 0; + } + push @{ $form->{CA} }, $ca; + } + } $sth->finish; diff --git a/sql-ledger/SL/CP.pm b/sql-ledger/SL/CP.pm index f84bd1594..539ff6d9a 100644 --- a/sql-ledger/SL/CP.pm +++ b/sql-ledger/SL/CP.pm @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2002 +# Copyright (C) 2003 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -57,26 +57,32 @@ sub paymentaccounts { # connect to database my $dbh = $form->dbconnect($myconfig); - my $query = qq|SELECT accno, description + my $query = qq|SELECT accno, description, link FROM chart - WHERE link LIKE '%$form->{arap}_paid%' + WHERE link LIKE '%$form->{ARAP}%' ORDER BY accno|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); + $form->{PR}{$form->{ARAP}} = (); + $form->{PR}{"$form->{ARAP}_paid"} = (); + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { - push @{ $form->{PR} }, $ref; + foreach my $item (split /:/, $ref->{link}) { + if ($item eq $form->{ARAP}) { + push @{ $form->{PR}{$form->{ARAP}} }, $ref; + } + if ($item eq "$form->{ARAP}_paid") { + push @{ $form->{PR}{"$form->{ARAP}_paid"} }, $ref; + } + } } $sth->finish; # get currencies and closedto - $query = qq|SELECT curr, closedto + $query = qq|SELECT curr, closedto, current_date FROM defaults|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - ($form->{currencies}, $form->{closedto}) = $sth->fetchrow_array; - $sth->finish; + ($form->{currencies}, $form->{closedto}, $form->{datepaid}) = $dbh->selectrow_array($query); $dbh->disconnect; @@ -89,15 +95,14 @@ sub get_openvc { my $dbh = $form->dbconnect($myconfig); my $arap = ($form->{vc} eq 'customer') ? 'ar' : 'ap'; - my $query = qq|SELECT count(*) FROM $form->{vc} ct, $arap a WHERE a.$form->{vc}_id = ct.id AND a.amount != a.paid|; - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - my ($count) = $sth->fetchrow_array; - $sth->finish; + my ($count) = $dbh->selectrow_array($query); + + my $sth; + my $ref; # build selection list if ($count < $myconfig->{vclimit}) { @@ -109,7 +114,7 @@ sub get_openvc { $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { push @{ $form->{"all_$form->{vc}"} }, $ref; } @@ -117,6 +122,44 @@ sub get_openvc { } + if ($form->{ARAP} eq 'AR') { + $query = qq|SELECT id, description + FROM department + WHERE role = 'P' + ORDER BY 2|; + } else { + $query = qq|SELECT id, description + FROM department + ORDER BY 2|; + } + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_departments} }, $ref; + } + $sth->finish; + + # get language codes + $query = qq|SELECT * + FROM language + ORDER BY 2|; + $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); + + $form->{all_languages} = (); + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_languages} }, $ref; + } + $sth->finish; + + # get currency for first name + if ($form->{"all_$form->{vc}"}) { + $query = qq|SELECT curr FROM $form->{vc} + WHERE id = $form->{"all_$form->{vc}"}->[0]->{id}|; + ($form->{currency}) = $dbh->selectrow_array($query); + } + $dbh->disconnect; } @@ -124,36 +167,34 @@ sub get_openvc { sub get_openinvoices { my ($self, $myconfig, $form) = @_; - - return unless $form->{"$form->{vc}_id"}; - + + my $null; + my $department_id; + # connect to database my $dbh = $form->dbconnect($myconfig); - + my $where = qq|WHERE $form->{vc}_id = $form->{"$form->{vc}_id"} AND curr = '$form->{currency}' - AND NOT amount = paid|; + AND amount != paid|; - if ($form->{transdatefrom}) { - $where .= " AND transdate >= '$form->{transdatefrom}'"; - } - if ($form->{transdateto}) { - $where .= " AND transdate <= '$form->{transdateto}'"; - } - - my ($arap, $buysell); + my ($buysell); if ($form->{vc} eq 'customer') { - $arap = "ar"; $buysell = "buy"; } else { - $arap = "ap"; $buysell = "sell"; } + ($null, $department_id) = split /--/, $form->{department}; + if ($department_id) { + $where .= qq| + AND department_id = $department_id|; + } + my $query = qq|SELECT id, invnumber, transdate, amount, paid, curr - FROM $arap + FROM $form->{arap} $where - ORDER BY id|; + ORDER BY transdate, invnumber|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -172,10 +213,12 @@ sub get_openinvoices { sub process_payment { my ($self, $myconfig, $form) = @_; - + # connect to database, turn AutoCommit off my $dbh = $form->dbconnect_noauto($myconfig); + my $sth; + my ($paymentaccno) = split /--/, $form->{account}; # if currency ne defaultcurrency update exchangerate @@ -193,70 +236,94 @@ sub process_payment { my $query = qq|SELECT fxgain_accno_id, fxloss_accno_id FROM defaults|; - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - my ($fxgain_accno_id, $fxloss_accno_id) = $sth->fetchrow_array; - $sth->finish; + my ($fxgain_accno_id, $fxloss_accno_id) = $dbh->selectrow_array($query); - my ($ARAP, $arap, $buysell); + my ($buysell); if ($form->{vc} eq 'customer') { - $ARAP = "AR"; - $arap = "ar"; $buysell = "buy"; } else { - $ARAP = "AP"; - $arap = "ap"; $buysell = "sell"; } + + my $ml; + my $where; + + if ($form->{ARAP} eq 'AR') { + $ml = 1; + $where = qq| + (c.link = 'AR' + OR c.link LIKE 'AR:%') + |; + } else { + $ml = -1; + $where = qq| + (c.link = 'AP' + OR c.link LIKE '%:AP' + OR c.link LIKE '%:AP:%') + |; + } + my $paymentamount = $form->parse_amount($myconfig, $form->{amount}); + + my $null; + ($null, $form->{department_id}) = split /--/, $form->{department}; + $form->{department_id} *= 1; + + + # query to retrieve paid amount + $query = qq|SELECT paid FROM $form->{arap} + WHERE id = ? + FOR UPDATE|; + my $pth = $dbh->prepare($query) || $form->dberror($query); + + my %audittrail; + # go through line by line for my $i (1 .. $form->{rowcount}) { - if ($form->{"paid_$i"}) { + $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"}); + $form->{"due_$i"} = $form->parse_amount($myconfig, $form->{"due_$i"}); + + if ($form->{"checked_$i"} && $form->{"paid_$i"}) { - $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"}); + $paymentamount -= $form->{"paid_$i"}; # get exchangerate for original - $query = qq|SELECT $buysell FROM exchangerate e, $arap a + $query = qq|SELECT $buysell + FROM exchangerate e + JOIN $form->{arap} a ON (a.transdate = e.transdate) WHERE e.curr = '$form->{currency}' - AND a.transdate = e.transdate AND a.id = $form->{"id_$i"}|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - my ($exchangerate) = $sth->fetchrow_array; - $sth->finish; + my ($exchangerate) = $dbh->selectrow_array($query); $exchangerate = 1 unless $exchangerate; - $query = qq|SELECT c.id FROM chart c, acc_trans a - WHERE a.chart_id = c.id - AND c.link = '$ARAP' + $query = qq|SELECT c.id + FROM chart c + JOIN acc_trans a ON (a.chart_id = c.id) + WHERE $where AND a.trans_id = $form->{"id_$i"}|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - my ($id) = $sth->fetchrow_array; - $sth->finish; - - my $amount = $form->round_amount($form->{"paid_$i"} * $exchangerate * -1, 2); - $ml = ($ARAP eq 'AR') ? -1 : 1; + my ($id) = $dbh->selectrow_array($query); + + $amount = $form->round_amount($form->{"paid_$i"} * $exchangerate, 2); + # add AR/AP - $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate, amount) - VALUES ($form->{"id_$i"}, $id, - '$form->{datepaid}', $amount * $ml)|; + $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate, + amount) + VALUES ($form->{"id_$i"}, $id, '$form->{datepaid}', + $amount * $ml)|; $dbh->do($query) || $form->dberror($query); # add payment - $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate, amount, - source) + $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate, + amount, source, memo) VALUES ($form->{"id_$i"}, (SELECT id FROM chart WHERE accno = '$paymentaccno'), - '$form->{datepaid}', $form->{"paid_$i"} * $ml, - '$form->{source}')|; + '$form->{datepaid}', $form->{"paid_$i"} * $ml * -1, | + .$dbh->quote($form->{source}).qq|, | + .$dbh->quote($form->{memo}).qq|)|; $dbh->do($query) || $form->dberror($query); # add exchangerate difference if currency ne defaultcurrency @@ -269,12 +336,11 @@ sub process_payment { VALUES ($form->{"id_$i"}, (SELECT id FROM chart WHERE accno = '$paymentaccno'), - '$form->{datepaid}', $amount * $ml, '0', '1')|; + '$form->{datepaid}', $amount * $ml * -1, '0', '1')|; $dbh->do($query) || $form->dberror($query); # gain/loss - - $amount = $form->round_amount($form->{"paid_$i"} * ($exchangerate - $form->{exchangerate}) * $ml, 2); + $amount = $form->round_amount($form->{"paid_$i"} * ($exchangerate - $form->{exchangerate}) * $ml * -1, 2); if ($amount != 0) { my $accno_id = ($amount > 0) ? $fxgain_accno_id : $fxloss_accno_id; $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate, @@ -287,15 +353,37 @@ sub process_payment { $form->{"paid_$i"} = $form->round_amount($form->{"paid_$i"} * $exchangerate, 2); + $pth->execute($form->{"id_$i"}) || $form->dberror; + ($amount) = $pth->fetchrow_array; + $pth->finish; + + $amount += $form->{"paid_$i"}; + # update AR/AP transaction - $query = qq|UPDATE $arap set - paid = paid + $form->{"paid_$i"}, + $query = qq|UPDATE $form->{arap} set + paid = $amount, datepaid = '$form->{datepaid}' WHERE id = $form->{"id_$i"}|; $dbh->do($query) || $form->dberror($query); + + %audittrail = ( tablename => $form->{arap}, + reference => $form->{source}, + formname => $form->{formname}, + action => 'posted', + id => $form->{"id_$i"} ); + + $form->audittrail($dbh, "", \%audittrail); + } } - + + + # record a AR/AP with a payment + if ($form->round_amount($paymentamount, 2) != 0) { + $form->{invnumber} = ""; + OP::overpayment("", $myconfig, $form, $dbh, $paymentamount, $ml, 1); + } + my $rc = $dbh->commit; $dbh->disconnect; diff --git a/sql-ledger/SL/CT.pm b/sql-ledger/SL/CT.pm index 7c42cb843..bfcc2196a 100644 --- a/sql-ledger/SL/CT.pm +++ b/sql-ledger/SL/CT.pm @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -24,51 +24,87 @@ # # backend code for customers and vendors # -# CHANGE LOG: -# DS. 2000-07-04 Created -# #====================================================================== package CT; -sub get_tuple { +sub create_links { my ($self, $myconfig, $form) = @_; my $dbh = $form->dbconnect($myconfig); - my $query = qq|SELECT * - FROM $form->{db} - WHERE id = $form->{id}|; - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); + my $query; + my $sth; + my $ref; + + if ($form->{id}) { + $query = qq|SELECT ct.*, b.description AS business, s.*, + e.name AS employee, g.pricegroup AS pricegroup, + l.description AS language, ct.curr + FROM $form->{db} ct + LEFT JOIN business b ON (ct.business_id = b.id) + LEFT JOIN shipto s ON (ct.id = s.trans_id) + LEFT JOIN employee e ON (ct.employee_id = e.id) + LEFT JOIN pricegroup g ON (g.id = ct.pricegroup_id) + LEFT JOIN language l ON (l.code = ct.language_code) + WHERE ct.id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); - my $ref = $sth->fetchrow_hashref(NAME_lc); + $ref = $sth->fetchrow_hashref(NAME_lc); - map { $form->{$_} = $ref->{$_} } keys %$ref; + map { $form->{$_} = $ref->{$_} } keys %$ref; - $sth->finish; + $sth->finish; + # check if it is orphaned + my $arap = ($form->{db} eq 'customer') ? "ar" : "ap"; + $query = qq|SELECT a.id + FROM $arap a + JOIN $form->{db} ct ON (a.$form->{db}_id = ct.id) + WHERE ct.id = $form->{id} + UNION + SELECT a.id + FROM oe a + JOIN $form->{db} ct ON (a.$form->{db}_id = ct.id) + WHERE ct.id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + unless ($sth->fetchrow_array) { + $form->{status} = "orphaned"; + } + $sth->finish; - # get ship to - $query = qq|SELECT * - FROM shipto - WHERE trans_id = $form->{id}|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - $ref = $sth->fetchrow_hashref(NAME_lc); + # get taxes for customer/vendor + $query = qq|SELECT c.accno + FROM chart c + JOIN $form->{db}tax t ON (t.chart_id = c.id) + WHERE t.$form->{db}_id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); - map { $form->{$_} = $ref->{$_} } keys %$ref; + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + $form->{tax}{$ref->{accno}}{taxable} = 1; + } + $sth->finish; - $sth->finish; + } else { + + ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh); + $query = qq|SELECT current_date FROM defaults|; + ($form->{startdate}) = $dbh->selectrow_array($query); + + } # get tax labels - $query = qq|SELECT accno, description - FROM chart, tax - WHERE link LIKE '%CT_tax%' - AND chart.id = tax.chart_id - ORDER BY accno|; + $query = qq|SELECT c.accno, c.description + FROM chart c + JOIN tax t ON (t.chart_id = c.id) + WHERE c.link LIKE '%CT_tax%' + ORDER BY c.accno|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -79,94 +115,67 @@ sub get_tuple { $sth->finish; chop $form->{taxaccounts}; - # get taxes for customer/vendor - $query = qq|SELECT chart_id, accno - FROM $form->{db}tax, chart - WHERE chart_id = chart.id - AND $form->{db}_id = $form->{id}|; + + # get business types + $query = qq|SELECT * + FROM business + ORDER BY 2|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { - $form->{tax}{$ref->{accno}}{taxable} = 1; + push @{ $form->{all_business} }, $ref; } $sth->finish; - - $dbh->disconnect; - -} - - -sub taxaccounts { - my ($self, $myconfig, $form) = @_; - - my $dbh = $form->dbconnect($myconfig); - - # get tax labels - my $query = qq|SELECT accno, description - FROM chart, tax - WHERE link LIKE '%CT_tax%' - AND chart.id = tax.chart_id - ORDER BY accno|; + # this is for the salesperson + $query = qq|SELECT id, name + FROM employee + WHERE sales = '1' + ORDER BY 2|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - - while (my $taxref = $sth->fetchrow_hashref(NAME_lc)) { - $form->{taxaccounts} .= "$taxref->{accno} "; - $form->{tax}{$taxref->{accno}}{description} = $taxref->{description}; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_employee} }, $ref; } $sth->finish; - chop $form->{taxaccounts}; - - $dbh->disconnect; - -} - - -sub delete_customer { - my ($self, $myconfig, $form) = @_; - - # connect to database, turn AutoCommit off - my $dbh = $form->dbconnect_noauto($myconfig); - - my $query = qq|SELECT id FROM ar - WHERE customer_id = $form->{id} - UNION - SELECT id FROM oe - WHERE customer_id = $form->{id}|; - my $sth = $dbh->prepare($query) || $form->dberror($query); - $sth->execute; - my ($rc) = $sth->fetchrow_array; + # get language + $query = qq|SELECT * + FROM language + ORDER BY 2|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_language} }, $ref; + } $sth->finish; - - if ($rc) { - $dbh->disconnect; - $rc = -1; - } else { - - # delete customer - $query = qq|DELETE FROM customer - WHERE id = $form->{id}|; - $dbh->do($query) || $form->dberror($query); - - $query = qq|DELETE FROM shipto - WHERE trans_id = $form->{id}|; - $dbh->do($query) || $form->dberror($query); - - $query = qq|DELETE FROM customertax - WHERE customer_id = $form->{id}|; - $dbh->do($query) || $form->dberror($query); - - # commit and redirect - $rc = $dbh->commit; - $dbh->disconnect; - + + # get pricegroups + $query = qq|SELECT * + FROM pricegroup + ORDER BY 2|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_pricegroup} }, $ref; } - - $rc; + $sth->finish; + + # get currencies + $query = qq|SELECT curr AS currencies + FROM defaults|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + ($form->{currencies}) = $sth->fetchrow_array; + $sth->finish; + + $dbh->disconnect; + } @@ -174,18 +183,24 @@ sub save_customer { my ($self, $myconfig, $form) = @_; # connect to database - my $dbh = $form->dbconnect($myconfig); - - # escape ' - map { $form->{$_} =~ s/'/''/g } qw(customernumber name addr1 addr2 addr3 addr4 contact notes); - + my $dbh = $form->dbconnect_noauto($myconfig); + my $query; + my $sth; + my $null; + + # remove double spaces + $form->{name} =~ s/ / /g; + # remove double minus and minus at the end + $form->{name} =~ s/--+/-/g; + $form->{name} =~ s/-+$//; + # assign value discount, terms, creditlimit + $form->{discount} = $form->parse_amount($myconfig, $form->{discount}); $form->{discount} /= 100; $form->{terms} *= 1; $form->{taxincluded} *= 1; $form->{creditlimit} = $form->parse_amount($myconfig, $form->{creditlimit}); - my ($query, $sth); if ($form->{id}) { $query = qq|DELETE FROM customertax @@ -195,6 +210,15 @@ sub save_customer { $query = qq|DELETE FROM shipto WHERE trans_id = $form->{id}|; $dbh->do($query) || $form->dberror($query); + + # retrieve enddate + if ($form->{type} && $form->{enddate}) { + my $now; + $query = qq|SELECT enddate, current_date AS now FROM customer|; + ($form->{enddate}, $now) = $dbh->selectrow_array($query); + $form->{enddate} = $now if $form->{enddate} lt $now; + } + } else { my $uid = time; $uid .= $form->{login}; @@ -212,25 +236,55 @@ sub save_customer { $sth->finish; } - + + my $employee_id; + ($null, $employee_id) = split /--/, $form->{employee}; + $employee_id *= 1; + + my $pricegroup_id; + ($null, $pricegroup_id) = split /--/, $form->{pricegroup}; + $pricegroup_id *= 1; + + my $business_id; + ($null, $business_id) = split /--/, $form->{business}; + $business_id *= 1; + + my $language_code; + ($null, $language_code) = split /--/, $form->{language}; + + $form->{customernumber} = $form->update_defaults($myconfig, "customernumber", $dbh) if ! $form->{customernumber}; + $query = qq|UPDATE customer SET - customernumber = '$form->{customernumber}', - name = '$form->{name}', - addr1 = '$form->{addr1}', - addr2 = '$form->{addr2}', - addr3 = '$form->{addr3}', - addr4 = '$form->{addr4}', - contact = '$form->{contact}', + customernumber = |.$dbh->quote($form->{customernumber}).qq|, + name = |.$dbh->quote($form->{name}).qq|, + address1 = |.$dbh->quote($form->{address1}).qq|, + address2 = |.$dbh->quote($form->{address2}).qq|, + city = |.$dbh->quote($form->{city}).qq|, + state = |.$dbh->quote($form->{state}).qq|, + zipcode = |.$dbh->quote($form->{zipcode}).qq|, + country = |.$dbh->quote($form->{country}).qq|, + contact = |.$dbh->quote($form->{contact}).qq|, phone = '$form->{phone}', fax = '$form->{fax}', email = '$form->{email}', cc = '$form->{cc}', bcc = '$form->{bcc}', - notes = '$form->{notes}', + notes = |.$dbh->quote($form->{notes}).qq|, discount = $form->{discount}, creditlimit = $form->{creditlimit}, terms = $form->{terms}, - taxincluded = '$form->{taxincluded}' + taxincluded = '$form->{taxincluded}', + business_id = $business_id, + taxnumber = |.$dbh->quote($form->{taxnumber}).qq|, + sic_code = '$form->{sic}', + iban = '$form->{iban}', + bic = '$form->{bic}', + employee_id = $employee_id, + pricegroup_id = $pricegroup_id, + language_code = '$language_code', + curr = '$form->{curr}', + startdate = |.$form->dbquote($form->{startdate}, SQL_DATE).qq|, + enddate = |.$form->dbquote($form->{enddate}, SQL_DATE).qq| WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); @@ -248,6 +302,7 @@ sub save_customer { # add shipto $form->add_shipto($dbh, $form->{id}); + $dbh->commit; $dbh->disconnect; } @@ -257,15 +312,24 @@ sub save_vendor { my ($self, $myconfig, $form) = @_; # connect to database - my $dbh = $form->dbconnect($myconfig); + my $dbh = $form->dbconnect_noauto($myconfig); - # escape ' - map { $form->{$_} =~ s/'/''/g } qw(vendornumber name addr1 addr2 addr3 addr4 contact notes); + my $query; + my $sth; + my $null; + + # remove double spaces + $form->{name} =~ s/ / /g; + # remove double minus and minus at the end + $form->{name} =~ s/--+/-/g; + $form->{name} =~ s/-+$//; + $form->{discount} = $form->parse_amount($myconfig, $form->{discount}); + $form->{discount} /= 100; $form->{terms} *= 1; $form->{taxincluded} *= 1; - - my $query; + $form->{creditlimit} = $form->parse_amount($myconfig, $form->{creditlimit}); + if ($form->{id}) { $query = qq|DELETE FROM vendortax @@ -293,23 +357,55 @@ sub save_vendor { } - + my $employee_id; + ($null, $employee_id) = split /--/, $form->{employee}; + $employee_id *= 1; + + my $pricegroup_id; + ($null, $pricegroup_id) = split /--/, $form->{pricegroup}; + $pricegroup_id *= 1; + + my $business_id; + ($null, $business_id) = split /--/, $form->{business}; + $business_id *= 1; + + my $language_code; + ($null, $language_code) = split /--/, $form->{language}; + + $form->{vendornumber} = $form->update_defaults($myconfig, "vendornumber", $dbh) if ! $form->{vendornumber}; + $query = qq|UPDATE vendor SET - vendornumber = '$form->{vendornumber}', - name = '$form->{name}', - addr1 = '$form->{addr1}', - addr2 = '$form->{addr2}', - addr3 = '$form->{addr3}', - addr4 = '$form->{addr4}', - contact = '$form->{contact}', + vendornumber = |.$dbh->quote($form->{vendornumber}).qq|, + name = |.$dbh->quote($form->{name}).qq|, + address1 = |.$dbh->quote($form->{address1}).qq|, + address2 = |.$dbh->quote($form->{address2}).qq|, + city = |.$dbh->quote($form->{city}).qq|, + state = |.$dbh->quote($form->{state}).qq|, + zipcode = |.$dbh->quote($form->{zipcode}).qq|, + country = |.$dbh->quote($form->{country}).qq|, + contact = |.$dbh->quote($form->{contact}).qq|, phone = '$form->{phone}', fax = '$form->{fax}', email = '$form->{email}', cc = '$form->{cc}', bcc = '$form->{bcc}', - notes = '$form->{notes}', + notes = |.$dbh->quote($form->{notes}).qq|, terms = $form->{terms}, - taxincluded = '$form->{taxincluded}' + discount = $form->{discount}, + creditlimit = $form->{creditlimit}, + taxincluded = '$form->{taxincluded}', + gifi_accno = '$form->{gifi_accno}', + business_id = $business_id, + taxnumber = |.$dbh->quote($form->{taxnumber}).qq|, + sic_code = '$form->{sic}', + iban = '$form->{iban}', + bic = '$form->{bic}', + employee_id = $employee_id, + language_code = '$language_code', + pricegroup_id = $pricegroup_id, + curr = '$form->{curr}', + startdate = |.$form->dbquote($form->{startdate}, SQL_DATE).qq|, + enddate = |.$form->dbquote($form->{enddate}, SQL_DATE).qq| WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); @@ -327,113 +423,422 @@ sub save_vendor { # add shipto $form->add_shipto($dbh, $form->{id}); + $dbh->commit; $dbh->disconnect; } -sub delete_vendor { +sub delete { my ($self, $myconfig, $form) = @_; - # connect to database, turn AutoCommit off - my $dbh = $form->dbconnect_noauto($myconfig); + # connect to database + my $dbh = $form->dbconnect($myconfig); + + # delete customer/vendor + my $query = qq|DELETE FROM $form->{db} + WHERE id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $dbh->disconnect; - # check if there are any transactions on file - my $query = qq|SELECT id FROM ap - WHERE vendor_id = $form->{id} - UNION - SELECT id FROM oe - WHERE vendor_id = $form->{id}|; - my $sth = $dbh->prepare($query) || $form->dberror($query); - $sth->execute; +} + + +sub search { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $where = "1 = 1"; + $form->{sort} = ($form->{sort}) ? $form->{sort} : "name"; + my @a = qw(name); + my $sortorder = $form->sort_order(\@a); + + my $var; + my $item; + + @a = ("$form->{db}number"); + push @a, qw(name contact city state zipcode country notes email); - my ($rc) = $sth->fetchrow_array; - $sth->finish; + foreach $item (@a) { + if ($form->{$item}) { + $var = $form->like(lc $form->{$item}); + $where .= " AND lower(ct.$item) LIKE '$var'"; + } + } + if ($form->{address}) { + $var = $form->like(lc $form->{address}); + $where .= " AND (lower(ct.address1) LIKE '$var' OR lower(ct.address2) LIKE '$var')"; + } + + if ($form->{status} eq 'orphaned') { + $where .= qq| AND ct.id NOT IN (SELECT o.$form->{db}_id + FROM oe o, $form->{db} cv + WHERE cv.id = o.$form->{db}_id)|; + if ($form->{db} eq 'customer') { + $where .= qq| AND ct.id NOT IN (SELECT a.customer_id + FROM ar a, customer cv + WHERE cv.id = a.customer_id)|; + } + if ($form->{db} eq 'vendor') { + $where .= qq| AND ct.id NOT IN (SELECT a.vendor_id + FROM ap a, vendor cv + WHERE cv.id = a.vendor_id)|; + } + $form->{l_invnumber} = $form->{l_ordnumber} = $form->{l_quonumber} = ""; + } - if ($rc) { - $dbh->disconnect; - $rc = -1; - } else { + + my $query = qq|SELECT ct.*, b.description AS business, + e.name AS employee, g.pricegroup, l.description AS language, + m.name AS manager + FROM $form->{db} ct + LEFT JOIN business b ON (ct.business_id = b.id) + LEFT JOIN employee e ON (ct.employee_id = e.id) + LEFT JOIN employee m ON (m.id = e.managerid) + LEFT JOIN pricegroup g ON (ct.pricegroup_id = g.id) + LEFT JOIN language l ON (l.code = ct.language_code) + WHERE $where|; + + # redo for invoices, orders and quotations + if ($form->{l_transnumber} || $form->{l_invnumber} || $form->{l_ordnumber} || $form->{l_quonumber}) { + + my ($ar, $union, $module); + $query = ""; + my $transwhere; + my $openarap = ""; + my $openoe = ""; - # delete vendor - $query = qq|DELETE FROM vendor - WHERE id = $form->{id}|; - $dbh->do($query) || $form->dberror($query); + if ($form->{open} || $form->{closed}) { + unless ($form->{open} && $form->{closed}) { + $openarap = " AND a.amount != a.paid" if $form->{open}; + $openarap = " AND a.amount = a.paid" if $form->{closed}; + $openoe = " AND o.closed = '0'" if $form->{open}; + $openoe = " AND o.closed = '1'" if $form->{closed}; + } + } + + if ($form->{l_transnumber}) { + $ar = ($form->{db} eq 'customer') ? 'ar' : 'ap'; + $module = $ar; + + $transwhere = ""; + $transwhere .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $transwhere .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + + + $query = qq|SELECT ct.*, b.description AS business, + a.invnumber, a.ordnumber, a.quonumber, a.id AS invid, + '$ar' AS module, 'invoice' AS formtype, + (a.amount = a.paid) AS closed, a.amount, a.netamount + FROM $form->{db} ct + JOIN $ar a ON (a.$form->{db}_id = ct.id) + LEFT JOIN business b ON (ct.business_id = b.id) + WHERE $where + AND a.invoice = '0' + $transwhere + $openarap + |; + + $union = qq| + UNION|; + + } - $query = qq|DELETE FROM shipto - WHERE trans_id = $form->{id}|; - $dbh->do($query) || $form->dberror($query); + if ($form->{l_invnumber}) { + $ar = ($form->{db} eq 'customer') ? 'ar' : 'ap'; + $module = ($ar eq 'ar') ? 'is' : 'ir'; - $query = qq|DELETE FROM vendortax - WHERE vendor_id = $form->{id}|; - $dbh->do($query) || $form->dberror($query); + $transwhere = ""; + $transwhere .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $transwhere .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + + $query .= qq|$union + SELECT ct.*, b.description AS business, + a.invnumber, a.ordnumber, a.quonumber, a.id AS invid, + '$module' AS module, 'invoice' AS formtype, + (a.amount = a.paid) AS closed, a.amount, a.netamount + FROM $form->{db} ct + JOIN $ar a ON (a.$form->{db}_id = ct.id) + LEFT JOIN business b ON (ct.business_id = b.id) + WHERE $where + AND a.invoice = '1' + $transwhere + $openarap + |; + + $union = qq| + UNION|; + + } + + if ($form->{l_ordnumber}) { + + $transwhere = ""; + $transwhere .= " AND o.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $transwhere .= " AND o.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + $query .= qq|$union + SELECT ct.*, b.description AS business, + ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, + 'oe' AS module, 'order' AS formtype, + o.closed, o.amount, o.netamount + FROM $form->{db} ct + JOIN oe o ON (o.$form->{db}_id = ct.id) + LEFT JOIN business b ON (ct.business_id = b.id) + WHERE $where + AND o.quotation = '0' + $transwhere + $openoe + |; + + $union = qq| + UNION|; + + } + + if ($form->{l_quonumber}) { + + $transwhere = ""; + $transwhere .= " AND o.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $transwhere .= " AND o.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + $query .= qq|$union + SELECT ct.*, b.description AS business, + ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, + 'oe' AS module, 'quotation' AS formtype, + o.closed, o.amount, o.netamount + FROM $form->{db} ct + JOIN oe o ON (o.$form->{db}_id = ct.id) + LEFT JOIN business b ON (ct.business_id = b.id) + WHERE $where + AND o.quotation = '1' + $transwhere + $openoe + |; - # commit and redirect - $rc = $dbh->commit; - $dbh->disconnect; + } + $sortorder .= ", invid"; } - $rc; + $query .= qq| + ORDER BY $sortorder|; + + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + $ref->{address} = ""; + map { $ref->{address} .= "$ref->{$_} "; } qw(address1 address2 city state zipcode country); + push @{ $form->{CT} }, $ref; + } + + $sth->finish; + $dbh->disconnect; } -sub search { +sub get_history { my ($self, $myconfig, $form) = @_; - + # connect to database my $dbh = $form->dbconnect($myconfig); + my $query; my $where = "1 = 1"; - $form->{sort} = "name" unless ($form->{sort}); + $form->{sort} = "partnumber" unless $form->{sort}; + my $sortorder = $form->{sort}; + my %ordinal = (); + my $var; + my $table; + + # setup ASC or DESC + $form->sort_order(); if ($form->{"$form->{db}number"}) { - my $companynumber = $form->like(lc $form->{"$form->{db}number"}); - $where .= " AND lower($form->{db}number) LIKE '$companynumber'"; + $var = $form->like(lc $form->{"$form->{db}number"}); + $where .= " AND lower(ct.$form->{db}number) LIKE '$var'"; } if ($form->{name}) { - my $name = $form->like(lc $form->{name}); - $where .= " AND lower(name) LIKE '$name'"; + $var = $form->like(lc $form->{name}); + $where .= " AND lower(ct.name) LIKE '$var'"; + } + if ($form->{address}) { + $var = $form->like(lc $form->{address}); + $where .= " AND lower(ct.address1) LIKE '$var'"; + } + if ($form->{city}) { + $var = $form->like(lc $form->{city}); + $where .= " AND lower(ct.city) LIKE '$var'"; + } + if ($form->{state}) { + $var = $form->like(lc $form->{state}); + $where .= " AND lower(ct.state) LIKE '$var'"; + } + if ($form->{zipcode}) { + $var = $form->like(lc $form->{zipcode}); + $where .= " AND lower(ct.zipcode) LIKE '$var'"; + } + if ($form->{country}) { + $var = $form->like(lc $form->{country}); + $where .= " AND lower(ct.country) LIKE '$var'"; } if ($form->{contact}) { - my $contact = $form->like(lc $form->{contact}); - $where .= " AND lower(contact) LIKE '$contact'"; + $var = $form->like(lc $form->{contact}); + $where .= " AND lower(ct.contact) LIKE '$var'"; + } + if ($form->{notes}) { + $var = $form->like(lc $form->{notes}); + $where .= " AND lower(ct.notes) LIKE '$var'"; } if ($form->{email}) { - my $email = $form->like(lc $form->{email}); - $where .= " AND lower(email) LIKE '$email'"; + $var = $form->like(lc $form->{email}); + $where .= " AND lower(ct.email) LIKE '$var'"; } - if ($form->{status} eq 'orphaned') { - $where .= qq| AND id NOT IN (SELECT o.$form->{db}_id - FROM oe o, $form->{db} ct - WHERE ct.id = o.$form->{db}_id)|; - if ($form->{db} eq 'customer') { - $where .= qq| AND id NOT IN (SELECT a.customer_id - FROM ar a, customer ct - WHERE ct.id = a.customer_id)|; - } - if ($form->{db} eq 'vendor') { - $where .= qq| AND id NOT IN (SELECT a.vendor_id - FROM ap a, vendor ct - WHERE ct.id = a.vendor_id)|; + $where .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $where .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + + if ($form->{open} || $form->{closed}) { + unless ($form->{open} && $form->{closed}) { + if ($form->{type} eq 'invoice') { + $where .= " AND a.amount != a.paid" if $form->{open}; + $where .= " AND a.amount = a.paid" if $form->{closed}; + } else { + $where .= " AND a.closed = '0'" if $form->{open}; + $where .= " AND a.closed = '1'" if $form->{closed}; + } } } - my $query = qq~SELECT id, name, $form->{db}number, - addr1 || ' ' || addr2 || ' ' || addr3 || ' ' || addr4 AS address, - contact, phone, fax, email, cc, terms - FROM $form->{db} - WHERE $where - ORDER BY $form->{sort}~; + my $invnumber = 'invnumber'; + my $deldate = 'deliverydate'; + my $buysell; + + if ($form->{db} eq 'customer') { + $buysell = "buy"; + if ($form->{type} eq 'invoice') { + $where .= qq| AND a.invoice = '1' AND i.assemblyitem = '0'|; + $table = 'ar'; + } else { + $table = 'oe'; + if ($form->{type} eq 'order') { + $invnumber = 'ordnumber'; + $where .= qq| AND a.quotation = '0'|; + } else { + $invnumber = 'quonumber'; + $where .= qq| AND a.quotation = '1'|; + } + $deldate = 'reqdate'; + } + } + if ($form->{db} eq 'vendor') { + $buysell = "sell"; + if ($form->{type} eq 'invoice') { + $where .= qq| AND a.invoice = '1' AND i.assemblyitem = '0'|; + $table = 'ap'; + } else { + $table = 'oe'; + if ($form->{type} eq 'order') { + $invnumber = 'ordnumber'; + $where .= qq| AND a.quotation = '0'|; + } else { + $invnumber = 'quonumber'; + $where .= qq| AND a.quotation = '1'|; + } + $deldate = 'reqdate'; + } + } + + my $invjoin = qq| + JOIN invoice i ON (i.trans_id = a.id)|; + + if ($form->{type} eq 'order') { + $invjoin = qq| + JOIN orderitems i ON (i.trans_id = a.id)|; + } + if ($form->{type} eq 'quotation') { + $invjoin = qq| + JOIN orderitems i ON (i.trans_id = a.id)|; + $where .= qq| AND a.quotation = '1'|; + } + + + if ($form->{history} eq 'summary') { + $query = qq|SELECT curr FROM defaults|; + my ($curr) = $dbh->selectrow_array($query); + $curr =~ s/:.*//; + + %ordinal = ( partnumber => 8, + description => 9 + ); + $sortorder = "2 $form->{direction}, 1, $ordinal{$sortorder} $form->{direction}"; + + $query = qq|SELECT ct.id AS ctid, ct.name, ct.address1, + ct.address2, ct.city, ct.state, + p.id AS pid, p.partnumber, i.description, p.unit, + sum(i.qty) AS qty, sum(i.sellprice) AS sellprice, + '$curr' AS curr, + ct.zipcode, ct.country + FROM $form->{db} ct + JOIN $table a ON (a.$form->{db}_id = ct.id) + $invjoin + JOIN parts p ON (p.id = i.parts_id) + WHERE $where + GROUP BY ct.id, ct.name, ct.address1, ct.address2, ct.city, + ct.state, ct.zipcode, ct.country, + p.id, p.partnumber, i.description, p.unit + ORDER BY $sortorder|; + } else { + %ordinal = ( partnumber => 9, + description => 12, + "$deldate" => 16, + serialnumber => 17, + projectnumber => 18 + ); + + $sortorder = "2 $form->{direction}, 1, 11, $ordinal{$sortorder} $form->{direction}"; + + $query = qq|SELECT ct.id AS ctid, ct.name, ct.address1, + ct.address2, ct.city, ct.state, + p.id AS pid, p.partnumber, a.id AS invid, + a.$invnumber, a.curr, i.description, + i.qty, i.sellprice, i.discount, + i.$deldate, i.serialnumber, pr.projectnumber, + e.name AS employee, ct.zipcode, ct.country, i.unit|; + $query .= qq|, i.fxsellprice| if $form->{type} eq 'invoice'; + + if ($form->{type} ne 'invoice') { + if ($form->{l_curr}) { + $query .= qq|, (SELECT $buysell FROM exchangerate ex + WHERE a.curr = ex.curr + AND a.transdate = ex.transdate) AS exchangerate|; + } + } + + $query .= qq| + FROM $form->{db} ct + JOIN $table a ON (a.$form->{db}_id = ct.id) + $invjoin + JOIN parts p ON (p.id = i.parts_id) + LEFT JOIN project pr ON (pr.id = i.project_id) + LEFT JOIN employee e ON (e.id = a.employee_id) + WHERE $where + ORDER BY $sortorder|; + } + my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + $ref->{address} = ""; + $ref->{exchangerate} = 1 unless $ref->{exchangerate}; + map { $ref->{address} .= "$ref->{$_} "; } qw(address1 address2 city state zipcode country); + $ref->{id} = $ref->{ctid}; push @{ $form->{CT} }, $ref; } @@ -443,5 +848,161 @@ sub search { } +sub pricelist { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $query; + + if ($form->{db} eq 'customer') { + $query = qq|SELECT p.id, p.partnumber, p.description, + p.sellprice, pg.partsgroup, p.partsgroup_id, + m.pricebreak, m.sellprice, + m.validfrom, m.validto, m.curr + FROM partscustomer m + JOIN parts p ON (p.id = m.parts_id) + LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id) + WHERE m.customer_id = $form->{id} + ORDER BY partnumber|; + } + if ($form->{db} eq 'vendor') { + $query = qq|SELECT p.id, p.partnumber AS sku, p.description, + pg.partsgroup, p.partsgroup_id, + m.partnumber, m.leadtime, m.lastcost, m.curr + FROM partsvendor m + JOIN parts p ON (p.id = m.parts_id) + LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id) + WHERE m.vendor_id = $form->{id} + ORDER BY p.partnumber|; + } + + my $sth; + my $ref; + + if ($form->{id}) { + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_partspricelist} }, $ref; + } + $sth->finish; + } + + $query = qq|SELECT curr FROM defaults|; + ($form->{currencies}) = $dbh->selectrow_array($query); + + $query = qq|SELECT id, partsgroup FROM partsgroup + ORDER BY partsgroup|; + + $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); + + $form->{all_partsgroup} = (); + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_partsgroup} }, $ref; + } + $sth->finish; + + $dbh->disconnect; + +} + + +sub save_pricelist { + my ($self, $myconfig, $form) = @_; + + my $dbh = $form->dbconnect_noauto($myconfig); + + my $query = qq|DELETE FROM parts$form->{db} + WHERE $form->{db}_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + + foreach $i (1 .. $form->{rowcount}) { + + if ($form->{"id_$i"}) { + + if ($form->{db} eq 'customer') { + map { $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"}) } qw(pricebreak sellprice); + + $query = qq|INSERT INTO parts$form->{db} (parts_id, customer_id, + pricebreak, sellprice, validfrom, validto, curr) + VALUES ($form->{"id_$i"}, $form->{id}, + $form->{"pricebreak_$i"}, $form->{"sellprice_$i"},| + .$form->dbquote($form->{"validfrom_$i"}, SQL_DATE) .qq|,| + .$form->dbquote($form->{"validto_$i"}, SQL_DATE) .qq|, + '$form->{"curr_$i"}')|; + } else { + map { $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"}) } qw(leadtime lastcost); + + $query = qq|INSERT INTO parts$form->{db} (parts_id, vendor_id, + partnumber, lastcost, leadtime, curr) + VALUES ($form->{"id_$i"}, $form->{id}, + '$form->{"partnumber_$i"}', $form->{"lastcost_$i"}, + $form->{"leadtime_$i"}, '$form->{"curr_$i"}')|; + + } + $dbh->do($query) || $form->dberror($query); + } + + } + + $_ = $dbh->commit; + $dbh->disconnect; + +} + + + +sub retrieve_item { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $i = $form->{rowcount}; + my $var; + my $null; + + my $where = "WHERE p.obsolete = '0' AND p.income_accno_id > 0"; + + if ($form->{"partnumber_$i"}) { + $var = $form->like(lc $form->{"partnumber_$i"}); + $where .= " AND lower(p.partnumber) LIKE '$var'"; + } + if ($form->{"description_$i"}) { + $var = $form->like(lc $form->{"description_$i"}); + $where .= " AND lower(p.description) LIKE '$var'"; + } + + if ($form->{"partsgroup_$i"}) { + ($null, $var) = split /--/, $form->{"partsgroup_$i"}; + $where .= qq| AND p.partsgroup_id = $var|; + } + + + my $query = qq|SELECT p.id, p.partnumber, p.description, p.sellprice, + p.lastcost, p.unit, pg.partsgroup, p.partsgroup_id + FROM parts p + LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id) + $where + |; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my $ref; + $form->{item_list} = (); + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{item_list} }, $ref; + } + $sth->finish; + $dbh->disconnect; + +} + + 1; diff --git a/sql-ledger/SL/Form.pm b/sql-ledger/SL/Form.pm index ef5f2ca81..c722b4417 100644 --- a/sql-ledger/SL/Form.pm +++ b/sql-ledger/SL/Form.pm @@ -1,6 +1,6 @@ -#===================================================================== +#================================================================= # SQL-Ledger Accounting -# Copyright (C) 1998-2003 +# Copyright (C) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -8,7 +8,8 @@ # # Contributors: Thomas Bayen # Antti Kaihola -# Moritz Bunkus (tex code) +# Moritz Bunkus (tex) +# Jim Rawlings (DB2) # # 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 @@ -23,9 +24,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #====================================================================== -# Utilities for parsing forms -# and supporting routines for linking account numbers -# used in AR, AP and IS, IR modules +# +# main package # #====================================================================== @@ -52,11 +52,15 @@ sub new { $self->{$key} = &unescape("",$value); } - $self->{action} = lc $self->{action}; - $self->{action} =~ s/( |-|,)/_/g; + $self->{menubar} = 1 if $self->{path} =~ /lynx/i; + + if (substr($self->{action}, 0, 1) !~ /( |\.)/) { + $self->{action} = lc $self->{action}; + $self->{action} =~ s/(( |-|,|#|\/)|\.$)/_/g; + } - $self->{version} = "2.0.8"; - $self->{dbversion} = "2.0.8"; + $self->{version} = "2.4.4"; + $self->{dbversion} = "2.4.4"; bless $self, $type; @@ -68,7 +72,7 @@ sub debug { print "\n"; - map { print "$_ = $self->{$_}\n" } (sort keys %{$self}); + map { print "$_ = $self->{$_}\n" } (sort keys %$self); } @@ -77,8 +81,8 @@ sub escape { my ($self, $str, $beenthere) = @_; # for Apache 2 we escape strings twice - if (($ENV{SERVER_SOFTWARE} =~ /Apache\/2/) && !$beenthere) { - $str = $self->escape($str, 1); + if (($ENV{SERVER_SIGNATURE} =~ /Apache\/2\.(\d+)\.(\d+)/) && !$beenthere) { + $str = $self->escape($str, 1) if $2 < 44; } $str =~ s/([^a-zA-Z0-9_.-])/sprintf("%%%02x", ord($1))/ge; @@ -100,25 +104,43 @@ sub unescape { } +sub quote { + my ($self, $str) = @_; + + if ($str && ! ref($str)) { + $str =~ s/"/"/g; + } + + $str; + +} + + +sub hide_form { + my $self = shift; + + map { print qq|\n| } sort keys %$self; + +} + + sub error { my ($self, $msg) = @_; if ($ENV{HTTP_USER_AGENT}) { $msg =~ s/\n/
/g; - print qq|Content-Type: text/html + delete $self->{pre}; - + if (!$self->{header}) { + $self->header; + } -

Error!

+ print qq|

Error!

-

$msg - - - - |; +

$msg|; - die "Error: $msg\n"; + exit; } else { @@ -132,24 +154,23 @@ sub error { } - sub info { my ($self, $msg) = @_; if ($ENV{HTTP_USER_AGENT}) { $msg =~ s/\n/
/g; + delete $self->{pre}; + if (!$self->{header}) { $self->header; print qq| |; + $self->{header} = 1; } - print qq| + print "
$msg"; -

$msg - |; - } else { if ($self->{info_function}) { @@ -162,16 +183,18 @@ sub info { } + + sub numtextrows { my ($self, $str, $cols, $maxrows) = @_; - my $rows; + my $rows = 0; - map { $rows += int ((length $_)/$cols) + 1 } (split /\r/, $str); + map { $rows += int (((length) - 2)/$cols) + 1 } split /\r/, $str; - $rows = $maxrows if (defined $maxrows && ($rows > $maxrows)); - - $rows; + $maxrows = $rows unless defined $maxrows; + + return ($rows > $maxrows) ? $maxrows : $rows; } @@ -194,85 +217,136 @@ sub isblank { sub header { - my ($self) = @_; + my ($self, $init) = @_; - my ($nocache, $stylesheet, $charset); - - # use expire tag to prevent caching -# $nocache = qq| -# -#|; + return if $self->{header}; - if ($self->{stylesheet} && (-f "css/$self->{stylesheet}")) { - $stylesheet = qq| -|; - } + my ($stylesheet, $favicon, $charset); - if ($self->{charset}) { - $charset = qq| -|; - } + if ($ENV{HTTP_USER_AGENT}) { - $self->{titlebar} = ($self->{title}) ? "$self->{title} - $self->{titlebar}" : $self->{titlebar}; - - print qq|Content-Type: text/html + if ($self->{stylesheet} && (-f "css/$self->{stylesheet}")) { + $stylesheet = qq| + |; + } + + if ($self->{favicon} && (-f "$self->{favicon}")) { + $favicon = qq| + |; + } + + if ($self->{charset}) { + $charset = qq| + |; + } + + $self->{titlebar} = ($self->{title}) ? "$self->{title} - $self->{titlebar}" : $self->{titlebar}; + + $self->set_cookie($init); + + print qq|Content-Type: text/html - $self->{titlebar} - $nocache + $favicon $stylesheet $charset +$self->{pre} |; + } + + $self->{header} = 1; } +sub set_cookie { + my ($self, $init) = @_; + + $self->{timeout} = ($self->{timeout} > 0) ? $self->{timeout} : 3600; + + if ($self->{endsession}) { + $_ = time; + } else { + $_ = time + $self->{timeout}; + } + + if ($ENV{HTTP_USER_AGENT}) { + + my @d = split / +/, scalar gmtime($_); + my $today = "$d[0], $d[2]-$d[1]-$d[4] $d[3] GMT"; + + if ($init) { + $self->{sessionid} = time; + } + print qq|Set-Cookie: SQL-Ledger-$self->{login}=$self->{sessionid}; expires=$today; path=/;\n| if $self->{login}; + } + +} + + sub redirect { my ($self, $msg) = @_; if ($self->{callback}) { ($script, $argv) = split(/\?/, $self->{callback}); - exec ("perl", "$script", $argv); } else { - if ($ENV{HTTP_USER_AGENT}) { - $msg =~ s/\n/
/g; - - print qq|Content-Type: text/html + $self->info($msg); + exit; + } - +} -

$msg

- - -|; +sub sort_columns { + my ($self, @columns) = @_; - } else { - print "$msg\n"; + if ($self->{sort}) { + if (@columns) { + @columns = grep !/^$self->{sort}$/, @columns; + splice @columns, 0, 0, $self->{sort}; } - - exit; - } + @columns; + } -sub sort_columns { - my ($self, @columns) = @_; +sub sort_order { + my ($self, $columns, $ordinal) = @_; - @columns = grep !/^$self->{sort}$/, @columns; - splice @columns, 0, 0, $self->{sort}; + # setup direction + if ($self->{direction}) { + if ($self->{sort} eq $self->{oldsort}) { + if ($self->{direction} eq 'ASC') { + $self->{direction} = "DESC"; + } else { + $self->{direction} = "ASC"; + } + } + } else { + $self->{direction} = "ASC"; + } + $self->{oldsort} = $self->{sort}; - @columns; + my $sortorder = join ',', $self->sort_columns(@{$columns}); + if ($ordinal) { + map { $sortorder =~ s/$_/$ordinal->{$_}/ } keys %$ordinal; + } + my @a = split /,/, $sortorder; + $a[0] = "$a[0] $self->{direction}"; + $sortorder = join ',', @a; + + $sortorder; + } @@ -298,6 +372,13 @@ sub format_amount { $amount = join '', reverse split //, $amount; $amount .= "\.$dec" if ($dec ne ""); } + + if ($myconfig->{numberformat} eq "1'000.00") { + $amount =~ s/\d{3,}?/$&'/g; + $amount =~ s/'$//; + $amount = join '', reverse split //, $amount; + $amount .= "\.$dec" if ($dec ne ""); + } if ($myconfig->{numberformat} eq '1.000,00') { $amount =~ s/\d{3,}?/$&./g; @@ -345,6 +426,10 @@ sub parse_amount { $amount =~ s/,/\./; } + if ($myconfig->{numberformat} eq "1'000.00") { + $amount =~ s/'//g; + } + $amount =~ s/,//g; return ($amount * 1); @@ -358,7 +443,7 @@ sub round_amount { # $places = 3 if $places == 2; if (($places * 1) >= 0) { - # compensate for perl behaviour, add 1/10^$places+3 + # add 1/10^$places+3 sprintf("%.${places}f", $amount + (1 / (10 ** ($places + 3))) * (($amount > 0) ? 1 : -1)); } else { $places *= -1; @@ -371,15 +456,23 @@ sub round_amount { sub parse_template { my ($self, $myconfig, $userspath) = @_; - # { Moritz Bunkus - # Some variables used for page breaks my ($chars_per_line, $lines_on_first_page, $lines_on_second_page) = (0, 0, 0); my ($current_page, $current_line) = (1, 1); my $pagebreak = ""; my $sum = 0; - # } Moritz Bunkus - open(IN, "$self->{templates}/$self->{IN}") or $self->error("$self->{IN} : $!"); + my $subdir = ""; + my $err = ""; + + if ($self->{language_code}) { + if (-f "$self->{templates}/$self->{language_code}/$self->{IN}") { + open(IN, "$self->{templates}/$self->{language_code}/$self->{IN}") or $self->error("$self->{IN} : $!"); + } else { + open(IN, "$self->{templates}/$self->{IN}") or $self->error("$self->{IN} : $!"); + } + } else { + open(IN, "$self->{templates}/$self->{IN}") or $self->error("$self->{IN} : $!"); + } @_ = ; close(IN); @@ -389,21 +482,24 @@ sub parse_template { # OUT is used for the media, screen, printer, email # for postscript we store a copy in a temporary file my $fileid = time; - $self->{tmpfile} = "$userspath/${fileid}.$self->{IN}"; + my $tmpfile = $self->{IN}; + $tmpfile =~ s/\./\.$self->{fileid}./ if $self->{fileid}; + $self->{tmpfile} = "$userspath/${fileid}.${tmpfile}"; + if ($self->{format} =~ /(postscript|pdf)/ || $self->{media} eq 'email') { $out = $self->{OUT}; $self->{OUT} = ">$self->{tmpfile}"; } - if ($self->{OUT}) { open(OUT, "$self->{OUT}") or $self->error("$self->{OUT} : $!"); } else { open(OUT, ">-") or $self->error("STDOUT : $!"); + $self->header; + } - # first we generate a tmpfile # read file and replace <%variable%> while ($_ = shift) { @@ -412,28 +508,26 @@ sub parse_template { $var = $_; - # { Moritz Bunkus # detect pagebreak block and its parameters - if (/<%pagebreak ([0-9]+) ([0-9]+) ([0-9]+)%>/) { + if (/\s*<%pagebreak ([0-9]+) ([0-9]+) ([0-9]+)%>/) { $chars_per_line = $1; $lines_on_first_page = $2; $lines_on_second_page = $3; while ($_ = shift) { - last if (/<\%end pagebreak%>/); + last if (/\s*<%end pagebreak%>/); $pagebreak .= $_; } } - # } Moritz Bunkus - if (/<%foreach /) { + if (/\s*<%foreach /) { # this one we need for the count chomp $var; - $var =~ s/<%foreach (.+?)%>/$1/; + $var =~ s/\s*<%foreach (.+?)%>/$1/; while ($_ = shift) { - last if (/<%end /); + last if (/\s*<%end /); # store line in $par $par .= $_; @@ -442,7 +536,6 @@ sub parse_template { # display contents of $self->{number}[] array for $i (0 .. $#{ $self->{$var} }) { - # { Moritz Bunkus # Try to detect whether a manual page break is necessary # but only if there was a <%pagebreak ...%> block before @@ -480,26 +573,23 @@ sub parse_template { $current_line += $lines; } $sum += $self->parse_amount($myconfig, $self->{"linetotal"}[$i]); - # } Moritz Bunkus - # don't parse par, we need it for each line - $_ = $par; - s/<%(.+?)%>/$self->{$1}[$i]/mg; - print OUT; + print OUT $self->format_line($par, $i); + } next; } # if not comes before if! - if (/<%if not /) { + if (/\s*<%if not /) { # check if it is not set and display chop; - s/<%if not (.+?)%>/$1/; + s/\s*<%if not (.+?)%>/$1/; unless ($self->{$_}) { while ($_ = shift) { - last if (/<%end /); + last if (/\s*<%end /); # store line in $par $par .= $_; @@ -509,20 +599,20 @@ sub parse_template { } else { while ($_ = shift) { - last if (/<%end /); + last if (/\s*<%end /); } next; } } - if (/<%if /) { + if (/\s*<%if /) { # check if it is set and display chop; - s/<%if (.+?)%>/$1/; + s/\s*<%if (.+?)%>/$1/; if ($self->{$_}) { while ($_ = shift) { - last if (/<%end /); + last if (/\s*<%end /); # store line in $par $par .= $_; @@ -532,26 +622,30 @@ sub parse_template { } else { while ($_ = shift) { - last if (/<%end /); + last if (/\s*<%end /); } next; } } # check for <%include filename%> - if (/<%include /) { + if (/\s*<%include /) { # get the filename chomp $var; - $var =~ s/<%include (.+?)%>/$1/; + $var =~ s/\s*<%include (.+?)%>/$1/; - # mangle filename if someone tries to be cute - $var =~ s/\///g; + # mangle filename + $var =~ s/(\/|\.\.)//g; # prevent the infinite loop! next if ($self->{"$var"}); - open(INC, "$self->{templates}/$var") or $self->error($self->cleanup."$self->{templates}/$var : $!"); + unless (open(INC, "$self->{templates}/$var")) { + $err = $!; + $self->cleanup; + $self->error("$self->{templates}/$var : $err"); + } unshift(@_, ); close(INC); @@ -560,32 +654,35 @@ sub parse_template { next; } - s/<%(.+?)%>/$self->{$1}/g; - print OUT; + print OUT $self->format_line($_); + } close(OUT); - # { Moritz Bunkus # Convert the tex file to postscript if ($self->{format} =~ /(postscript|pdf)/) { use Cwd; $self->{cwd} = cwd(); - chdir("$userspath") or $self->error($self->cleanup."chdir : $!"); + $self->{tmpdir} = "$self->{cwd}/$userspath"; + + unless (chdir("$userspath")) { + $err = $!; + $self->cleanup; + $self->error("chdir : $err"); + } $self->{tmpfile} =~ s/$userspath\///g; - # DS. added screen and email option in addition to printer - # screen if ($self->{format} eq 'postscript') { system("latex --interaction=nonstopmode $self->{tmpfile} > $self->{tmpfile}.err"); $self->error($self->cleanup) if ($?); - + $self->{tmpfile} =~ s/tex$/dvi/; - - system("dvips $self->{tmpfile} -o -q > /dev/null"); + + system("dvips $self->{tmpfile} -o -q"); $self->error($self->cleanup."dvips : $!") if ($?); $self->{tmpfile} =~ s/dvi$/ps/; } @@ -597,6 +694,7 @@ sub parse_template { } + if ($self->{format} =~ /(postscript|pdf)/ || $self->{media} eq 'email') { if ($self->{media} eq 'email') { @@ -605,22 +703,28 @@ sub parse_template { my $mail = new Mailer; - $self->{email} =~ s/,/>,{$_} = $self->{$_} } qw(cc bcc subject message version format charset); - $mail->{to} = qq|"$self->{name}" <$self->{email}>|; + $mail->{to} = qq|$self->{email}|; $mail->{from} = qq|"$myconfig->{name}" <$myconfig->{email}>|; $mail->{fileid} = "$fileid."; # if we send html or plain text inline - if (($self->{format} eq 'html') && ($self->{sendmode} eq 'inline')) { - $mail->{contenttype} = "text/html"; + if (($self->{format} =~ /(html|txt)/) && ($self->{sendmode} eq 'inline')) { + my $br = ""; + $br = "
" if $self->{format} eq 'html'; + + $mail->{contenttype} = "text/$self->{format}"; - $mail->{message} =~ s/\r\n/
\n/g; - $myconfig->{signature} =~ s/\\n/
\n/g; - $mail->{message} .= "
\n--
\n$myconfig->{signature}\n
"; + $mail->{message} =~ s/\r\n/$br\n/g; + $myconfig->{signature} =~ s/\\n/$br\n/g; + $mail->{message} .= "$br\n-- $br\n$myconfig->{signature}\n$br" if $myconfig->{signature}; - open(IN, $self->{tmpfile}) or $self->error($self->cleanup."$self->{tmpfile} : $!"); + unless (open(IN, $self->{tmpfile})) { + $err = $!; + $self->cleanup; + $self->error("$self->{tmpfile} : $err"); + } + while () { $mail->{message} .= $_; } @@ -632,37 +736,57 @@ sub parse_template { @{ $mail->{attachments} } = ($self->{tmpfile}); $myconfig->{signature} =~ s/\\n/\r\n/g; - $mail->{message} .= "\r\n--\r\n$myconfig->{signature}"; + $mail->{message} .= "\r\n-- \r\n$myconfig->{signature}" if $myconfig->{signature}; } - my $err = $mail->send($out); - $self->error($self->cleanup."$err") if ($err); + if ($err = $mail->send($out)) { + $self->cleanup; + $self->error($err); + } } else { $self->{OUT} = $out; - open(IN, $self->{tmpfile}) or $self->error($self->cleanup."$self->{tmpfile} : $!"); + unless (open(IN, $self->{tmpfile})) { + $err = $!; + $self->cleanup; + $self->error("$self->{tmpfile} : $err"); + } + + binmode(IN); - $self->{copies} = 1 unless $self->{media} eq 'printer'; + $self->{copies} = 1 if $self->{media} =~ /(screen|email|queue)/; + + chdir("$self->{cwd}"); for my $i (1 .. $self->{copies}) { - if ($self->{OUT}) { - open(OUT, $self->{OUT}) or $self->error($self->cleanup."$self->{OUT} : $!"); + unless (open(OUT, $self->{OUT})) { + $err = $!; + $self->cleanup; + $self->error("$self->{OUT} : $err"); + } } else { - open(OUT, ">-") or $self->error($self->cleanup."$!: STDOUT"); - + # launch application - print qq|Content-Type: application/$self->{format}; name="$self->{tmpfile}" - Content-Disposition: filename="$self->{tmpfile}" + print qq|Content-Type: application/$self->{format} +Content-Disposition: attachment; filename="$self->{tmpfile}"\n\n|; + + unless (open(OUT, ">-")) { + $err = $!; + $self->cleanup; + $self->error("STDOUT : $err"); + } - |; } + + binmode(OUT); while () { print OUT $_; } + close(OUT); seek IN, 0, 0; } @@ -673,7 +797,92 @@ sub parse_template { $self->cleanup; } - # } Moritz Bunkus + +} + + +sub format_line { + my $self = shift; + + $_ = shift; + my $i = shift; + my ($str, $pos, $l, $item, $newstr); + my $var = ""; + my %a; + + while (/<%(.+?)%>/) { + + %a = (); + + foreach $item (split / /, $1) { + my ($key, $value) = split /=/, $item; + if (defined $value) { + $a{$key} = $value; + } else { + $var = $item; + } + } + + $str = (defined $i) ? $self->{$var}[$i] : $self->{$var}; + + if ($a{align} || $a{width} || $a{offset}) { + + $str =~ s/( |\n)+/" " x $a{offset}/ge; + $l = length $str; + + if ($l > $a{width}) { + if (($pos = rindex $str, " ", $a{width}) > 0) { + $newstr = substr($str, 0, $pos); + $newstr .= "\n"; + $str = substr($str, $pos + 1); + + while (length $str > $a{width}) { + if (($pos = rindex $str, " ", $a{width}) > 0) { + $newstr .= (" " x $a{offset}).substr($str, 0, $pos); + $newstr .= "\n"; + $str = substr($str, $pos + 1); + } else { + $newstr .= (" " x $a{offset}).substr($str, 0, $a{width}); + $newstr .= "\n"; + $str = substr($str, $a{width} + 1); + } + } + } + $l = length $str; + $str .= " " x ($a{width} - $l); + $newstr .= (" " x $a{offset}).$str; + $str = $newstr; + + $l = $a{width}; + } + + # pad left, right or center + $pos = lc $a{align}; + $l = ($a{width} - $l); + + my $pad = " " x $l; + + if ($pos eq 'right') { + $str = "$pad$str"; + } + + if ($pos eq 'left') { + $str = "$str$pad"; + } + + if ($pos eq 'center') { + $pad = " " x ($l/2); + $str = "$pad$str"; + $pad = " " x ($l/2 + 1) if ($l % 2); + $str .= "$pad"; + } + } + + s/<%(.+?)%>/$str/; + + } + + $_; } @@ -681,6 +890,8 @@ sub parse_template { sub cleanup { my $self = shift; + chdir("$self->{tmpdir}"); + my @err = (); if (-f "$self->{tmpfile}.err") { open(FH, "$self->{tmpfile}.err"); @@ -695,7 +906,6 @@ sub cleanup { unlink(<$tmpfile.*>); } - chdir("$self->{cwd}"); "@err"; @@ -711,19 +921,22 @@ sub format_string { $format = 'tex'; } - my %replace = ( 'order' => { 'html' => [ quotemeta('\n'), ' ' ], - 'tex' => [ '&', quotemeta('\n'), ' ', + my %replace = ( 'order' => { html => [ '<', '>', quotemeta('\n'), ' ' ], + txt => [ quotemeta('\n') ], + tex => [ '&', quotemeta('\n'), ' ', '\$', '%', '_', '#', quotemeta('^'), - '{', '}', '<', '>', '£' ] }, - 'html' => { + '{', '}', '<', '>', '£', + quotemeta('\\\\') ] }, + html => { '<' => '<', '>' => '>', quotemeta('\n') => '
', ' ' => '
' }, - 'tex' => { + txt => { quotemeta('\n') }, + tex => { '&' => '\&', '\$' => '\$', '%' => '\%', '_' => '\_', '#' => '\#', quotemeta('^') => '\^\\', '{' => '\{', '}' => '\}', '<' => '$<$', '>' => '$>$', quotemeta('\n') => '\newline ', ' ' => '\newline ', - '£' => '\pounds ', + '£' => '\pounds ', quotemeta('\\\\') => '$\backslash$' } ); @@ -737,27 +950,16 @@ sub format_string { sub datetonum { my ($self, $date, $myconfig) = @_; - if ($date) { - # get separator - my $spc = $myconfig->{dateformat}; - $spc =~ s/\w//g; - $spc = substr($spc, 1, 1); - - if ($spc eq '.') { - $spc = '\.'; - } - if ($spc eq '/') { - $spc = '\/'; - } + if ($date && $date =~ /\D/) { if ($myconfig->{dateformat} =~ /^yy/) { - ($yy, $mm, $dd) = split /$spc/, $date; + ($yy, $mm, $dd) = split /\D/, $date; } if ($myconfig->{dateformat} =~ /^mm/) { - ($mm, $dd, $yy) = split /$spc/, $date; + ($mm, $dd, $yy) = split /\D/, $date; } if ($myconfig->{dateformat} =~ /^dd/) { - ($dd, $mm, $yy) = split /$spc/, $date; + ($dd, $mm, $yy) = split /\D/, $date; } $dd *= 1; @@ -776,7 +978,6 @@ sub datetonum { } - # Database routines used throughout sub dbconnect { @@ -803,7 +1004,7 @@ sub dbconnect_noauto { # set db options if ($myconfig->{dboptions}) { - $dbh->do($myconfig->{dboptions}) || $self->dberror($myconfig->{dboptions}); + $dbh->do($myconfig->{dboptions}); } $dbh; @@ -811,18 +1012,45 @@ sub dbconnect_noauto { } +sub dbquote { + my ($self, $var, $type) = @_; + + my $rv = 'NULL'; + + # DBI does not return NULL for SQL_DATE if the date is empty, bug ? + if (defined $var) { + if (defined $type) { + if ($type eq 'SQL_DATE') { + $rv = "'$var'" if $var; + } elsif ($type eq 'SQL_INT.*') { + $rv = int $var; + } else { + if ($type !~ /SQL_.*CHAR/) { + $rv = $var * 1; + } else { + $var =~ s/'/''/g; + $rv = "'$var'"; + } + } + } else { + $var =~ s/'/''/g; + $rv = "'$var'"; + } + } + + $rv; + +} + + sub update_balance { my ($self, $dbh, $table, $field, $where, $value) = @_; # if we have a value, go do it if ($value != 0) { # retrieve balance from table - my $query = "SELECT $field FROM $table WHERE $where"; - my $sth = $dbh->prepare($query); - - $sth->execute || $self->dberror($query); - my ($balance) = $sth->fetchrow_array; - $sth->finish; + my $query = "SELECT $field FROM $table WHERE $where FOR UPDATE"; + my ($balance) = $dbh->selectrow_array($query); $balance += $value; # update balance @@ -841,7 +1069,8 @@ sub update_exchangerate { my $query = qq|SELECT curr FROM exchangerate WHERE curr = '$curr' - AND transdate = '$transdate'|; + AND transdate = '$transdate' + FOR UPDATE|; my $sth = $dbh->prepare($query); $sth->execute || $self->dberror($query); @@ -869,77 +1098,35 @@ sub update_exchangerate { } +sub save_exchangerate { + my ($self, $myconfig, $currency, $transdate, $rate, $fld) = @_; + + my $dbh = $self->dbconnect($myconfig); + + my ($buy, $sell) = (0, 0); + $buy = $rate if $fld eq 'buy'; + $sell = $rate if $fld eq 'sell'; + + $self->update_exchangerate($dbh, $currency, $transdate, $buy, $sell); + + $dbh->disconnect; + +} + + sub get_exchangerate { my ($self, $dbh, $curr, $transdate, $fld) = @_; my $query = qq|SELECT $fld FROM exchangerate WHERE curr = '$curr' AND transdate = '$transdate'|; - my $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); - - my ($exchangerate) = $sth->fetchrow_array; - $sth->finish; + my ($exchangerate) = $dbh->selectrow_array($query); $exchangerate; } -sub delete_exchangerate { - my ($self, $dbh) = @_; - - my @transdate = (); - my $transdate; - - my $query = qq|SELECT DISTINCT transdate - FROM acc_trans - WHERE trans_id = $self->{id}|; - my $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); - - while ($transdate = $sth->fetchrow_array) { - push @transdate, $transdate; - } - $sth->finish; - - $query = qq|SELECT transdate FROM acc_trans - WHERE ar.id = trans_id - AND ar.curr = '$self->{currency}' - AND transdate IN - (SELECT transdate FROM acc_trans - WHERE trans_id = $self->{id}) - AND trans_id != $self->{id} - UNION SELECT transdate FROM acc_trans - WHERE ap.id = trans_id - AND ap.curr = '$self->{currency}' - AND transdate IN - (SELECT transdate FROM acc_trans - WHERE trans_id = $self->{id}) - AND trans_id != $self->{id} - UNION SELECT transdate FROM oe - WHERE oe.curr = '$self->{currency}' - AND transdate IN - (SELECT transdate FROM acc_trans - WHERE trans_id = $self->{id})|; - $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); - - while ($transdate = $sth->fetchrow_array) { - @transdate = grep !/^$transdate$/, @transdate; - } - $sth->finish; - - foreach $transdate (@transdate) { - $query = qq|DELETE FROM exchangerate - WHERE curr = '$self->{currency}' - AND transdate = '$transdate'|; - $dbh->do($query) || $self->dberror($query); - } - -} - - sub check_exchangerate { my ($self, $myconfig, $currency, $transdate, $fld) = @_; @@ -950,11 +1137,8 @@ sub check_exchangerate { my $query = qq|SELECT $fld FROM exchangerate WHERE curr = '$currency' AND transdate = '$transdate'|; - my $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); - - my ($exchangerate) = $sth->fetchrow_array; - $sth->finish; + my ($exchangerate) = $dbh->selectrow_array($query); + $dbh->disconnect; $exchangerate; @@ -966,20 +1150,25 @@ sub add_shipto { my ($self, $dbh, $id) = @_; my $shipto; - foreach my $item (qw(name addr1 addr2 addr3 addr4 contact phone fax email)) { + foreach my $item (qw(name address1 address2 city state zipcode country contact phone fax email)) { if ($self->{"shipto$item"}) { $shipto = 1 if ($self->{$item} ne $self->{"shipto$item"}); } - $self->{"shipto$item"} =~ s/'/''/g; } if ($shipto) { - my $query = qq|INSERT INTO shipto (trans_id, shiptoname, shiptoaddr1, - shiptoaddr2, shiptoaddr3, shiptoaddr4, shiptocontact, - shiptophone, shiptofax, shiptoemail) VALUES ($id, - '$self->{shiptoname}', '$self->{shiptoaddr1}', - '$self->{shiptoaddr2}', '$self->{shiptoaddr3}', - '$self->{shiptoaddr4}', '$self->{shiptocontact}', + my $query = qq|INSERT INTO shipto (trans_id, shiptoname, shiptoaddress1, + shiptoaddress2, shiptocity, shiptostate, + shiptozipcode, shiptocountry, shiptocontact, + shiptophone, shiptofax, shiptoemail) VALUES ($id, | + .$dbh->quote($self->{shiptoname}).qq|, | + .$dbh->quote($self->{shiptoaddress1}).qq|, | + .$dbh->quote($self->{shiptoaddress2}).qq|, | + .$dbh->quote($self->{shiptocity}).qq|, | + .$dbh->quote($self->{shiptostate}).qq|, | + .$dbh->quote($self->{shiptozipcode}).qq|, | + .$dbh->quote($self->{shiptocountry}).qq|, | + .$dbh->quote($self->{shiptocontact}).qq|, '$self->{shiptophone}', '$self->{shiptofax}', '$self->{shiptoemail}')|; $dbh->do($query) || $self->dberror($query); @@ -991,13 +1180,14 @@ sub add_shipto { sub get_employee { my ($self, $dbh) = @_; - my $query = qq|SELECT name FROM employee - WHERE login = '$self->{login}'|; - my $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); - - ($self->{employee}) = $sth->fetchrow_array; - $sth->finish; + my $login = $self->{login}; + $login =~ s/@.*//; + my $query = qq|SELECT name, id FROM employee + WHERE login = '$login'|; + my (@a) = $dbh->selectrow_array($query); + $a[1] *= 1; + + @a; } @@ -1010,16 +1200,28 @@ sub get_name { my $dbh = $self->dbconnect($myconfig); my $name = $self->like(lc $self->{$table}); - my $query = qq~SELECT id, name, - addr1 || ' ' || addr2 || ' ' || addr3 || ' ' || addr4 AS address - FROM $table - WHERE lower(name) LIKE '$name' - ORDER BY name~; + my $query = qq~SELECT c.id, c.name, c.address1, c.address2, + c.city, c.state, c.zipcode, c.country + FROM $table c + WHERE lower(c.name) LIKE '$name' + ORDER BY c.name~; + + if ($self->{openinvoices}) { + $query = qq~SELECT DISTINCT c.id, c.name, c.address1, c.address2, + c.city, c.state, c.zipcode, c.country + FROM $self->{arap} a + JOIN $table c ON (a.${table}_id = c.id) + WHERE a.amount != a.paid + AND lower(c.name) LIKE '$name' + ORDER BY c.name~; + } + my $sth = $dbh->prepare($query); $sth->execute || $self->dberror($query); my $i = 0; + @{ $self->{name_list} } = (); while ($ref = $sth->fetchrow_hashref(NAME_lc)) { push(@{ $self->{name_list} }, $ref); $i++; @@ -1035,47 +1237,221 @@ sub get_name { # the selection sub is used in the AR, AP, IS, IR and OE module # sub all_vc { - my ($self, $myconfig, $table) = @_; + my ($self, $myconfig, $table, $module, $dbh, $enddate) = @_; - my $dbh = $self->dbconnect($myconfig); + my $ref; + my $closedb; + if (! defined $dbh) { + $dbh = $self->dbconnect($myconfig); + $closedb = 1; + } + my $sth; my $query = qq|SELECT count(*) FROM $table|; - my $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); - my ($count) = $sth->fetchrow_array; - $sth->finish; + my $where; + if (defined $enddate) { + $where = qq|AND (enddate IS NULL OR enddate >= '$enddate')|; + $query .= qq| WHERE 1=1 + $where|; + } + my ($count) = $dbh->selectrow_array($query); + # build selection list if ($count < $myconfig->{vclimit}) { $query = qq|SELECT id, name FROM $table + WHERE 1=1 + $where ORDER BY name|; $sth = $dbh->prepare($query); $sth->execute || $self->dberror($query); - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { push @{ $self->{"all_$table"} }, $ref; } - $sth->finish; } - $dbh->disconnect; - -} - - -sub create_links { - my ($self, $module, $myconfig, $table) = @_; - - $self->all_vc($myconfig, $table); - # get last customers or vendors - my ($query, $sth); + # get self + if (! $self->{employee_id}) { + ($self->{employee}, $self->{employee_id}) = split /--/, $self->{employee}; + ($self->{employee}, $self->{employee_id}) = $self->get_employee($dbh) unless $self->{employee_id}; + } + + # setup sales contacts + $query = qq|SELECT id, name + FROM employee + WHERE sales = '1' + $where + ORDER BY name|; + $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $self->{all_employees} }, $ref; + } + $sth->finish; + + + if ($module eq 'AR') { + # prepare query for departments + $query = qq|SELECT id, description + FROM department + WHERE role = 'P' + ORDER BY 2|; + + } else { + $query = qq|SELECT id, description + FROM department + ORDER BY 2|; + } + + $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $self->{all_departments} }, $ref; + } + $sth->finish; + + + # get projects + $query = qq|SELECT * + FROM project + ORDER BY projectnumber|; + $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); + + $self->{all_projects} = (); + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $self->{all_projects} }, $ref; + } + $sth->finish; + + # get language codes + $query = qq|SELECT * + FROM language + ORDER BY 2|; + $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); + + $self->{all_languages} = (); + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $self->{all_languages} }, $ref; + } + $sth->finish; + + $self->all_years($dbh, $myconfig); + + $dbh->disconnect if $closedb; + +} + + +# this is only used for reports +sub all_projects { + my ($self, $myconfig) = @_; + + my $dbh = $self->dbconnect($myconfig); + + my $query = qq|SELECT * + FROM project + ORDER BY projectnumber|; + $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); + + $self->{all_projects} = (); + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $self->{all_projects} }, $ref; + } + $sth->finish; + + $dbh->disconnect; + +} + + +sub all_departments { + my ($self, $myconfig, $table) = @_; my $dbh = $self->dbconnect($myconfig); + my $where = "1 = 1"; + if (defined $table) { + if ($table eq 'customer') { + $where = " role = 'P'"; + } + } + + my $query = qq|SELECT id, description + FROM department + WHERE $where + ORDER BY 2|; + my $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $self->{all_departments} }, $ref; + } + $sth->finish; + + $self->all_years($dbh, $myconfig); + + $dbh->disconnect; + +} + + +sub all_years { + my ($self, $dbh, $myconfig) = @_; + + # get years + my $query = qq|SELECT (SELECT MIN(transdate) FROM acc_trans), + (SELECT MAX(transdate) FROM acc_trans) + FROM defaults|; + my ($startdate, $enddate) = $dbh->selectrow_array($query); + + if ($myconfig->{dateformat} =~ /^yy/) { + ($startdate) = split /\W/, $startdate; + ($enddate) = split /\W/, $enddate; + } else { + (@_) = split /\W/, $startdate; + $startdate = @_[2]; + (@_) = split /\W/, $enddate; + $enddate = @_[2]; + } + + while ($enddate >= $startdate) { + push @{ $self->{all_years} }, $enddate--; + } + + %{ $self->{all_month} } = ( '01' => 'January', + '02' => 'February', + '03' => 'March', + '04' => 'April', + '05' => 'May ', + '06' => 'June', + '07' => 'July', + '08' => 'August', + '09' => 'September', + '10' => 'October', + '11' => 'November', + '12' => 'December' ); + +} + + +sub create_links { + my ($self, $module, $myconfig, $table) = @_; + + # get last customers or vendors + my ($query, $sth); + + my $dbh = $self->dbconnect($myconfig); + my %xkeyref = (); @@ -1090,7 +1466,7 @@ sub create_links { $self->{accounts} = ""; while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { - foreach my $key (split(/:/, $ref->{link})) { + foreach my $key (split /:/, $ref->{link}) { if ($key =~ /$module/) { # cross reference for keys $xkeyref{$ref->{accno}} = $key; @@ -1103,18 +1479,21 @@ sub create_links { } } $sth->finish; - - + if ($self->{id}) { my $arap = ($table eq 'customer') ? 'ar' : 'ap'; $query = qq|SELECT a.invnumber, a.transdate, a.${table}_id, a.datepaid, a.duedate, a.ordnumber, - a.taxincluded, a.curr AS currency, a.notes, c.name AS $table, - a.amount AS oldinvtotal, a.paid AS oldtotalpaid - FROM $arap a, $table c - WHERE a.${table}_id = c.id - AND a.id = $self->{id}|; + a.taxincluded, a.curr AS currency, a.notes, a.intnotes, + c.name AS $table, a.department_id, d.description AS department, + a.amount AS oldinvtotal, a.paid AS oldtotalpaid, + a.employee_id, e.name AS employee, c.language_code + FROM $arap a + JOIN $table c ON (a.${table}_id = c.id) + LEFT JOIN employee e ON (e.id = a.employee_id) + LEFT JOIN department d ON (d.id = a.department_id) + WHERE a.id = $self->{id}|; $sth = $dbh->prepare($query); $sth->execute || $self->dberror($query); @@ -1124,29 +1503,46 @@ sub create_links { } $sth->finish; + + # get printed, emailed + $query = qq|SELECT s.printed, s.emailed, s.spoolfile, s.formname + FROM status s + WHERE s.trans_id = $self->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + $self->{printed} .= "$ref->{formname} " if $ref->{printed}; + $self->{emailed} .= "$ref->{formname} " if $ref->{emailed}; + $self->{queued} .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile}; + } + $sth->finish; + map { $self->{$_} =~ s/ +$//g } qw(printed emailed queued); + + # get amounts from individual entries - $query = qq|SELECT c.accno, c.description, a.source, a.amount, + $query = qq|SELECT c.accno, c.description, a.source, a.amount, a.memo, a.transdate, a.cleared, a.project_id, p.projectnumber FROM acc_trans a JOIN chart c ON (c.id = a.chart_id) - LEFT JOIN project p ON (a.project_id = p.id) + LEFT JOIN project p ON (p.id = a.project_id) WHERE a.trans_id = $self->{id} AND a.fx_transaction = '0' ORDER BY transdate|; $sth = $dbh->prepare($query); $sth->execute || $self->dberror($query); + my $fld = ($table eq 'customer') ? 'buy' : 'sell'; - # get exchangerate for currency + $self->{exchangerate} = $self->get_exchangerate($dbh, $self->{currency}, $self->{transdate}, $fld); - + # store amounts in {acc_trans}{$key} for multiple accounts while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { $ref->{exchangerate} = $self->get_exchangerate($dbh, $self->{currency}, $ref->{transdate}, $fld); push @{ $self->{acc_trans}{$xkeyref{$ref->{accno}}} }, $ref; } - $sth->finish; $query = qq|SELECT d.curr AS currencies, d.closedto, d.revtrans, @@ -1179,22 +1575,14 @@ sub create_links { map { $self->{$_} = $ref->{$_} } keys %$ref; $sth->finish; - if ($self->{"$self->{vc}_id"}) { - # only setup currency - ($self->{currency}) = split /:/, $self->{currencies}; - - } else { - + if (! $self->{"$self->{vc}_id"}) { $self->lastname_used($dbh, $myconfig, $table, $module); - - my $fld = ($table eq 'customer') ? 'buy' : 'sell'; - # get exchangerate for currency - $self->{exchangerate} = $self->get_exchangerate($dbh, $self->{currency}, $self->{transdate}, $fld); - } } + $self->all_vc($myconfig, $table, $module, $dbh, $self->{transdate}); + $dbh->disconnect; } @@ -1204,27 +1592,40 @@ sub lastname_used { my ($self, $dbh, $myconfig, $table, $module) = @_; my $arap = ($table eq 'customer') ? "ar" : "ap"; - $arap = 'oe' if ($self->{type} =~ /_order/); - + my $where = "1 = 1"; + my $sth; + + if ($self->{type} =~ /_order/) { + $arap = 'oe'; + $where = "quotation = '0'"; + } + if ($self->{type} =~ /_quotation/) { + $arap = 'oe'; + $where = "quotation = '1'"; + } + my $query = qq|SELECT id FROM $arap WHERE id IN (SELECT MAX(id) FROM $arap - WHERE ${table}_id > 0)|; - my $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); - - my ($trans_id) = $sth->fetchrow_array; - $sth->finish; + WHERE $where + AND ${table}_id > 0)|; + my ($trans_id) = $dbh->selectrow_array($query); $trans_id *= 1; - $query = qq|SELECT ct.name, a.curr, a.${table}_id, - current_date + ct.terms AS duedate + + my $DAYS = ($myconfig->{dbdriver} eq 'DB2') ? "DAYS" : ""; + + $query = qq|SELECT ct.name AS $table, a.curr AS currency, a.${table}_id, + current_date + ct.terms $DAYS AS duedate, a.department_id, + d.description AS department, ct.notes, ct.curr AS currency FROM $arap a JOIN $table ct ON (a.${table}_id = ct.id) + LEFT JOIN department d ON (a.department_id = d.id) WHERE a.id = $trans_id|; $sth = $dbh->prepare($query); $sth->execute || $self->dberror($query); - ($self->{$table}, $self->{currency}, $self->{"${table}_id"}, $self->{duedate}) = $sth->fetchrow_array; + my $ref = $sth->fetchrow_hashref(NAME_lc); + map { $self->{$_} = $ref->{$_} } keys %$ref; $sth->finish; } @@ -1240,17 +1641,30 @@ sub current_date { $days *= 1; if ($thisdate) { my $dateformat = $myconfig->{dateformat}; - $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/; + if ($myconfig->{dateformat} !~ /^y/) { + my @a = split /\D/, $thisdate; + $dateformat .= "yy" if (length $a[2] > 2); + } - $query = qq|SELECT to_date('$thisdate', '$dateformat') + $days AS thisdate - FROM defaults|; - $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); + if ($thisdate !~ /\D/) { + $dateformat = 'yyyymmdd'; + } + + if ($myconfig->{dbdriver} eq 'DB2') { + $query = qq|SELECT date('$thisdate') + $days DAYS AS thisdate + FROM defaults|; + } else { + $query = qq|SELECT to_date('$thisdate', '$dateformat') + $days AS thisdate + FROM defaults|; + } + + $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); } else { $query = qq|SELECT current_date AS thisdate FROM defaults|; - $sth = $dbh->prepare($query); - $sth->execute || $self->dberror($query); + $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); } ($thisdate) = $sth->fetchrow_array; @@ -1264,14 +1678,14 @@ sub current_date { sub like { - my ($self, $string) = @_; + my ($self, $str) = @_; - unless ($string =~ /%/) { - $string = "%$string%"; + if ($str !~ /(%|_)/) { + $str = "%$str%"; } - $string =~ s/'/''/g; - $string; + $str =~ s/'/''/g; + $str; } @@ -1298,7 +1712,529 @@ sub redo_rows { } + +sub get_partsgroup { + my ($self, $myconfig, $p) = @_; + + my $dbh = $self->dbconnect($myconfig); + + my $query = qq|SELECT DISTINCT pg.id, pg.partsgroup + FROM partsgroup pg + JOIN parts p ON (p.partsgroup_id = pg.id)|; + + if ($p->{searchitems} eq 'part') { + $query .= qq| + WHERE p.inventory_accno_id > 0|; + } + if ($p->{searchitems} eq 'service') { + $query .= qq| + WHERE p.inventory_accno_id IS NULL|; + } + if ($p->{searchitems} eq 'assembly') { + $query .= qq| + WHERE p.assembly = '1'|; + } + if ($p->{searchitems} eq 'labor') { + $query .= qq| + WHERE p.inventory_accno_id > 0 AND p.income_accno_id IS NULL|; + } + + $query .= qq| + ORDER BY partsgroup|; + + if ($p->{all}) { + $query = qq|SELECT id, partsgroup FROM partsgroup + ORDER BY partsgroup|; + } + + if ($p->{language_code}) { + $query = qq|SELECT DISTINCT pg.id, pg.partsgroup, + t.description AS translation + FROM partsgroup pg + JOIN parts p ON (p.partsgroup_id = pg.id) + LEFT JOIN translation t ON (t.trans_id = pg.id AND t.language_code = '$p->{language_code}') + ORDER BY translation|; + } + + my $sth = $dbh->prepare($query); + $sth->execute || $self->dberror($query); + + $self->{all_partsgroup} = (); + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $self->{all_partsgroup} }, $ref; + } + $sth->finish; + $dbh->disconnect; + +} + + +sub update_status { + my ($self, $myconfig) = @_; + + # no id return + return unless $self->{id}; + + my $i; + my $id; + + my $dbh = $self->dbconnect_noauto($myconfig); + + my $query = qq|DELETE FROM status + WHERE formname = |.$dbh->quote($self->{formname}).qq| + AND trans_id = ?|; + my $sth = $dbh->prepare($query) || $self->dberror($query); + + if ($self->{formname} =~ /(check|receipt)/) { + for $i (1 .. $self->{rowcount}) { + $sth->execute($self->{"id_$i"} * 1) || $self->dberror($query); + $sth->finish; + } + } else { + $sth->execute($self->{id}) || $self->dberror($query); + $sth->finish; + } + + my $printed = ($self->{printed} =~ /$self->{formname}/) ? "1" : "0"; + my $emailed = ($self->{emailed} =~ /$self->{formname}/) ? "1" : "0"; + my %queued = split / /, $self->{queued}; + + if ($self->{formname} =~ /(check|receipt)/) { + # this is a check or receipt, add one entry for each lineitem + my ($accno) = split /--/, $self->{account}; + $query = qq|INSERT INTO status (trans_id, printed, spoolfile, formname, + chart_id) VALUES (?, '$printed',| + .$dbh->quote($queued{$self->{formname}}).qq|, | + .$dbh->quote($self->{formname}).qq|, + (SELECT id FROM chart WHERE accno = | + .$dbh->quote($accno).qq|))|; + $sth = $dbh->prepare($query) || $self->dberror($query); + + for $i (1 .. $self->{rowcount}) { + if ($self->{"checked_$i"}) { + $sth->execute($self->{"id_$i"}) || $self->dberror($query); + $sth->finish; + } + } + } else { + $query = qq|INSERT INTO status (trans_id, printed, emailed, + spoolfile, formname) + VALUES ($self->{id}, '$printed', '$emailed', | + .$dbh->quote($queued{$self->{formname}}).qq|, | + .$dbh->quote($self->{formname}).qq|)|; + $dbh->do($query) || $self->dberror($query); + } + + $dbh->commit; + $dbh->disconnect; + +} + + +sub save_status { + my ($self, $dbh) = @_; + + my ($query, $printed, $emailed); + + my $formnames = $self->{printed}; + my $emailforms = $self->{emailed}; + + my $query = qq|DELETE FROM status + WHERE formname = '$self->{formname}' + AND trans_id = $self->{id}|; + $dbh->do($query) || $self->dberror($query); + + if ($self->{queued}) { + $query = qq|DELETE FROM status + WHERE spoolfile IS NOT NULL + AND trans_id = $self->{id}|; + $dbh->do($query) || $self->dberror($query); + + my %queued = split / /, $self->{queued}; + + foreach my $formname (keys %queued) { + $printed = ($self->{printed} =~ /$self->{formname}/) ? "1" : "0"; + $emailed = ($self->{emailed} =~ /$self->{formname}/) ? "1" : "0"; + + $query = qq|INSERT INTO status (trans_id, printed, emailed, + spoolfile, formname) + VALUES ($self->{id}, '$printed', '$emailed', + '$queued{$formname}', '$formname')|; + $dbh->do($query) || $self->dberror($query); + $formnames =~ s/$formname//; + $emailforms =~ s/$formname//; + + } + } + + # save printed, emailed info + $formnames =~ s/^ +//g; + $emailforms =~ s/^ +//g; + + my %status = (); + map { $status{$_}{printed} = 1 } split / +/, $formnames; + map { $status{$_}{emailed} = 1 } split / +/, $emailforms; + + foreach my $formname (keys %status) { + $printed = ($formnames =~ /$self->{formname}/) ? "1" : "0"; + $emailed = ($emailforms =~ /$self->{formname}/) ? "1" : "0"; + + $query = qq|INSERT INTO status (trans_id, printed, emailed, formname) + VALUES ($self->{id}, '$printed', '$emailed', '$formname')|; + $dbh->do($query) || $self->dberror($query); + } + +} + + +sub save_intnotes { + my ($self, $myconfig, $table) = @_; + + # no id return + return unless $self->{id}; + + my $dbh = $self->dbconnect($myconfig); + + my $query = qq|UPDATE $table SET + intnotes = |.$dbh->quote($self->{intnotes}).qq| + WHERE id = $self->{id}|; + $dbh->do($query) || $self->dberror($query); + + $dbh->disconnect; + +} + + +sub update_defaults { + my ($self, $myconfig, $fld, $dbh) = @_; + + my $closedb; + + if (! defined $dbh) { + $dbh = $self->dbconnect_noauto($myconfig); + $closedb = 1; + } + + my $query = qq|SELECT $fld FROM defaults FOR UPDATE|; + ($_) = $dbh->selectrow_array($query); + + $_ = "0" unless $_; + + # check for and replace + # <%DATE%>, <%YYMMDD%> or variations of + # <%NAME 1 1 3%>, <%BUSINESS%>, <%BUSINESS 10%>, <%CURR...%> + # <%DESCRIPTION 1 1 3%>, <%ITEM 1 1 3%>, <%PARTSGROUP 1 1 3%> only for parts + # <%PHONE%> for customer and vendors + + my $num = $_; + $num =~ s/(<%.*?%>)//g; + ($num) = $num =~ /(\d+)/; + if (defined $num) { + my $incnum; + # if we have leading zeros check how long it is + if ($num =~ /^0/) { + my $l = length $num; + $incnum = $num + 1; + $l -= length $incnum; + + # pad it out with zeros + my $padzero = "0" x $l; + $incnum = ("0" x $l) . $incnum; + } else { + $incnum = $num + 1; + } + + s/$num/$incnum/; + } + + my $dbvar = $_; + my $var = $_; + my $str; + my $param; + + if (/<%/) { + while (/<%/) { + s/<%.*?%>//; + last unless $&; + $param = $&; + $str = ""; + + if ($param =~ /<%date%>/i) { + $str = ($self->split_date($myconfig->{dateformat}, $self->{transdate}))[0]; + $var =~ s/$param/$str/; + } + + if ($param =~ /<%(name|business|description|item|partsgroup|phone|custom)/i) { + my $fld = lc $&; + $fld =~ s/<%//; + if ($fld =~ /name/) { + if ($self->{type}) { + $fld = $self->{vc}; + } + } + + my $p = $param; + $p =~ s/(<|>|%)//g; + my @p = split / /, $p; + my @n = split / /, uc $self->{$fld}; + if ($#p > 0) { + for (my $i = 1; $i <= $#p; $i++) { + $str .= substr($n[$i-1], 0, $p[$i]); + } + } else { + ($str) = split /--/, $self->{$fld}; + } + $var =~ s/$param/$str/; + + $var =~ s/\W//g if $fld eq 'phone'; + } + + if ($param =~ /<%(yy|mm|dd)/i) { + my $p = $param; + $p =~ s/(<|>|%)//g; + my $spc = $p; + $spc =~ s/\w//g; + $spc = substr($spc, 0, 1); + my %d = ( yy => 1, mm => 2, dd => 3 ); + my @p = (); + + my @a = $self->split_date($myconfig->{dateformat}, $self->{transdate}); + map { push @p, $a[$d{$_}] if ($p =~ /$_/) } sort keys %d; + $str = join $spc, @p; + + $var =~ s/$param/$str/; + } + + if ($param =~ /<%curr/i) { + $var =~ s/$param/$self->{currency}/; + } + + } + } + + $query = qq|UPDATE defaults + SET $fld = '$dbvar'|; + $dbh->do($query) || $form->dberror($query); + + if ($closedb) { + $dbh->commit; + $dbh->disconnect; + } + + $var; + +} + + +sub split_date { + my ($self, $dateformat, $date) = @_; + + my @d = localtime; + my $mm; + my $dd; + my $yy; + my $rv; + + if (! $date) { + $dd = $d[3]; + $mm = $d[4]++; + $yy = substr($d[5],-2); + $mm *= 1; + $dd *= 1; + $mm = "0$mm" if $mm < 10; + $dd = "0$dd" if $dd < 10; + } + + if ($dateformat =~ /^yy/) { + if ($date) { + if ($date =~ /\D/) { + ($yy, $mm, $dd) = split /\D/, $date; + $mm *= 1; + $dd *= 1; + $mm = "0$mm" if $mm < 10; + $dd = "0$dd" if $dd < 10; + $yy = substr($yy, -2); + $rv = "$yy$mm$dd"; + } else { + $rv = $date; + } + } else { + $rv = "$yy$mm$dd"; + } + } + + if ($dateformat =~ /^mm/) { + if ($date) { + if ($date =~ /\D/) { + ($mm, $dd, $yy) = split /\D/, $date if $date; + $mm *= 1; + $dd *= 1; + $mm = "0$mm" if $mm < 10; + $dd = "0$dd" if $dd < 10; + $yy = substr($yy, -2); + $rv = "$mm$dd$yy"; + } else { + $rv = $date; + } + } else { + $rv = "$mm$dd$yy"; + } + } + + if ($dateformat =~ /^dd/) { + if ($date) { + if ($date =~ /\D/) { + ($dd, $mm, $yy) = split /\D/, $date if $date; + $mm *= 1; + $dd *= 1; + $mm = "0$mm" if $mm < 10; + $dd = "0$dd" if $dd < 10; + $yy = substr($yy, -2); + $rv = "$dd$mm$yy"; + } else { + $rv = $date; + } + } else { + $rv = "$dd$mm$yy"; + } + } + + ($rv, $yy, $mm, $dd); + +} + + +sub from_to { + my ($self, $yy, $mm, $interval) = @_; + + use Time::Local; + + my @t; + my $dd = 1; + my $fromdate = "$yy${mm}01"; + my $bd = 1; + + if (defined $interval) { + if ($interval == 12) { + $yy++ if $mm > 1; + } else { + if (($mm += $interval) > 12) { + $mm -= 12; + $yy++ if $mm > 1; + } + if ($interval == 0) { + @t = localtime(time); + $dd = $t[3]; + $mm = $t[4] + 1; + $yy = $t[5] + 1900; + $bd = 0; + } + } + } else { + if ($mm++ > 12) { + $mm -= 12; + $yy++; + } + } + + $mm--; + @t = localtime(timelocal(0,0,0,$dd,$mm,$yy) - $bd); + + $t[4]++; + $t[4] = substr("0$t[4]",-2); + $t[3] = substr("0$t[3]",-2); + + ($fromdate, "$yy$t[4]$t[3]"); + +} + + +sub audittrail { + my ($self, $dbh, $myconfig, $audittrail) = @_; + +# table, $reference, $formname, $action, $id, $transdate) = @_; + + my $query; + my $rv; + + # if we have an id add audittrail, otherwise get a new timestamp + + if ($audittrail->{id}) { + $dbh = $self->dbconnect($myconfig) if $myconfig; + + $query = qq|SELECT audittrail FROM defaults|; + + if ($dbh->selectrow_array($query)) { + my ($null, $employee_id) = $self->get_employee($dbh); + + if ($self->{audittrail} && !$myconfig) { + chop $self->{audittrail}; + + my @a = split /\|/, $self->{audittrail}; + my %newtrail = (); + my $key; + my $i; + my @flds = qw(tablename reference formname action transdate); + + # put into hash and remove dups + while (@a) { + $key = "$a[2]$a[3]"; + $i = 0; + $newtrail{$key} = { map { $_ => $a[$i++] } @flds }; + splice @a, 0, 5; + } + + $query = qq|INSERT INTO audittrail (trans_id, tablename, reference, + formname, action, employee_id, transdate) + VALUES ($audittrail->{id}, ?, ?, + ?, ?, $employee_id, ?)|; + my $sth = $dbh->prepare($query) || $self->dberror($query); + + foreach $key (sort { $newtrail{$a}{transdate} cmp $newtrail{$b}{transdate} } keys %newtrail) { + $i = 1; + map { $sth->bind_param($i++, $newtrail{$key}{$_}) } @flds; + + $sth->execute || $self->dberror; + $sth->finish; + } + } + + + if ($audittrail->{transdate}) { + $query = qq|INSERT INTO audittrail (trans_id, tablename, reference, + formname, action, employee_id, transdate) VALUES ( + $audittrail->{id}, '$audittrail->{tablename}', | + .$dbh->quote($audittrail->{reference}).qq|', + '$audittrail->{formname}', '$audittrail->{action}', + $employee_id, '$audittrail->{transdate}')|; + } else { + $query = qq|INSERT INTO audittrail (trans_id, tablename, reference, + formname, action, employee_id) VALUES ($audittrail->{id}, + '$audittrail->{tablename}', | + .$dbh->quote($audittrail->{reference}).qq|, + '$audittrail->{formname}', '$audittrail->{action}', + $employee_id)|; + } + $dbh->do($query); + } + } else { + $dbh = $self->dbconnect($myconfig); + + $query = qq|SELECT current_timestamp FROM defaults|; + my ($timestamp) = $dbh->selectrow_array($query); + + $rv = "$audittrail->{tablename}|$audittrail->{reference}|$audittrail->{formname}|$audittrail->{action}|$timestamp|"; + } + + $dbh->disconnect if $myconfig; + + $rv; + +} + + + package Locale; @@ -1352,27 +2288,26 @@ sub date { my $longdate = ""; my $longmonth = ($longformat) ? 'LONG_MONTH' : 'SHORT_MONTH'; + if ($date) { # get separator $spc = $myconfig->{dateformat}; $spc =~ s/\w//g; - $spc = substr($spc, 1, 1); + $spc = substr($spc, 0, 1); - if ($spc eq '.') { - $spc = '\.'; - } - if ($spc eq '/') { - $spc = '\/'; - } - - if ($myconfig->{dateformat} =~ /^yy/) { - ($yy, $mm, $dd) = split /$spc/, $date; - } - if ($myconfig->{dateformat} =~ /^mm/) { - ($mm, $dd, $yy) = split /$spc/, $date; - } - if ($myconfig->{dateformat} =~ /^dd/) { - ($dd, $mm, $yy) = split /$spc/, $date; + if ($date =~ /\D/) { + if ($myconfig->{dateformat} =~ /^yy/) { + ($yy, $mm, $dd) = split /\D/, $date; + } + if ($myconfig->{dateformat} =~ /^mm/) { + ($mm, $dd, $yy) = split /\D/, $date; + } + if ($myconfig->{dateformat} =~ /^dd/) { + ($dd, $mm, $yy) = split /\D/, $date; + } + } else { + $date = substr($date, 2); + ($yy, $mm, $dd) = ($date =~ /(..)(..)(..)/); } $dd *= 1; @@ -1381,9 +2316,34 @@ sub date { $yy = ($yy >= 70 && $yy <= 99) ? $yy + 1900 : $yy; if ($myconfig->{dateformat} =~ /^dd/) { - $longdate = "$dd. ".&text($self, $self->{$longmonth}[$mm])." $yy"; + $mm++; + $dd = "0$dd" if ($dd < 10); + $mm = "0$mm" if ($mm < 10); + $longdate = "$dd$spc$mm$spc$yy"; + + if (defined $longformat) { + $longdate = "$dd"; + $longdate .= ($spc eq '.') ? ". " : " "; + $longdate .= &text($self, $self->{$longmonth}[--$mm])." $yy"; + } + } elsif ($myconfig->{dateformat} =~ /^yy/) { + $mm++; + $dd = "0$dd" if ($dd < 10); + $mm = "0$mm" if ($mm < 10); + $longdate = "$yy$spc$mm$spc$dd"; + + if (defined $longformat) { + $longdate = &text($self, $self->{$longmonth}[--$mm])." $dd $yy"; + } } else { - $longdate = &text($self, $self->{$longmonth}[$mm])." $dd, $yy"; + $mm++; + $dd = "0$dd" if ($dd < 10); + $mm = "0$mm" if ($mm < 10); + $longdate = "$mm$spc$dd$spc$yy"; + + if (defined $longformat) { + $longdate = &text($self, $self->{$longmonth}[--$mm])." $dd $yy"; + } } } diff --git a/sql-ledger/SL/GL.pm b/sql-ledger/SL/GL.pm index 5bceb078a..221f71726 100644 --- a/sql-ledger/SL/GL.pm +++ b/sql-ledger/SL/GL.pm @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -24,10 +24,6 @@ # # General ledger backend code # -# CHANGE LOG: -# DS. 2000-07-04 Created -# DS. 2001-06-12 Changed relations from accno to chart_id -# #====================================================================== package GL; @@ -38,6 +34,14 @@ sub delete_transaction { # connect to database my $dbh = $form->dbconnect_noauto($myconfig); + + my %audittrail = ( tablename => 'gl', + reference => $form->{reference}, + formname => 'transaction', + action => 'deleted', + id => $form->{id} ); + + $form->audittrail($dbh, "", \%audittrail); my $query = qq|DELETE FROM gl WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); @@ -57,34 +61,11 @@ sub delete_transaction { sub post_transaction { my ($self, $myconfig, $form) = @_; - my ($debit, $credit) = (0, 0); + my $null; my $project_id; - + my $department_id; my $i; - # check if debit and credit balances - for $i (1 .. $form->{rowcount}) { - if ($form->{"debit_$i"} && $form->{"credit_$i"}) { - return -1; - } - - $form->{"debit_$i"} = $form->parse_amount($myconfig, $form->{"debit_$i"}); - $form->{"credit_$i"} = $form->parse_amount($myconfig, $form->{"credit_$i"}); - - $debit += $form->{"debit_$i"}; - $credit += $form->{"credit_$i"}; - } - - $debit = $form->round_amount($debit, 2); - $credit = $form->round_amount($credit, 2); - - if ($debit != $credit) { - return -2; - } - if (($debit + $credit) == 0) { - return -3; - } - # connect to database, turn off AutoCommit my $dbh = $form->dbconnect_noauto($myconfig); @@ -97,11 +78,8 @@ sub post_transaction { # if there is a $form->{id} replace the old transaction # delete all acc_trans entries and add the new ones - # escape ' - map { $form->{$_} =~ s/'/''/g } qw(reference description); - - - my ($query, $sth); + my $query; + my $sth; if ($form->{id}) { # delete individual transactions @@ -125,48 +103,75 @@ sub post_transaction { ($form->{id}) = $sth->fetchrow_array; $sth->finish; - } + ($null, $department_id) = split /--/, $form->{department}; + $department_id *= 1; + $query = qq|UPDATE gl SET - reference = '$form->{reference}', - description = '$form->{description}', - notes = '$form->{notes}', - transdate = '$form->{transdate}' + reference = |.$dbh->quote($form->{reference}).qq|, + description = |.$dbh->quote($form->{description}).qq|, + notes = |.$dbh->quote($form->{notes}).qq|, + transdate = '$form->{transdate}', + department_id = $department_id WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); - + + my $amount = 0; + my $posted = 0; # insert acc_trans transactions for $i (1 .. $form->{rowcount}) { + + $form->{"debit_$i"} = $form->parse_amount($myconfig, $form->{"debit_$i"}); + $form->{"credit_$i"} = $form->parse_amount($myconfig, $form->{"credit_$i"}); + # extract accno ($accno) = split(/--/, $form->{"accno_$i"}); - my $amount = 0; + $amount = 0; if ($form->{"credit_$i"} != 0) { $amount = $form->{"credit_$i"}; + $posted = 0; } if ($form->{"debit_$i"} != 0) { $amount = $form->{"debit_$i"} * -1; + $posted = 0; } - # if there is an amount, add the record - if ($amount != 0) { - $project_id = ($form->{"project_id_$i"}) ? $form->{"project_id_$i"} : 'NULL'; + # add the record + if (! $posted) { + + ($null, $project_id) = split /--/, $form->{"projectnumber_$i"}; + $project_id *= 1; + $form->{"fx_transaction_$i"} *= 1; + $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, - source, project_id) + source, project_id, fx_transaction) VALUES ($form->{id}, (SELECT id - FROM chart + FROM chart WHERE accno = '$accno'), - $amount, '$form->{transdate}', '$form->{reference}', - $project_id)|; + $amount, '$form->{transdate}', | + .$dbh->quote($form->{reference}).qq|, + $project_id, '$form->{"fx_transaction_$i"}')|; $dbh->do($query) || $form->dberror($query); + + $posted = 1; } + } + + my %audittrail = ( tablename => 'gl', + reference => $form->{reference}, + formname => 'transaction', + action => 'posted', + id => $form->{id} ); + + $form->audittrail($dbh, "", \%audittrail); # commit and redirect my $rc = $dbh->commit; @@ -185,21 +190,33 @@ sub all_transactions { my $dbh = $form->dbconnect($myconfig); my $query; my $sth; + my $var; + my $null; my ($glwhere, $arwhere, $apwhere) = ("1 = 1", "1 = 1", "1 = 1"); if ($form->{reference}) { - my $source = $form->like(lc $form->{reference}); - $glwhere .= " AND lower(g.reference) LIKE '$source'"; - $arwhere .= " AND lower(a.invnumber) LIKE '$source'"; - $apwhere .= " AND lower(a.invnumber) LIKE '$source'"; + $var = $form->like(lc $form->{reference}); + $glwhere .= " AND lower(g.reference) LIKE '$var'"; + $arwhere .= " AND lower(a.invnumber) LIKE '$var'"; + $apwhere .= " AND lower(a.invnumber) LIKE '$var'"; } + if ($form->{department}) { + ($null, $var) = split /--/, $form->{department}; + $glwhere .= " AND g.department_id = $var"; + $arwhere .= " AND a.department_id = $var"; + $apwhere .= " AND a.department_id = $var"; + } + if ($form->{source}) { - my $source = $form->like(lc $form->{source}); - $glwhere .= " AND lower(ac.source) LIKE '$source'"; - $arwhere .= " AND lower(ac.source) LIKE '$source'"; - $apwhere .= " AND lower(ac.source) LIKE '$source'"; + $var = $form->like(lc $form->{source}); + $glwhere .= " AND lower(ac.source) LIKE '$var'"; + $arwhere .= " AND lower(ac.source) LIKE '$var'"; + $apwhere .= " AND lower(ac.source) LIKE '$var'"; } + + ($form->{datefrom}, $form->{dateto}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month}; + if ($form->{datefrom}) { $glwhere .= " AND ac.transdate >= '$form->{datefrom}'"; $arwhere .= " AND ac.transdate >= '$form->{datefrom}'"; @@ -210,17 +227,27 @@ sub all_transactions { $arwhere .= " AND ac.transdate <= '$form->{dateto}'"; $apwhere .= " AND ac.transdate <= '$form->{dateto}'"; } + if ($form->{amountfrom}) { + $glwhere .= " AND abs(ac.amount) >= $form->{amountfrom}"; + $arwhere .= " AND abs(ac.amount) >= $form->{amountfrom}"; + $apwhere .= " AND abs(ac.amount) >= $form->{amountfrom}"; + } + if ($form->{amountto}) { + $glwhere .= " AND abs(ac.amount) <= $form->{amountto}"; + $arwhere .= " AND abs(ac.amount) <= $form->{amountto}"; + $apwhere .= " AND abs(ac.amount) <= $form->{amountto}"; + } if ($form->{description}) { - my $description = $form->like(lc $form->{description}); - $glwhere .= " AND lower(g.description) LIKE '$description'"; - $arwhere .= " AND lower(ct.name) LIKE '$description'"; - $apwhere .= " AND lower(ct.name) LIKE '$description'"; + $var = $form->like(lc $form->{description}); + $glwhere .= " AND lower(g.description) LIKE '$var'"; + $arwhere .= " AND lower(ct.name) LIKE '$var'"; + $apwhere .= " AND lower(ct.name) LIKE '$var'"; } if ($form->{notes}) { - my $notes = $form->like(lc $form->{notes}); - $glwhere .= " AND lower(g.notes) LIKE '$notes'"; - $arwhere .= " AND lower(a.notes) LIKE '$notes'"; - $apwhere .= " AND lower(a.notes) LIKE '$notes'"; + $var = $form->like(lc $form->{notes}); + $glwhere .= " AND lower(g.notes) LIKE '$var'"; + $arwhere .= " AND lower(a.notes) LIKE '$var'"; + $apwhere .= " AND lower(a.notes) LIKE '$var'"; } if ($form->{accno}) { $glwhere .= " AND c.accno = '$form->{accno}'"; @@ -240,68 +267,56 @@ sub all_transactions { if ($form->{accno}) { # get category for account - $query = qq|SELECT category + $query = qq|SELECT category, link FROM chart WHERE accno = '$form->{accno}'|; - $sth = $dbh->prepare($query); - - $sth->execute || $form->dberror($query); - ($form->{ml}) = $sth->fetchrow_array; - $sth->finish; + ($form->{ml}, $form->{link}) = $dbh->selectrow_array($query); if ($form->{datefrom}) { $query = qq|SELECT SUM(ac.amount) - FROM acc_trans ac, chart c - WHERE ac.chart_id = c.id - AND c.accno = '$form->{accno}' + FROM acc_trans ac + JOIN chart c ON (ac.chart_id = c.id) + WHERE c.accno = '$form->{accno}' AND ac.transdate < date '$form->{datefrom}' |; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - ($form->{balance}) = $sth->fetchrow_array; - $sth->finish; + ($form->{balance}) = $dbh->selectrow_array($query); } } if ($form->{gifi_accno}) { # get category for account - $query = qq|SELECT category + $query = qq|SELECT category, link FROM chart WHERE gifi_accno = '$form->{gifi_accno}'|; - $sth = $dbh->prepare($query); - - $sth->execute || $form->dberror($query); - ($form->{ml}) = $sth->fetchrow_array; - $sth->finish; + ($form->{ml}, $form->{link}) = $dbh->selectrow_array($query); if ($form->{datefrom}) { $query = qq|SELECT SUM(ac.amount) - FROM acc_trans ac, chart c - WHERE ac.chart_id = c.id - AND c.gifi_accno = '$form->{gifi_accno}' + FROM acc_trans ac + JOIN chart c ON (ac.chart_id = c.id) + WHERE c.gifi_accno = '$form->{gifi_accno}' AND ac.transdate < date '$form->{datefrom}' |; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - ($form->{balance}) = $sth->fetchrow_array; - $sth->finish; + ($form->{balance}) = $dbh->selectrow_array($query); } } - my $false = ($myconfig->{dbdriver} eq 'Pg') ? FALSE : q|'0'|; + my $false = ($myconfig->{dbdriver} =~ /Pg/) ? FALSE : q|'0'|; - my $sortorder = join ', ', $form->sort_columns(qw(transdate reference source description accno)); - my %ordinal = ( transdate => 6, + my %ordinal = ( id => 1, + accno => 9, + transdate => 6, reference => 4, source => 7, description => 5 ); - map { $sortorder =~ s/$_/$ordinal{$_}/ } keys %ordinal; + + my @a = (id, transdate, reference, source, description, accno); + my $sortorder = $form->sort_order(\@a, \%ordinal); my $query = qq|SELECT g.id, 'gl' AS type, $false AS invoice, g.reference, g.description, ac.transdate, ac.source, - ac.amount, c.accno, c.gifi_accno, g.notes + ac.amount, c.accno, c.gifi_accno, g.notes, c.link, + '' AS till, ac.cleared FROM gl g, acc_trans ac, chart c WHERE $glwhere AND ac.chart_id = c.id @@ -309,7 +324,8 @@ sub all_transactions { UNION ALL SELECT a.id, 'ar' AS type, a.invoice, a.invnumber, ct.name, ac.transdate, ac.source, - ac.amount, c.accno, c.gifi_accno, a.notes + ac.amount, c.accno, c.gifi_accno, a.notes, c.link, + a.till, ac.cleared FROM ar a, acc_trans ac, chart c, customer ct WHERE $arwhere AND ac.chart_id = c.id @@ -318,7 +334,8 @@ sub all_transactions { UNION ALL SELECT a.id, 'ap' AS type, a.invoice, a.invnumber, ct.name, ac.transdate, ac.source, - ac.amount, c.accno, c.gifi_accno, a.notes + ac.amount, c.accno, c.gifi_accno, a.notes, c.link, + a.till, ac.cleared FROM ap a, acc_trans ac, chart c, vendor ct WHERE $apwhere AND ac.chart_id = c.id @@ -328,6 +345,7 @@ sub all_transactions { my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { # gl @@ -347,7 +365,7 @@ sub all_transactions { # ar if ($ref->{type} eq "ar") { if ($ref->{invoice}) { - $ref->{module} = "is"; + $ref->{module} = ($ref->{till}) ? "ps" : "is"; } else { $ref->{module} = "ar"; } @@ -365,6 +383,7 @@ sub all_transactions { } + $sth->finish; if ($form->{accno}) { @@ -392,7 +411,7 @@ sub all_transactions { sub transaction { my ($self, $myconfig, $form) = @_; - my ($query, $sth); + my ($query, $sth, $ref); # connect to database my $dbh = $form->dbconnect($myconfig); @@ -406,27 +425,33 @@ sub transaction { ($form->{closedto}, $form->{revtrans}) = $sth->fetchrow_array; $sth->finish; - $query = "SELECT reference, description, notes, transdate - FROM gl - WHERE id = $form->{id}"; + $query = qq|SELECT g.*, + d.description AS department + FROM gl g + LEFT JOIN department d ON (d.id = g.department_id) + WHERE g.id = $form->{id}|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - ($form->{reference}, $form->{description}, $form->{notes}, $form->{transdate}) = $sth->fetchrow_array; + $ref = $sth->fetchrow_hashref(NAME_lc); + map { $form->{$_} = $ref->{$_} } keys %$ref; $sth->finish; # retrieve individual rows - $query = "SELECT c.accno, a.amount, project_id, - (SELECT p.projectnumber FROM project p - WHERE a.project_id = p.id) AS projectnumber - FROM acc_trans a, chart c - WHERE a.chart_id = c.id - AND a.trans_id = $form->{id} - ORDER BY accno"; + $query = qq|SELECT c.accno, c.description, ac.amount, ac.project_id, + p.projectnumber, ac.fx_transaction + FROM acc_trans ac + JOIN chart c ON (ac.chart_id = c.id) + LEFT JOIN project p ON (p.id = ac.project_id) + WHERE ac.trans_id = $form->{id} + ORDER BY accno|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + if ($ref->{fx_transaction}) { + $form->{transfer} = 1; + } push @{ $form->{GL} }, $ref; } } else { @@ -440,16 +465,43 @@ sub transaction { $sth->finish; + my $paid; + if ($form->{transfer}) { + $paid = "AND link LIKE '%_paid%' + AND NOT (category = 'I' + OR category = 'E') + + UNION + + SELECT accno,description + FROM chart + WHERE id IN (SELECT fxgain_accno_id FROM defaults) + OR id IN (SELECT fxloss_accno_id FROM defaults)"; + } + # get chart of accounts $query = qq|SELECT accno,description FROM chart WHERE charttype = 'A' + $paid ORDER by accno|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - $form->{chart} = ""; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_accno} }, $ref; + } + $sth->finish; + + # get projects + $query = qq|SELECT * + FROM project + ORDER BY projectnumber|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { - push @{ $form->{chart} }, $ref; + push @{ $form->{all_projects} }, $ref; } $sth->finish; diff --git a/sql-ledger/SL/HR.pm b/sql-ledger/SL/HR.pm new file mode 100644 index 000000000..6e1bae850 --- /dev/null +++ b/sql-ledger/SL/HR.pm @@ -0,0 +1,558 @@ +#===================================================================== +# SQL-Ledger Accounting +# Copyright (C) 2003 +# +# 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. +#====================================================================== +# +# backend code for human resources and payroll +# +#====================================================================== + +package HR; + + +sub get_employee { + my ($self, $myconfig, $form) = @_; + + my $dbh = $form->dbconnect($myconfig); + + my $query; + my $sth; + my $ref; + my $notid = ""; + + if ($form->{id}) { + $query = qq|SELECT e.* + FROM employee e + WHERE e.id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + $ref = $sth->fetchrow_hashref(NAME_lc); + + # check if employee can be deleted, orphaned + $form->{status} = "orphaned" unless $ref->{login}; + +$form->{status} = 'orphaned'; # leave orphaned for now until payroll is done + + $ref->{employeelogin} = $ref->{login}; + delete $ref->{login}; + map { $form->{$_} = $ref->{$_} } keys %$ref; + + $sth->finish; + + # get manager + $form->{managerid} *= 1; + $query = qq|SELECT name + FROM employee + WHERE id = $form->{managerid}|; + ($form->{manager}) = $dbh->selectrow_array($query); + + +######### disabled for now +if ($form->{deductions}) { + # get allowances + $query = qq|SELECT d.id, d.description, da.before, da.after, da.rate + FROM employeededuction da + JOIN deduction d ON (da.deduction_id = d.id) + WHERE da.employee_id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + $ref->{rate} *= 100; + push @{ $form->{all_employeededuction} }, $ref; + } + $sth->finish; +} + + $notid = qq|AND id != $form->{id}|; + + } + + + # get managers + $query = qq|SELECT id, name + FROM employee + WHERE sales = '1' + AND role = 'manager' + $notid + ORDER BY 2|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_manager} }, $ref; + } + $sth->finish; + + + # get deductions +if ($form->{deductions}) { + $query = qq|SELECT id, description + FROM deduction + ORDER BY 2|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_deduction} }, $ref; + } + $sth->finish; +} + + $dbh->disconnect; + +} + + + +sub save_employee { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect_noauto($myconfig); + my $query; + my $sth; + + if (! $form->{id}) { + my $uid = time; + $uid .= $form->{login}; + + $query = qq|INSERT INTO employee (name) + VALUES ('$uid')|; + $dbh->do($query) || $form->dberror($query); + + $query = qq|SELECT id FROM employee + WHERE name = '$uid'|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + ($form->{id}) = $sth->fetchrow_array; + $sth->finish; + } + + my ($null, $managerid) = split /--/, $form->{manager}; + $managerid *= 1; + $form->{sales} *= 1; + + $form->{employeenumber} = $form->update_defaults($myconfig, "employeenumber", $dbh) if ! $form->{employeenumber}; + + $query = qq|UPDATE employee SET + employeenumber = |.$dbh->quote($form->{employeenumber}).qq|, + name = |.$dbh->quote($form->{name}).qq|, + address1 = |.$dbh->quote($form->{address1}).qq|, + address2 = |.$dbh->quote($form->{address2}).qq|, + city = |.$dbh->quote($form->{city}).qq|, + state = |.$dbh->quote($form->{state}).qq|, + zipcode = |.$dbh->quote($form->{zipcode}).qq|, + country = |.$dbh->quote($form->{country}).qq|, + workphone = '$form->{workphone}', + homephone = '$form->{homephone}', + startdate = |.$form->dbquote($form->{startdate}, SQL_DATE).qq|, + enddate = |.$form->dbquote($form->{enddate}, SQL_DATE).qq|, + notes = |.$dbh->quote($form->{notes}).qq|, + role = '$form->{role}', + sales = '$form->{sales}', + email = |.$dbh->quote($form->{email}).qq|, + ssn = '$form->{ssn}', + dob = |.$form->dbquote($form->{dob}, SQL_DATE).qq|, + iban = '$form->{iban}', + bic = '$form->{bic}', + managerid = $managerid + WHERE id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + +# for now +if ($form->{selectdeduction}) { + # insert deduction and allowances for payroll + $query = qq|DELETE FROM employeededuction + WHERE employee_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $query = qq|INSERT INTO employeededuction (employee_id, deduction_id, + before, after, rate) VALUES ($form->{id},?,?,?,?)|; + my $sth = $dbh->prepare($query) || $form->dberror($query); + + for ($i = 1; $i <= $form->{deduction_rows}; $i++) { + map { $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"}) } qw(before after); + ($null, $deduction_id) = split /--/, $form->{"deduction_$i"}; + if ($deduction_id) { + $sth->execute($deduction_id, $form->{"before_$i"}, $form->{"after_$i"}, $form->{"rate_$i"} / 100) || $form->dberror($query); + } + } + $sth->finish; +} + + $dbh->commit; + $dbh->disconnect; + +} + + +sub delete_employee { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect_noauto($myconfig); + + # delete employee + my $query = qq|DELETE FROM $form->{db} + WHERE id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $dbh->commit; + $dbh->disconnect; + +} + + +sub employees { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $where = "1 = 1"; + $form->{sort} = ($form->{sort}) ? $form->{sort} : "name"; + my @a = qw(name); + my $sortorder = $form->sort_order(\@a); + + my $var; + + if ($form->{startdate}) { + $where .= " AND e.startdate >= '$startdate'"; + } + if ($form->{enddate}) { + $where .= " AND e.enddate >= '$enddate'"; + } + if ($form->{name}) { + $var = $form->like(lc $form->{name}); + $where .= " AND lower(e.name) LIKE '$var'"; + } + if ($form->{notes}) { + $var = $form->like(lc $form->{notes}); + $where .= " AND lower(e.notes) LIKE '$var'"; + } + if ($form->{status} eq 'sales') { + $where .= " AND e.sales = '1'"; + } + if ($form->{status} eq 'orphaned') { + $where .= qq| AND e.login IS NULL|; + } + + my $query = qq|SELECT e.*, m.name AS manager + FROM employee e + LEFT JOIN employee m ON (m.id = e.managerid) + WHERE $where + ORDER BY $sortorder|; + + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + $ref->{address} = ""; + map { $ref->{address} .= "$ref->{$_} "; } qw(address1 address2 city state zipcode country); + push @{ $form->{all_employee} }, $ref; + } + + $sth->finish; + $dbh->disconnect; + +} + + +sub get_deduction { + my ($self, $myconfig, $form) = @_; + + my $dbh = $form->dbconnect($myconfig); + my $query; + my $sth; + my $ref; + my $item; + my $i; + + if ($form->{id}) { + $query = qq|SELECT d.*, + c1.accno AS ap_accno, + c1.description AS ap_description, + c2.accno AS expense_accno, + c2.description AS expense_description + FROM deduction d + LEFT JOIN chart c1 ON (c1.id = d.ap_accno_id) + LEFT JOIN chart c2 ON (c2.id = d.expense_accno_id) + WHERE d.id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + $ref = $sth->fetchrow_hashref(NAME_lc); + map { $form->{$_} = $ref->{$_} } keys %$ref; + + $sth->finish; + + # check if orphaned +$form->{status} = 'orphaned'; # for now + + + # get the rates + $query = qq|SELECT rate, amount, above, below + FROM deductionrate + WHERE trans_id = $form->{id} + ORDER BY rate, amount|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{deductionrate} }, $ref; + } + $sth->finish; + + # get all for deductionbase + $query = qq|SELECT d.description, d.id, db.maximum + FROM deductionbase db + JOIN deduction d ON (d.id = db.deduction_id) + WHERE db.trans_id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{deductionbase} }, $ref; + } + $sth->finish; + + # get all for deductionafter + $query = qq|SELECT d.description, d.id + FROM deductionafter da + JOIN deduction d ON (d.id = da.deduction_id) + WHERE da.trans_id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{deductionafter} }, $ref; + } + $sth->finish; + + # build selection list for base and after + $query = qq|SELECT id, description + FROM deduction + WHERE id != $form->{id} + ORDER BY 2|; + + } else { + # build selection list for base and after + $query = qq|SELECT id, description + FROM deduction + ORDER BY 2|; + } + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_deduction} }, $ref; + } + $sth->finish; + + + my %category = ( ap => 'L', + expense => 'E' ); + + foreach $item (keys %category) { + $query = qq|SELECT accno, description + FROM chart + WHERE charttype = 'A' + AND category = '$category{$item}' + ORDER BY accno|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{"${item}_accounts"} }, $ref; + } + $sth->finish; + } + + + $dbh->disconnect; + +} + + +sub deductions { + my ($self, $myconfig, $form) = @_; + + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT d.id, d.description, d.employeepays, d.employerpays, + c1.accno AS ap_accno, c2.accno AS expense_accno, + dr.rate, dr.amount, dr.above, dr.below + FROM deduction d + JOIN deductionrate dr ON (dr.trans_id = d.id) + LEFT JOIN chart c1 ON (d.ap_accno_id = c1.id) + LEFT JOIN chart c2 ON (d.expense_accno_id = c2.id) + ORDER BY 2, 7, 8|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_deduction} }, $ref; + } + + $sth->finish; + $dbh->disconnect; + +} + + +sub save_deduction { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect_noauto($myconfig); + + ($form->{ap_accno}) = split /--/, $form->{ap_accno}; + ($form->{expense_accno}) = split /--/, $form->{expense_accno}; + + my $null; + my $deduction_id; + my $query; + my $sth; + + if (! $form->{id}) { + my $uid = time; + $uid .= $form->{login}; + + $query = qq|INSERT INTO deduction (description) + VALUES ('$uid')|; + $dbh->do($query) || $form->dberror($query); + + $query = qq|SELECT id FROM deduction + WHERE description = '$uid'|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + ($form->{id}) = $sth->fetchrow_array; + $sth->finish; + } + + + map { $form->{$_} = $form->parse_amount($myconfig, $form->{$_}) } qw(employeepays employerpays); + + $query = qq|UPDATE deduction SET + description = |.$dbh->quote($form->{description}).qq|, + ap_accno_id = + (SELECT id FROM chart + WHERE accno = '$form->{ap_accno}'), + expense_accno_id = + (SELECT id FROM chart + WHERE accno = '$form->{expense_accno}'), + employerpays = '$form->{employerpays}', + employeepays = '$form->{employeepays}', + fromage = |.$form->dbquote($form->{fromage}, SQL_INT).qq|, + toage = |.$form->dbquote($form->{toage}, SQL_INT).qq| + WHERE id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + + $query = qq|DELETE FROM deductionrate + WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $query = qq|INSERT INTO deductionrate + (trans_id, rate, amount, above, below) VALUES (?,?,?,?,?)|; + $sth = $dbh->prepare($query) || $form->dberror($query); + + for ($i = 1; $i <= $form->{rate_rows}; $i++) { + map { $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"}) } qw(rate amount above below); + $form->{"rate_$i"} /= 100; + + if ($form->{"rate_$i"} || $form->{"amount_$i"}) { + $sth->execute($form->{id}, $form->{"rate_$i"}, $form->{"amount_$i"}, $form->{"above_$i"}, $form->{"below_$i"}) || $form->dberror($query); + } + } + $sth->finish; + + + $query = qq|DELETE FROM deductionbase + WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $query = qq|INSERT INTO deductionbase + (trans_id, deduction_id, maximum) VALUES (?,?,?)|; + $sth = $dbh->prepare($query) || $form->dberror($query); + + for ($i = 1; $i <= $form->{base_rows}; $i++) { + ($null, $deduction_id) = split /--/, $form->{"base_$i"}; + $form->{"maximum_$i"} = $form->parse_amount($myconfig, $form->{"maximum_$i"}); + if ($deduction_id) { + $sth->execute($form->{id}, $deduction_id, $form->{"maximum_$i"}) || $form->dberror($query); + } + } + $sth->finish; + + + $query = qq|DELETE FROM deductionafter + WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $query = qq|INSERT INTO deductionafter + (trans_id, deduction_id) VALUES (?,?)|; + $sth = $dbh->prepare($query) || $form->dberror($query); + + for ($i = 1; $i <= $form->{after_rows}; $i++) { + ($null, $deduction_id) = split /--/, $form->{"after_$i"}; + if ($deduction_id) { + $sth->execute($form->{id}, $deduction_id) || $form->dberror($query); + } + } + $sth->finish; + + $dbh->commit; + $dbh->disconnect; + +} + + +sub delete_deduction { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect_noauto($myconfig); + + # delete deduction + my $query = qq|DELETE FROM $form->{db} + WHERE id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + foreach $item (qw(rate base after)) { + $query = qq|DELETE FROM deduction$item + WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + } + + $dbh->commit; + $dbh->disconnect; + +} + +1; + diff --git a/sql-ledger/SL/IC.pm b/sql-ledger/SL/IC.pm index f4a2f75ff..cf70b06ca 100644 --- a/sql-ledger/SL/IC.pm +++ b/sql-ledger/SL/IC.pm @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -34,11 +34,12 @@ sub get_part { # connect to db my $dbh = $form->dbconnect($myconfig); + my $i; my $query = qq|SELECT p.*, c1.accno AS inventory_accno, - c2.accno AS income_accno, - c3.accno AS expense_accno, + c2.accno AS income_accno, + c3.accno AS expense_accno, pg.partsgroup FROM parts p LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id) @@ -56,19 +57,23 @@ sub get_part { $sth->finish; my %oid = ('Pg' => 'a.oid', - 'Oracle' => 'a.rowid' + 'PgPP' => 'a.oid', + 'Oracle' => 'a.rowid', + 'DB2' => '1=1' ); - - - # part or service item + + # part, service item or labor $form->{item} = ($form->{inventory_accno}) ? 'part' : 'service'; + $form->{item} = 'labor' if ! $form->{income_accno}; + if ($form->{assembly}) { $form->{item} = 'assembly'; # retrieve assembly items $query = qq|SELECT p.id, p.partnumber, p.description, - p.sellprice, p.weight, a.qty, a.bom, p.unit, - pg.partsgroup + p.sellprice, p.weight, a.qty, a.bom, a.adj, p.unit, + p.lastcost, p.listprice, + pg.partsgroup, p.assembly, p.partsgroup_id FROM parts p JOIN assembly a ON (a.parts_id = p.id) LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) @@ -97,22 +102,20 @@ sub get_part { $form->{amount}{IC_cogs} = $form->{expense_accno}; - if ($form->{item} ne 'service') { + if ($form->{item} =~ /(part|assembly)/) { # get makes if ($form->{makemodel}) { - $query = qq|SELECT name FROM makemodel + $query = qq|SELECT make, model + FROM makemodel WHERE parts_id = $form->{id}|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - my $i = 1; - while (($form->{"make_$i"}, $form->{"model_$i"}) = split(/:/, $sth->fetchrow_array)) { - $i++; + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{makemodels} }, $ref; } $sth->finish; - $form->{makemodel_rows} = $i - 1; - } } @@ -135,11 +138,11 @@ sub get_part { $query = qq|SELECT parts_id FROM invoice WHERE parts_id = $form->{id} - UNION + UNION SELECT parts_id FROM orderitems WHERE parts_id = $form->{id} - UNION + UNION SELECT parts_id FROM assembly WHERE parts_id = $form->{id}|; @@ -149,13 +152,51 @@ sub get_part { ($form->{orphaned}) = $sth->fetchrow_array; $form->{orphaned} = !$form->{orphaned}; $sth->finish; - + + + if ($form->{item} =~ /(part|service)/) { + # get vendors + $query = qq|SELECT v.id, v.name, pv.partnumber, + pv.lastcost, pv.leadtime, pv.curr AS vendorcurr + FROM partsvendor pv + JOIN vendor v ON (v.id = pv.vendor_id) + WHERE pv.parts_id = $form->{id} + ORDER BY 2|; + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{vendormatrix} }, $ref; + } + $sth->finish; + } + + # get matrix + if ($form->{item} ne 'labor') { + $query = qq|SELECT pc.pricebreak, pc.sellprice AS customerprice, + pc.curr AS customercurr, + pc.validfrom, pc.validto, + c.name, c.id AS cid, g.pricegroup, g.id AS gid + FROM partscustomer pc + LEFT JOIN customer c ON (c.id = pc.customer_id) + LEFT JOIN pricegroup g ON (g.id = pc.pricegroup_id) + WHERE pc.parts_id = $form->{id} + ORDER BY c.name, g.pricegroup, pc.pricebreak|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{customermatrix} }, $ref; + } + $sth->finish; + } + $dbh->disconnect; } - sub save { my ($self, $myconfig, $form) = @_; @@ -175,50 +216,55 @@ sub save { # if there is a $form->{id} then replace the old entry # delete all makemodel entries and add the new ones - # escape ' - map { $form->{$_} =~ s/'/''/g } qw(partnumber description notes unit bin); - # undo amount formatting map { $form->{$_} = $form->parse_amount($myconfig, $form->{$_}) } qw(rop weight listprice sellprice lastcost stock); - # set date to NULL if nothing entered - $form->{priceupdate} = ($form->{priceupdate}) ? qq|'$form->{priceupdate}'| : "NULL"; + $form->{lastcost} = $form->{sellprice} if $form->{item} eq 'labor'; $form->{makemodel} = (($form->{make_1}) || ($form->{model_1})) ? 1 : 0; - $form->{alternate} = 0; $form->{assembly} = ($form->{item} eq 'assembly') ? 1 : 0; - $form->{obsolete} *= 1; - $form->{onhand} *= 1; - - my ($query, $sth); + map { $form->{$_} *= 1 } qw(alternate obsolete onhand); + + my $query; + my $sth; + my $i; + my $null; + my $vendor_id; + my $customer_id; if ($form->{id}) { # get old price - $query = qq|SELECT sellprice, weight + $query = qq|SELECT listprice, sellprice, lastcost, weight FROM parts WHERE id = $form->{id}|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - my ($sellprice, $weight) = $sth->fetchrow_array; + my ($listprice, $sellprice, $lastcost, $weight) = $sth->fetchrow_array; $sth->finish; # if item is part of an assembly adjust all assemblies - $query = qq|SELECT id, qty + $query = qq|SELECT id, qty, adj FROM assembly WHERE parts_id = $form->{id}|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my ($id, $qty) = $sth->fetchrow_array) { - &update_assembly($dbh, $form, $id, $qty * 1, $sellprice * 1, $weight * 1); + while (my ($id, $qty, $adj) = $sth->fetchrow_array) { + &update_assembly($dbh, $form, $id, $qty, $adj, $listprice * 1, $sellprice * 1, $lastcost * 1, $weight * 1); } $sth->finish; - - if ($form->{item} ne 'service') { + if ($form->{item} =~ /(part|service)/) { + # delete partsvendor records + $query = qq|DELETE FROM partsvendor + WHERE parts_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + } + + if ($form->{item} !~ /(service|labor)/) { # delete makemodel records $query = qq|DELETE FROM makemodel WHERE parts_id = $form->{id}|; @@ -236,20 +282,21 @@ sub save { WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); } else { - # update BOM only + # update BOM, A only $query = qq|UPDATE assembly - SET bom = ? + SET bom = ?, adj = ? WHERE id = ? AND parts_id = ?|; - $sth = $dbh->prepare($query); - + $sth = $dbh->prepare($query); + for $i (1 .. $form->{assembly_rows} - 1) { - $sth->execute(($form->{"bom_$i"}) ? '1' : '0', $form->{id}, $form->{"id_$i"}) || $form->dberror($query); + $sth->execute(($form->{"bom_$i"}) ? '1' : '0', ($form->{"adj_$i"}) ? '1' : '0', $form->{id}, $form->{"id_$i"}); + $sth->finish; } - $sth->finish; } - + $form->{onhand} += $form->{stock}; + } # delete tax records @@ -257,6 +304,11 @@ sub save { WHERE parts_id = $form->{id}|; $dbh->do($query) || $form->dberror($query); + # delete matrix + $query = qq|DELETE FROM partscustomer + WHERE parts_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + } else { my $uid = time; $uid .= $form->{login}; @@ -277,37 +329,16 @@ sub save { $form->{onhand} = ($form->{stock} * 1) if $form->{item} eq 'assembly'; } - - my $partsgroup_id = 0; - if ($form->{partsgroup}) { - my $partsgroup = lc $form->{partsgroup}; - $query = qq|SELECT DISTINCT id FROM partsgroup - WHERE lower(partsgroup) = '$partsgroup'|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - ($partsgroup_id) = $sth->fetchrow_array; - $sth->finish; - - if (!$partsgroup_id) { - $query = qq|INSERT INTO partsgroup (partsgroup) - VALUES ('$form->{partsgroup}')|; - $dbh->do($query) || $form->dberror($query); + my $partsgroup_id; + ($null, $partsgroup_id) = split /--/, $form->{partsgroup}; + $partsgroup_id *= 1; - $query = qq|SELECT id FROM partsgroup - WHERE partsgroup = '$form->{partsgroup}'|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); + $form->{partnumber} = $form->update_defaults($myconfig, "partnumber", $dbh) if ! $form->{partnumber}; - ($partsgroup_id) = $sth->fetchrow_array; - $sth->finish; - } - } - - - $query = qq|UPDATE parts SET - partnumber = '$form->{partnumber}', - description = '$form->{description}', + $query = qq|UPDATE parts SET + partnumber = |.$dbh->quote($form->{partnumber}).qq|, + description = |.$dbh->quote($form->{description}).qq|, makemodel = '$form->{makemodel}', alternate = '$form->{alternate}', assembly = '$form->{assembly}', @@ -315,11 +346,11 @@ sub save { sellprice = $form->{sellprice}, lastcost = $form->{lastcost}, weight = $form->{weight}, - priceupdate = $form->{priceupdate}, - unit = '$form->{unit}', - notes = '$form->{notes}', + priceupdate = |.$form->dbquote($form->{priceupdate}, SQL_DATE).qq|, + unit = |.$dbh->quote($form->{unit}).qq|, + notes = |.$dbh->quote($form->{notes}).qq|, rop = $form->{rop}, - bin = '$form->{bin}', + bin = |.$dbh->quote($form->{bin}).qq|, inventory_accno_id = (SELECT id FROM chart WHERE accno = '$form->{inventory_accno}'), income_accno_id = (SELECT id FROM chart @@ -336,15 +367,13 @@ sub save { # insert makemodel records - unless ($form->{item} eq 'service') { - for my $i (1 .. $form->{makemodel_rows}) { - # put make and model together + if ($form->{item} =~ /(part|assembly)/) { + for $i (1 .. $form->{makemodel_rows}) { if (($form->{"make_$i"}) || ($form->{"model_$i"})) { - map { $form->{"${_}_$i"} =~ s/'/''/g } qw(make model); - - $query = qq|INSERT INTO makemodel (parts_id, name) - VALUES ($form->{id}, - '$form->{"make_$i"}:$form->{"model_$i"}')|; + $query = qq|INSERT INTO makemodel (parts_id, make, model) + VALUES ($form->{id},| + .$dbh->quote($form->{"make_$i"}).qq|, | + .$dbh->quote($form->{"model_$i"}).qq|)|; $dbh->do($query) || $form->dberror($query); } } @@ -367,27 +396,88 @@ sub save { if ($form->{item} eq 'assembly') { if ($form->{orphaned}) { - for my $i (1 .. $form->{assembly_rows}) { + for $i (1 .. $form->{assembly_rows}) { $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}); if ($form->{"qty_$i"} != 0) { - $form->{"bom_$i"} *= 1; - $query = qq|INSERT INTO assembly (id, parts_id, qty, bom) + map { $form->{"${_}_$i"} *= 1 } qw(bom adj); + $query = qq|INSERT INTO assembly (id, parts_id, qty, bom, adj) VALUES ($form->{id}, $form->{"id_$i"}, - $form->{"qty_$i"}, '$form->{"bom_$i"}')|; + $form->{"qty_$i"}, '$form->{"bom_$i"}', + '$form->{"adj_$i"}')|; $dbh->do($query) || $form->dberror($query); } } } - # adjust onhand for the assembly + # adjust onhand for the parts if ($form->{onhand} != 0) { &adjust_inventory($dbh, $form, $form->{id}, $form->{onhand}); } + + @a = localtime; $a[5] += 1900; $a[4]++; + my $shippingdate = "$a[5]-$a[4]-$a[3]"; + ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh); + + # add inventory record + if ($form->{stock} != 0) { + $query = qq|INSERT INTO inventory (warehouse_id, parts_id, qty, + shippingdate, employee_id) VALUES ( + 0, $form->{id}, $form->{stock}, '$shippingdate', + $form->{employee_id})|; + $dbh->do($query) || $form->dberror($query); + } + + } + + + # add vendors + if ($form->{item} ne 'assembly') { + for $i (1 .. $form->{vendor_rows}) { + if ($form->{"vendor_$i"} && $form->{"lastcost_$i"}) { + + ($null, $vendor_id) = split /--/, $form->{"vendor_$i"}; + + map { $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"})} qw(lastcost leadtime); + + $query = qq|INSERT INTO partsvendor (vendor_id, parts_id, partnumber, + lastcost, leadtime, curr) + VALUES ($vendor_id, $form->{id},| + .$dbh->quote($form->{"partnumber_$i"}).qq|, + $form->{"lastcost_$i"}, + $form->{"leadtime_$i"}, '$form->{"vendorcurr_$i"}')|; + $dbh->do($query) || $form->dberror($query); + } + } + } + + + # add pricematrix + for $i (1 .. $form->{customer_rows}) { + + map { $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"})} qw(pricebreak customerprice); + + if ($form->{"customerprice_$i"}) { + + ($null, $customer_id) = split /--/, $form->{"customer_$i"}; + $customer_id *= 1; + + ($null, $pricegroup_id) = split /--/, $form->{"pricegroup_$i"}; + $pricegroup_id *= 1; + + $query = qq|INSERT INTO partscustomer (parts_id, customer_id, + pricegroup_id, pricebreak, sellprice, curr, + validfrom, validto) + VALUES ($form->{id}, $customer_id, + $pricegroup_id, $form->{"pricebreak_$i"}, + $form->{"customerprice_$i"}, '$form->{"customercurr_$i"}',| + .$form->dbquote($form->{"validfrom_$i"}, SQL_DATE).qq|, | + .$form->dbquote($form->{"validto_$i"}, SQL_DATE).qq|)|; + $dbh->do($query) || $form->dberror($query); + } } - # commit my $rc = $dbh->commit; $dbh->disconnect; @@ -399,27 +489,43 @@ sub save { sub update_assembly { - my ($dbh, $form, $id, $qty, $sellprice, $weight) = @_; + my ($dbh, $form, $id, $qty, $adj, $listprice, $sellprice, $lastcost, $weight) = @_; - my $query = qq|SELECT id, qty + my $formlistprice = $form->{listprice}; + my $formsellprice = $form->{sellprice}; + + if (!$adj) { + $formlistprice = $listprice; + $formsellprice = $sellprice; + } + + my $query = qq|SELECT id, qty, adj FROM assembly - WHERE parts_id = $id|; + WHERE parts_id = $id|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my ($pid, $aqty) = $sth->fetchrow_array) { - &update_assembly($dbh, $form, $pid, $aqty * $qty, $sellprice, $weight); + $form->{$id} = 1; + + while (my ($pid, $aqty, $aadj) = $sth->fetchrow_array) { + &update_assembly($dbh, $form, $pid, $aqty * $qty, $aadj, $listprice, $sellprice, $lastcost, $weight) if !$form->{$pid}; } $sth->finish; $query = qq|UPDATE parts - SET sellprice = sellprice + - $qty * ($form->{sellprice} - $sellprice), + SET listprice = listprice + + $qty * ($formlistprice - $listprice), + sellprice = sellprice + + $qty * ($formsellprice - $sellprice), + lastcost = lastcost + + $qty * ($form->{lastcost} - $lastcost), weight = weight + $qty * ($form->{weight} - $weight) WHERE id = $id|; $dbh->do($query) || $form->dberror($query); + delete $form->{$id}; + } @@ -443,6 +549,15 @@ sub retrieve_assemblies { } $where .= " AND NOT p.obsolete = '1'"; + my %ordinal = ( 'partnumber' => 2, + 'description' => 3, + 'bin' => 4 + ); + + my @a = qw(partnumber description bin); + my $sortorder = $form->sort_order(\@a, \%ordinal); + + # retrieve assembly items my $query = qq|SELECT p.id, p.partnumber, p.description, p.bin, p.onhand, p.rop, @@ -452,13 +567,58 @@ sub retrieve_assemblies { AND a.id = p.id) AS inventory FROM parts p WHERE $where - AND assembly = '1'|; + AND assembly = '1' + ORDER BY $sortorder|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { - push @{ $form->{assembly_items} }, $ref if $ref->{inventory}; + my $inh; + if ($form->{checkinventory}) { + $query = qq|SELECT p.id, p.onhand, a.qty FROM parts p + JOIN assembly a ON (a.parts_id = p.id) + WHERE a.id = ?|; + $inh = $dbh->prepare($query) || $form->dberror($query); + } + + my $onhand = (); + my $ref; + my $aref; + my $stock; + my $howmany; + my $ok; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + if ($ref->{inventory}) { + $ok = 1; + if ($form->{checkinventory}) { + $inh->execute($ref->{id}) || $form->dberror($query);; + $ok = 0; + while ($aref = $inh->fetchrow_hashref(NAME_lc)) { + $onhand{$aref->{id}} = (exists $onhand{$aref->{id}}) ? $onhand{$aref->{id}} : $aref->{onhand}; + + if ($aref->{onhand} >= $aref->{qty}) { + + $howmany = ($aref->{qty}) ? $aref->{onhand}/$aref->{qty} : 1; + if ($stock) { + $stock = ($stock > $howmany) ? $howmany : $stock; + } else { + $stock = $howmany; + } + $ok = 1; + + $onhand{$aref->{id}} -= ($aref->{qty} * $stock); + + } else { + $ok = 0; + last; + } + } + $inh->finish; + $ref->{stock} = (($ref->{rop} - $ref->{qty}) > $stock) ? int $stock : $ref->{rop}; + } + push @{ $form->{assembly_items} }, $ref if $ok; + } } $sth->finish; @@ -472,6 +632,11 @@ sub restock_assemblies { # connect to database my $dbh = $form->dbconnect_noauto($myconfig); + + @a = localtime; $a[5] += 1900; $a[4]++; + my $shippingdate = "$a[5]-$a[4]-$a[3]"; + + ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh); for my $i (1 .. $form->{rowcount}) { @@ -480,9 +645,18 @@ sub restock_assemblies { if ($form->{"qty_$i"} != 0) { &adjust_inventory($dbh, $form, $form->{"id_$i"}, $form->{"qty_$i"}); } + + # add inventory record + if ($form->{"qty_$i"} != 0) { + $query = qq|INSERT INTO inventory (warehouse_id, parts_id, qty, + shippingdate, employee_id) VALUES ( + 0, $form->{"id_$i"}, $form->{"qty_$i"}, '$shippingdate', + $form->{employee_id})|; + $dbh->do($query) || $form->dberror($query); + } } - + my $rc = $dbh->commit; $dbh->disconnect; @@ -495,9 +669,9 @@ sub adjust_inventory { my ($dbh, $form, $id, $qty) = @_; my $query = qq|SELECT p.id, p.inventory_accno_id, p.assembly, a.qty - FROM parts p - JOIN assembly a ON (a.parts_id = p.id) - WHERE a.id = $id|; + FROM parts p, assembly a + WHERE a.parts_id = p.id + AND a.id = $id|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -505,9 +679,10 @@ sub adjust_inventory { my $allocate = $qty * $ref->{qty}; - # is it a service item, then loop - $ref->{inventory_accno_id} *= 1; - next if (($ref->{inventory_accno_id} == 0) && !$ref->{assembly}); + # is it a service item then loop + if (($ref->{inventory_accno_id} *= 1) == 0) { + next unless $ref->{assembly}; # assembly + } # adjust parts onhand $form->update_balance($dbh, @@ -525,7 +700,7 @@ sub adjust_inventory { "onhand", qq|id = $id|, $qty); - + } @@ -534,11 +709,6 @@ sub delete { # connect to database, turn off AutoCommit my $dbh = $form->dbconnect_noauto($myconfig); - - if ($form->{item} eq 'assembly' && $form->{onhand} != 0) { - # adjust onhand for the assembly - &adjust_inventory($dbh, $form, $form->{id}, $form->{onhand} * -1); - } my $query = qq|DELETE FROM parts WHERE id = $form->{id}|; @@ -548,14 +718,26 @@ sub delete { WHERE parts_id = $form->{id}|; $dbh->do($query) || $form->dberror($query); + + if ($form->{item} ne 'assembly') { + $query = qq|DELETE FROM partsvendor + WHERE parts_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + } + # check if it is a part, assembly or service - if ($form->{item} eq 'part') { + if ($form->{item} ne 'service') { $query = qq|DELETE FROM makemodel WHERE parts_id = $form->{id}|; $dbh->do($query) || $form->dberror($query); } if ($form->{item} eq 'assembly') { + # delete inventory + $query = qq|DELETE FROM inventory + WHERE parts_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + $query = qq|DELETE FROM assembly WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); @@ -566,6 +748,14 @@ sub delete { WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); } + + $query = qq|DELETE FROM partscustomer + WHERE parts_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $query = qq|DELETE FROM translation + WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); # commit my $rc = $dbh->commit; @@ -581,7 +771,8 @@ sub assembly_item { my $i = $form->{assembly_rows}; my $var; - my $where = "1 = 1"; + my $null; + my $where = "p.obsolete = '0'"; if ($form->{"partnumber_$i"}) { $var = $form->like(lc $form->{"partnumber_$i"}); @@ -592,12 +783,12 @@ sub assembly_item { $where .= " AND lower(p.description) LIKE '$var'"; } if ($form->{"partsgroup_$i"}) { - $var = $form->like(lc $form->{"partsgroup_$i"}); - $where .= " AND lower(pg.partsgroup) LIKE '$var'"; + ($null, $var) = split /--/, $form->{"partsgroup_$i"}; + $where .= qq| AND p.partsgroup_id = $var|; } - + if ($form->{id}) { - $where .= " AND NOT p.id = $form->{id}"; + $where .= " AND p.id != $form->{id}"; } if ($partnumber) { @@ -610,8 +801,8 @@ sub assembly_item { my $dbh = $form->dbconnect($myconfig); my $query = qq|SELECT p.id, p.partnumber, p.description, p.sellprice, - p.weight, p.onhand, p.unit, - pg.partsgroup + p.weight, p.onhand, p.unit, p.lastcost, + pg.partsgroup, p.partsgroup_id FROM parts p LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) WHERE $where|; @@ -632,9 +823,12 @@ sub all_parts { my ($self, $myconfig, $form) = @_; my $where = '1 = 1'; + my $null; my $var; + my $ref; + my $item; - foreach my $item (qw(partnumber drawing microfiche)) { + foreach $item (qw(partnumber drawing microfiche)) { if ($form->{$item}) { $var = $form->like(lc $form->{$item}); $where .= " AND lower(p.$item) LIKE '$var'"; @@ -642,32 +836,46 @@ sub all_parts { } # special case for description if ($form->{description}) { - unless ($form->{bought} || $form->{sold} || $form->{onorder} || $form->{ordered}) { + unless ($form->{bought} || $form->{sold} || $form->{onorder} || $form->{ordered} || $form->{rfq} || $form->{quoted}) { $var = $form->like(lc $form->{description}); $where .= " AND lower(p.description) LIKE '$var'"; } } + + # assembly components + my $assemblyflds; + if ($form->{searchitems} eq 'component') { + $assemblyflds = qq|, p1.partnumber AS assemblypartnumber, a.id AS assembly_id|; + } + + # special case for serialnumber + if ($form->{l_serialnumber}) { + if ($form->{serialnumber}) { + $var = $form->like(lc $form->{serialnumber}); + $where .= " AND lower(i.serialnumber) LIKE '$var'"; + } + } + if ($form->{warehouse} || $form->{l_warehouse}) { + $form->{l_warehouse} = 1; + } + if ($form->{searchitems} eq 'part') { - $where .= " AND p.inventory_accno_id > 0"; + $where .= " AND p.inventory_accno_id > 0 AND p.assembly = '0' AND p.income_accno_id > 0"; } if ($form->{searchitems} eq 'assembly') { $form->{bought} = ""; $where .= " AND p.assembly = '1'"; } if ($form->{searchitems} eq 'service') { - $where .= " AND p.inventory_accno_id IS NULL AND NOT p.assembly = '1'"; - # irrelevant for services - $form->{make} = $form->{model} = ""; + $where .= " AND p.inventory_accno_id IS NULL AND p.assembly = '0'"; + } + if ($form->{searchitems} eq 'labor') { + $where .= " AND p.inventory_accno_id > 0 AND p.income_accno_id IS NULL"; } # items which were never bought, sold or on an order if ($form->{itemstatus} eq 'orphaned') { - $form->{onhand} = $form->{short} = 0; - $form->{bought} = $form->{sold} = 0; - $form->{onorder} = $form->{ordered} = 0; - $form->{transdatefrom} = $form->{transdateto} = ""; - $where .= " AND p.onhand = 0 AND p.id NOT IN (SELECT p.id FROM parts p, invoice i WHERE p.id = i.parts_id) @@ -682,80 +890,174 @@ sub all_parts { } if ($form->{itemstatus} eq 'obsolete') { $where .= " AND p.obsolete = '1'"; - $form->{onhand} = $form->{short} = 0; } if ($form->{itemstatus} eq 'onhand') { $where .= " AND p.onhand > 0"; } if ($form->{itemstatus} eq 'short') { - $where .= " AND p.onhand < 0"; + $where .= " AND p.onhand < p.rop"; } - if ($form->{make}) { - $var = $form->like(lc $form->{make}).":%"; - $where .= " AND p.id IN (SELECT DISTINCT ON (m.parts_id) m.parts_id - FROM makemodel m WHERE lower(m.name) LIKE '$var')"; - } - if ($form->{model}) { - $var = "%:".$form->like($form->{model}); - $where .= " AND p.id IN (SELECT DISTINCT ON (m.parts_id) m.parts_id - FROM makemodel m WHERE lower(m.name) LIKE '$var')"; + my $makemodelflds = qq|, '', ''|;; + my $makemodeljoin; + + if ($form->{make} || $form->{l_make} || $form->{model} || $form->{l_model}) { + $makemodelflds = qq|, m.make, m.model|; + $makemodeljoin = qq|LEFT JOIN makemodel m ON (m.parts_id = p.id)|; + + if ($form->{make}) { + $var = $form->like(lc $form->{make}); + $where .= " AND lower(m.make) LIKE '$var'"; + } + if ($form->{model}) { + $var = $form->like(lc $form->{model}); + $where .= " AND lower(m.model) LIKE '$var'"; + } } if ($form->{partsgroup}) { - $var = $form->like(lc $form->{partsgroup}); - $where .= " AND lower(pg.partsgroup) LIKE '$var'"; - + ($null, $var) = split /--/, $form->{partsgroup}; + $where .= qq| AND p.partsgroup_id = $var|; } # connect to database my $dbh = $form->dbconnect($myconfig); + my %ordinal = ( 'partnumber' => 2, + 'description' => 3, + 'bin' => 6, + 'priceupdate' => 12, + 'drawing' => 14, + 'microfiche' => 15, + 'partsgroup' => 17, + 'make' => 19, + 'model' => 20, + 'assemblypartnumber' => 21 + ); - my $sortorder = join ', ', $form->sort_columns(qw(partnumber description bin priceupdate partsgroup)); - $sortorder = $form->{sort} unless $sortorder; + my @a = qw(partnumber description); + my $sortorder = $form->sort_order(\@a, \%ordinal); + + my $query = qq|SELECT curr FROM defaults|; + my ($curr) = $dbh->selectrow_array($query); + $curr =~ s/:.*//; + + my $flds = qq|p.id, p.partnumber, p.description, p.onhand, p.unit, + p.bin, p.sellprice, p.listprice, p.lastcost, p.rop, + p.weight, p.priceupdate, p.image, p.drawing, p.microfiche, + p.assembly, pg.partsgroup, '$curr' AS curr + $makemodelflds $assemblyflds + |; + + $query = qq|SELECT $flds + FROM parts p + LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + $makemodeljoin + WHERE $where + ORDER BY $sortorder|; + + # redo query for components report + if ($form->{searchitems} eq 'component') { + + $query = qq|SELECT $flds + FROM assembly a + JOIN parts p ON (a.parts_id = p.id) + JOIN parts p1 ON (a.id = p1.id) + LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + $makemodeljoin + WHERE $where + ORDER BY $sortorder|; + + } - my $query = qq|SELECT p.id, p.partnumber, p.description, p.onhand, p.unit, - p.bin, p.sellprice, p.listprice, p.lastcost, p.rop, p.weight, - p.priceupdate, p.image, p.drawing, p.microfiche, - pg.partsgroup - FROM parts p - LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) - WHERE $where - ORDER BY $sortorder|; # rebuild query for bought and sold items - if ($form->{bought} || $form->{sold} || $form->{onorder} || $form->{ordered}) { + if ($form->{bought} || $form->{sold} || $form->{onorder} || $form->{ordered} || $form->{rfq} || $form->{quoted}) { + + $form->sort_order(); + my @a = qw(partnumber description employee); + + push @a, qw(invnumber serialnumber) if ($form->{bought} || $form->{sold}); + push @a, "ordnumber" if ($form->{onorder} || $form->{ordered}); + push @a, "quonumber" if ($form->{rfq} || $form->{quoted}); + + %ordinal = ( 'partnumber' => 2, + 'description' => 3, + 'serialnumber' => 4, + 'bin' => 7, + 'priceupdate' => 13, + 'partsgroup' => 18, + 'invnumber' => 19, + 'ordnumber' => 20, + 'quonumber' => 21, + 'name' => 23, + 'employee' => 24, + 'make' => 27, + 'model' => 28 + ); + $sortorder = $form->sort_order(\@a, \%ordinal); + my $union = ""; $query = ""; if ($form->{bought} || $form->{sold}) { my $invwhere = "$where"; + my $transdate = ($form->{method} eq 'accrual') ? "transdate" : "datepaid"; + $invwhere .= " AND i.assemblyitem = '0'"; - $invwhere .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; - $invwhere .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + $invwhere .= " AND a.$transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $invwhere .= " AND a.$transdate <= '$form->{transdateto}'" if $form->{transdateto}; if ($form->{description}) { $var = $form->like(lc $form->{description}); $invwhere .= " AND lower(i.description) LIKE '$var'"; } - my $flds = qq|p.id, p.partnumber, i.description, + if ($form->{open} || $form->{closed}) { + if ($form->{open} && $form->{closed}) { + if ($form->{method} eq 'cash') { + $invwhere .= " AND a.amount = a.paid"; + } + } else { + if ($form->{open}) { + if ($form->{method} eq 'cash') { + $invwhere .= " AND a.id = 0"; + } else { + $invwhere .= " AND NOT a.amount = a.paid"; + } + } else { + $invwhere .= " AND a.amount = a.paid"; + } + } + } else { + $invwhere .= " AND a.id = 0"; + } + + my $flds = qq|p.id, p.partnumber, i.description, i.serialnumber, i.qty AS onhand, i.unit, p.bin, i.sellprice, p.listprice, p.lastcost, p.rop, p.weight, p.priceupdate, p.image, p.drawing, p.microfiche, - pg.partsgroup, - a.invnumber, a.ordnumber, i.trans_id|; + p.assembly, + pg.partsgroup, a.invnumber, a.ordnumber, a.quonumber, + i.trans_id, ct.name, e.name AS employee, a.curr, a.till + $makemodelfld|; + if ($form->{bought}) { $query = qq| SELECT $flds, 'ir' AS module, '' AS type, - 1 AS exchangerate - FROM parts p - JOIN invoice i ON (i.parts_id = p.id) - JOIN ap a ON (i.trans_id = a.id) - LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + (SELECT sell FROM exchangerate ex + WHERE ex.curr = a.curr + AND ex.transdate = a.$transdate) AS exchangerate, + i.discount + FROM invoice i + JOIN parts p ON (p.id = i.parts_id) + JOIN ap a ON (a.id = i.trans_id) + JOIN vendor ct ON (a.vendor_id = ct.id) + LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + LEFT JOIN employee e ON (a.employee_id = e.id) + $makemodeljoin WHERE $invwhere|; $union = " UNION"; @@ -764,11 +1066,17 @@ sub all_parts { if ($form->{sold}) { $query .= qq|$union SELECT $flds, 'is' AS module, '' AS type, - 1 As exchangerate - FROM parts p - JOIN invoice i ON (i.parts_id = p.id) - JOIN ar a ON (i.trans_id = a.id) - LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + (SELECT buy FROM exchangerate ex + WHERE ex.curr = a.curr + AND ex.transdate = a.$transdate) AS exchangerate, + i.discount + FROM invoice i + JOIN parts p ON (p.id = i.parts_id) + JOIN ar a ON (a.id = i.trans_id) + JOIN customer ct ON (a.customer_id = ct.id) + LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + LEFT JOIN employee e ON (a.employee_id = e.id) + $makemodeljoin WHERE $invwhere|; $union = " UNION"; @@ -776,59 +1084,158 @@ sub all_parts { } if ($form->{onorder} || $form->{ordered}) { - my $ordwhere = "$where"; - $ordwhere .= " AND o.closed = '0'" unless $form->{closed}; - - $ordwhere .= " AND o.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; - $ordwhere .= " AND o.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + my $ordwhere = "$where + AND a.quotation = '0'"; + $ordwhere .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $ordwhere .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; if ($form->{description}) { $var = $form->like(lc $form->{description}); - $ordwhere .= " AND lower(oi.description) LIKE '$var'"; + $ordwhere .= " AND lower(i.description) LIKE '$var'"; + } + + if ($form->{open} || $form->{closed}) { + unless ($form->{open} && $form->{closed}) { + $ordwhere .= " AND a.closed = '0'" if $form->{open}; + $ordwhere .= " AND a.closed = '1'" if $form->{closed}; + } + } else { + $ordwhere .= " AND a.id = 0"; } - $flds = qq|p.id, p.partnumber, oi.description, - oi.qty AS onhand, oi.unit, p.bin, oi.sellprice, + $flds = qq|p.id, p.partnumber, i.description, '' AS serialnumber, + i.qty AS onhand, i.unit, p.bin, i.sellprice, p.listprice, p.lastcost, p.rop, p.weight, p.priceupdate, p.image, p.drawing, p.microfiche, - pg.partsgroup, - '' AS invnumber, o.ordnumber, oi.trans_id|; + p.assembly, + pg.partsgroup, '' AS invnumber, a.ordnumber, a.quonumber, + i.trans_id, ct.name,e.name AS employee, a.curr, '0' AS till + $makemodelfld|; if ($form->{ordered}) { $query .= qq|$union SELECT $flds, 'oe' AS module, 'sales_order' AS type, (SELECT buy FROM exchangerate ex - WHERE ex.curr = o.curr - AND ex.transdate = o.transdate) AS exchangerate - FROM parts p - JOIN orderitems oi ON (oi.parts_id = p.id) - JOIN oe o ON (oi.trans_id = o.id) - LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + WHERE ex.curr = a.curr + AND ex.transdate = a.transdate) AS exchangerate, + i.discount + FROM orderitems i + JOIN parts p ON (i.parts_id = p.id) + JOIN oe a ON (i.trans_id = a.id) + JOIN customer ct ON (a.customer_id = ct.id) + LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + LEFT JOIN employee e ON (a.employee_id = e.id) + $makemodeljoin WHERE $ordwhere - AND o.customer_id > 0|; + AND a.customer_id > 0|; $union = " UNION"; } if ($form->{onorder}) { - $flds = qq|p.id, p.partnumber, oi.description, - oi.qty * -1 AS onhand, oi.unit, p.bin, oi.sellprice, + $flds = qq|p.id, p.partnumber, i.description, '' AS serialnumber, + i.qty AS onhand, i.unit, p.bin, i.sellprice, p.listprice, p.lastcost, p.rop, p.weight, p.priceupdate, p.image, p.drawing, p.microfiche, - pg.partsgroup, - '' AS invnumber, o.ordnumber, oi.trans_id|; + p.assembly, + pg.partsgroup, '' AS invnumber, a.ordnumber, a.quonumber, + i.trans_id, ct.name,e.name AS employee, a.curr, '0' AS till + $makemodelfld|; $query .= qq|$union SELECT $flds, 'oe' AS module, 'purchase_order' AS type, (SELECT sell FROM exchangerate ex - WHERE ex.curr = o.curr - AND ex.transdate = o.transdate) AS exchangerate - FROM parts p - JOIN orderitems oi ON (oi.parts_id = p.id) - JOIN oe o ON (oi.trans_id = o.id) - LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + WHERE ex.curr = a.curr + AND ex.transdate = a.transdate) AS exchangerate, + i.discount + FROM orderitems i + JOIN parts p ON (i.parts_id = p.id) + JOIN oe a ON (i.trans_id = a.id) + JOIN vendor ct ON (a.vendor_id = ct.id) + LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + LEFT JOIN employee e ON (a.employee_id = e.id) + $makemodeljoin WHERE $ordwhere - AND o.vendor_id > 0|; + AND a.vendor_id > 0|; + } + + } + + if ($form->{rfq} || $form->{quoted}) { + my $quowhere = "$where + AND a.quotation = '1'"; + $quowhere .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; + $quowhere .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto}; + + if ($form->{description}) { + $var = $form->like(lc $form->{description}); + $quowhere .= " AND lower(i.description) LIKE '$var'"; + } + + if ($form->{open} || $form->{closed}) { + unless ($form->{open} && $form->{closed}) { + $ordwhere .= " AND a.closed = '0'" if $form->{open}; + $ordwhere .= " AND a.closed = '1'" if $form->{closed}; + } + } else { + $ordwhere .= " AND a.id = 0"; + } + + + $flds = qq|p.id, p.partnumber, i.description, '' AS serialnumber, + i.qty AS onhand, i.unit, p.bin, i.sellprice, + p.listprice, p.lastcost, p.rop, p.weight, + p.priceupdate, p.image, p.drawing, p.microfiche, + p.assembly, + pg.partsgroup, '' AS invnumber, a.ordnumber, a.quonumber, + i.trans_id, ct.name, e.name AS employee, a.curr, '0' AS till + $makemodelfld|; + + if ($form->{quoted}) { + $query .= qq|$union + SELECT $flds, 'oe' AS module, 'sales_quotation' AS type, + (SELECT buy FROM exchangerate ex + WHERE ex.curr = a.curr + AND ex.transdate = a.transdate) AS exchangerate, + i.discount + FROM orderitems i + JOIN parts p ON (i.parts_id = p.id) + JOIN oe a ON (i.trans_id = a.id) + JOIN customer ct ON (a.customer_id = ct.id) + LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + LEFT JOIN employee e ON (a.employee_id = e.id) + $makemodeljoin + WHERE $quowhere + AND a.customer_id > 0|; + $union = " + UNION"; + } + + if ($form->{rfq}) { + $flds = qq|p.id, p.partnumber, i.description, '' AS serialnumber, + i.qty AS onhand, i.unit, p.bin, i.sellprice, + p.listprice, p.lastcost, p.rop, p.weight, + p.priceupdate, p.image, p.drawing, p.microfiche, + p.assembly, + pg.partsgroup, '' AS invnumber, a.ordnumber, a.quonumber, + i.trans_id, ct.name, e.name AS employee, a.curr, '0' AS till + $makemodelfld|; + + $query .= qq|$union + SELECT $flds, 'oe' AS module, 'request_quotation' AS type, + (SELECT sell FROM exchangerate ex + WHERE ex.curr = a.curr + AND ex.transdate = a.transdate) AS exchangerate, + i.discount + FROM orderitems i + JOIN parts p ON (i.parts_id = p.id) + JOIN oe a ON (i.trans_id = a.id) + JOIN vendor ct ON (a.vendor_id = ct.id) + LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + LEFT JOIN employee e ON (a.employee_id = e.id) + $makemodeljoin + WHERE $quowhere + AND a.vendor_id > 0|; } } @@ -838,45 +1245,99 @@ sub all_parts { } + my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { push @{ $form->{parts} }, $ref; } - $sth->finish; - - # include individual items for assemblies + my @a = (); + + # include individual items for assembly if ($form->{searchitems} eq 'assembly' && $form->{bom}) { + + if ($form->{sold} || $form->{ordered} || $form->{quoted}) { + $flds = qq|p.id, p.partnumber, p.description, a.qty AS onhand, p.unit, + p.bin, p.sellprice, p.listprice, p.lastcost, p.rop, + p.weight, p.priceupdate, p.image, p.drawing, p.microfiche, + p.assembly, pg.partsgroup + $makemodelflds $assemblyflds + |; + } else { + # replace p.onhand with a.qty AS onhand + $flds =~ s/p.onhand/a.qty AS onhand/; + } + + while ($item = shift @{ $form->{parts} }) { + push @a, $item; + $flds =~ s/a\.qty.*AS onhand/a\.qty * $item->{onhand} AS onhand/; + push @a, &include_assembly($dbh, $form, $item->{id}, $flds, $makemodeljoin); + push @a, {id => $item->{id}}; + } + + # copy assemblies to $form->{parts} + @{ $form->{parts} } = @a; + + } + + + @a = (); + if ($form->{l_warehouse} || $form->{l_warehouse}) { + + if ($form->{warehouse}) { + ($null, $var) = split /--/, $form->{warehouse}; + $var *= 1; + $query = qq|SELECT SUM(qty) AS onhand, '$null' AS description + FROM inventory + WHERE warehouse_id = $var + AND parts_id = ?|; + } else { + + $query = qq|SELECT SUM(i.qty) AS onhand, w.description AS warehouse + FROM inventory i + JOIN warehouse w ON (w.id = i.warehouse_id) + WHERE i.parts_id = ? + GROUP BY w.description|; + } + + $sth = $dbh->prepare($query) || $form->dberror($query); + foreach $item (@{ $form->{parts} }) { - push @assemblies, $item; - $query = qq|SELECT p.id, p.partnumber, p.description, a.qty AS onhand, - p.unit, p.bin, - p.sellprice, p.listprice, p.lastcost, - p.rop, p.weight, p.priceupdate, - p.image, p.drawing, p.microfiche - FROM parts p - JOIN assembly a ON (p.id = a.parts_id) - WHERE a.id = $item->{id}|; - - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { - $ref->{assemblyitem} = 1; - push @assemblies, $ref; + if ($item->{onhand} <= 0 && ! $form->{warehouse}) { + push @a, $item; + next; } - $sth->finish; - push @assemblies, {id => $item->{id}}; + $sth->execute($item->{id}) || $form->dberror($query); + + if ($form->{warehouse}) { + + $ref = $sth->fetchrow_hashref(NAME_lc); + if ($ref->{onhand} > 0) { + $item->{onhand} = $ref->{onhand}; + push @a, $item; + } + } else { + + push @a, $item; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + if ($ref->{onhand} > 0) { + push @a, $ref; + } + } + } + + $sth->finish; } - # copy assemblies to $form->{parts} - @{ $form->{parts} } = @assemblies; - + @{ $form->{parts} } = @a; + } $dbh->disconnect; @@ -884,11 +1345,54 @@ sub all_parts { } +sub include_assembly { + my ($dbh, $form, $id, $flds, $makemodeljoin) = @_; + + $form->{stagger}++; + if ($form->{stagger} > $form->{pncol}) { + $form->{pncol} = $form->{stagger}; + } + + $form->{$id} = 1; + + my @a = (); + my $query = qq|SELECT $flds + FROM parts p + JOIN assembly a ON (a.parts_id = p.id) + LEFT JOIN partsgroup pg ON (pg.id = p.id) + $makemodeljoin + WHERE a.id = $id|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + $ref->{assemblyitem} = 1; + $ref->{stagger} = $form->{stagger}; + push @a, $ref; + if ($ref->{assembly} && !$form->{$ref->{id}}) { + push @a, &include_assembly($dbh, $form, $ref->{id}, $flds, $makemodeljoin); + if ($form->{stagger} > $form->{pncol}) { + $form->{pncol} = $form->{stagger}; + } + } + } + $sth->finish; + + $form->{$id} = 0; + $form->{stagger}--; + + @a; + +} + + sub create_links { my ($self, $module, $myconfig, $form) = @_; # connect to database my $dbh = $form->dbconnect($myconfig); + + my $ref; my $query = qq|SELECT accno, description, link FROM chart @@ -897,33 +1401,86 @@ sub create_links { my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { - foreach my $key (split(/:/, $ref->{link})) { + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + foreach my $key (split /:/, $ref->{link}) { if ($key =~ /$module/) { push @{ $form->{"${module}_links"}{$key} }, { accno => $ref->{accno}, description => $ref->{description} }; } } } + $sth->finish; + + if ($form->{item} ne 'assembly') { + $query = qq|SELECT count(*) FROM vendor|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + my ($count) = $sth->fetchrow_array; + $sth->finish; + + if ($count < $myconfig->{vclimit}) { + $query = qq|SELECT id, name + FROM vendor + ORDER BY name|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_vendor} }, $ref; + } + $sth->finish; + } + } + + # pricegroups, customers + $query = qq|SELECT count(*) FROM customer|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + my ($count) = $sth->fetchrow_array; $sth->finish; + if ($count < $myconfig->{vclimit}) { + $query = qq|SELECT id, name + FROM customer + ORDER BY name|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_customer} }, $ref; + } + $sth->finish; + } + + $query = qq|SELECT id, pricegroup + FROM pricegroup + ORDER BY pricegroup|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_pricegroup} }, $ref; + } + $sth->finish; + + if ($form->{id}) { - $query = qq|SELECT weightunit + $query = qq|SELECT weightunit, curr AS currencies FROM defaults|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - ($form->{weightunit}) = $sth->fetchrow_array; + ($form->{weightunit}, $form->{currencies}) = $sth->fetchrow_array; $sth->finish; } else { - $query = qq|SELECT weightunit, current_date + $query = qq|SELECT weightunit, current_date, curr AS currencies FROM defaults|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - ($form->{weightunit}, $form->{priceupdate}) = $sth->fetchrow_array; + ($form->{weightunit}, $form->{priceupdate}, $form->{currencies}) = $sth->fetchrow_array; $sth->finish; } @@ -932,5 +1489,25 @@ sub create_links { } +sub get_warehouses { + my ($self, $myconfig, $form) = @_; + + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT id, description + FROM warehouse|; + + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_warehouses} }, $ref; + } + $sth->finish; + + $dbh->disconnect; + +} + 1; diff --git a/sql-ledger/SL/IR.pm b/sql-ledger/SL/IR.pm index 357533e17..79a619be8 100644 --- a/sql-ledger/SL/IR.pm +++ b/sql-ledger/SL/IR.pm @@ -1,12 +1,12 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org # Web: http://www.sql-ledger.org # -# Contributors: +# Contributors: Jim Rawlings # # 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 @@ -35,8 +35,16 @@ sub post_invoice { # connect to database, turn off autocommit my $dbh = $form->dbconnect_noauto($myconfig); - my ($query, $sth, $null, $project_id); + my $query; + my $sth; + my $null; + my $project_id; my $exchangerate = 0; + my $allocated; + my $taxrate; + my $taxamount; + my $taxdiff; + my $item; if ($form->{id}) { @@ -58,10 +66,9 @@ sub post_invoice { ($form->{id}) = $sth->fetchrow_array; $sth->finish; + } - map { $form->{$_} =~ s/'/''/g } qw(invnumber ordnumber); - my ($amount, $linetotal, $lastinventoryaccno, $lastexpenseaccno); my ($netamount, $invoicediff, $expensediff) = (0, 0, 0); @@ -78,21 +85,33 @@ sub post_invoice { $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}); if ($form->{"qty_$i"} != 0) { + + # project + $project_id = 'NULL'; + if ($form->{"projectnumber_$i"}) { + ($null, $project_id) = split /--/, $form->{"projectnumber_$i"}; + } + + # undo discount formatting + $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100; - map { $form->{"${_}_$i"} =~ s/'/''/g } qw(partnumber description unit); - - my ($allocated, $taxrate) = (0, 0); - my $taxamount; + @taxaccounts = split / /, $form->{"taxaccounts_$i"}; + $taxdiff = 0; + $allocated = 0; + $taxrate = 0; - $form->{"sellprice_$i"} = $form->parse_amount($myconfig, $form->{"sellprice_$i"}); - my $fxsellprice = $form->{"sellprice_$i"}; - + # 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; + # deduct discount + my $discount = $form->round_amount($fxsellprice * $form->{"discount_$i"}, $decimalplaces); + $form->{"sellprice_$i"} = $fxsellprice - $discount; - map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{"taxaccounts_$i"}; + map { $taxrate += $form->{"${_}_rate"} } @taxaccounts; if ($form->{"inventory_accno_$i"}) { @@ -106,10 +125,22 @@ sub post_invoice { } $netamount += $linetotal; - - if ($taxamount != 0) { - map { $form->{amount}{$form->{id}}{$_} -= $taxamount * $form->{"${_}_rate"} / $taxrate } split / /, $form->{"taxaccounts_$i"}; + + if (@taxaccounts && $form->round_amount($taxamount, 2) == 0) { + if ($form->{taxincluded}) { + foreach $item (@taxaccounts) { + $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2); + $taxdiff += $taxamount; + $form->{amount}{$form->{id}}{$item} -= $taxamount; + } + $form->{amount}{$form->{id}}{$taxaccounts[0]} += $taxdiff; + } else { + map { $form->{amount}{$form->{id}}{$_} -= $linetotal * $form->{"${_}_rate"} } @taxaccounts; + } + } else { + map { $form->{amount}{$form->{id}}{$_} -= $taxamount * $form->{"${_}_rate"} / $taxrate } @taxaccounts; } + # add purchase to inventory, this one is without the tax! $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate}; @@ -126,11 +157,11 @@ sub post_invoice { # update parts table - $query = qq|UPDATE parts SET - lastcost = $form->{"sellprice_$i"}, - onhand = onhand + $form->{"qty_$i"} - WHERE id = $form->{"id_$i"}|; - $dbh->do($query) || $form->dberror($query); + $form->update_balance($dbh, + "parts", + "onhand", + qq|id = $form->{"id_$i"}|, + $form->{"qty_$i"}) unless $form->{shipped}; # check if we sold the item already and @@ -159,7 +190,7 @@ sub post_invoice { $linetotal = $form->round_amount($form->{"sellprice_$i"} * $qty, 2); - + if ($ref->{allocated} < 0) { # we have an entry for it already, adjust amount $form->update_balance($dbh, @@ -222,9 +253,22 @@ sub post_invoice { $netamount += $linetotal; - if ($taxamount != 0) { - map { $form->{amount}{$form->{id}}{$_} -= $taxamount * $form->{"${_}_rate"} / $taxrate } split / /, $form->{"taxaccounts_$i"}; + if (@taxaccounts && $form->round_amount($taxamount, 2) == 0) { + if ($form->{taxincluded}) { + foreach $item (@taxaccounts) { + $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2); + $totaltax += $taxamount; + $taxdiff += $taxamount; + $form->{amount}{$form->{id}}{$item} -= $taxamount; + } + $form->{amount}{$form->{id}}{$taxaccounts[0]} += $taxdiff; + } else { + map { $form->{amount}{$form->{id}}{$_} -= $linetotal * $form->{"${_}_rate"} } @taxaccounts; + } + } else { + map { $form->{amount}{$form->{id}}{$_} -= $taxamount * $form->{"${_}_rate"} / $taxrate } @taxaccounts; } + $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate}; $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2) * $form->{exchangerate}; @@ -241,38 +285,32 @@ sub post_invoice { # adjust and round sellprice $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate}, $decimalplaces); - # update lastcost - $query = qq|UPDATE parts SET - lastcost = $form->{"sellprice_$i"} - WHERE id = $form->{"id_$i"}|; - $dbh->do($query) || $form->dberror($query); - } - $project_id = 'NULL'; - if ($form->{"project_id_$i"}) { - $project_id = $form->{"project_id_$i"}; - } - $deliverydate = ($form->{"deliverydate_$i"}) ? qq|'$form->{"deliverydate_$i"}'| : "NULL"; - + # save detail record in invoice table $query = qq|INSERT INTO invoice (trans_id, parts_id, description, qty, - sellprice, fxsellprice, allocated, unit, deliverydate) - VALUES ($form->{id}, $form->{"id_$i"}, - '$form->{"description_$i"}', |. ($form->{"qty_$i"} * -1) .qq|, - $form->{"sellprice_$i"}, $fxsellprice, $allocated, - '$form->{"unit_$i"}', $deliverydate)|; + sellprice, fxsellprice, discount, allocated, + unit, deliverydate, project_id, serialnumber) + VALUES ($form->{id}, $form->{"id_$i"}, | + .$dbh->quote($form->{"description_$i"}).qq|, | + .($form->{"qty_$i"} * -1) .qq|, + $form->{"sellprice_$i"}, $fxsellprice, + $form->{"discount_$i"}, $allocated, | + .$dbh->quote($form->{"unit_$i"}).qq|, | + .$form->dbquote($form->{"deliverydate_$i"}, SQL_DATE).qq|, + $project_id, | + .$dbh->quote($form->{"serialnumber_$i"}).qq|)|; $dbh->do($query) || $form->dberror($query); } } - $form->{datepaid} = $form->{invdate}; + $form->{datepaid} = $form->{transdate}; # all amounts are in natural state, netamount includes the taxes # if tax is included, netamount is rounded to 2 decimal places, - # taxes are not # total payments for my $i (1 .. $form->{paidaccounts}) { @@ -292,7 +330,7 @@ sub post_invoice { $paiddiff = $amount - $netamount * $form->{exchangerate}; $netamount = $amount; - foreach my $item (split / /, $form->{taxaccounts}) { + foreach $item (split / /, $form->{taxaccounts}) { $amount = $form->{amount}{$form->{id}}{$item} * $form->{exchangerate}; $form->{amount}{$form->{id}}{$item} = $form->round_amount($amount, 2); $amount = $form->{amount}{$form->{id}}{$item} * -1; @@ -302,7 +340,7 @@ sub post_invoice { $invoicediff += $paiddiff; $expensediff += $paiddiff; - + ######## this only applies to tax included if ($lastinventoryaccno) { $form->{amount}{$form->{id}}{$lastinventoryaccno} -= $invoicediff; @@ -335,7 +373,7 @@ sub post_invoice { # update exchangerate if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) { - $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate}, 0, $form->{exchangerate}); + $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, 0, $form->{exchangerate}); } # record acc_trans transactions @@ -345,8 +383,9 @@ sub post_invoice { $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate) VALUES ($trans_id, (SELECT id FROM chart - WHERE accno = '$accno'), - $form->{amount}{$trans_id}{$accno}, '$form->{invdate}')|; + WHERE accno = '$accno'), + $form->{amount}{$trans_id}{$accno}, + '$form->{transdate}')|; $dbh->do($query) || $form->dberror($query); } } @@ -368,7 +407,7 @@ sub post_invoice { if ($form->{"paid_$i"} != 0) { my ($accno) = split /--/, $form->{"AP_paid_$i"}; - $form->{"datepaid_$i"} = $form->{invdate} unless ($form->{"datepaid_$i"}); + $form->{"datepaid_$i"} = $form->{transdate} unless ($form->{"datepaid_$i"}); $form->{datepaid} = $form->{"datepaid_$i"}; $amount = ($form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $paiddiff, 2)) * -1; @@ -387,11 +426,12 @@ sub post_invoice { # record payment $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, - source) + source, memo) VALUES ($form->{id}, (SELECT id FROM chart WHERE accno = '$accno'), - $form->{"paid_$i"}, '$form->{"datepaid_$i"}', - '$form->{"source_$i"}')|; + $form->{"paid_$i"}, '$form->{"datepaid_$i"}', | + .$dbh->quote($form->{"source_$i"}).qq|, | + .$dbh->quote($form->{"memo_$i"}).qq|)|; $dbh->do($query) || $form->dberror($query); @@ -411,7 +451,7 @@ sub post_invoice { # gain/loss - $amount = ($form->{"paid_$i"} * $form->{exchangerate}) - ($form->{"paid_$i"} * $form->{"exchangerate_$i"}); + $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate},2) - $form->round_amount($form->{"paid_$i"} * $form->{"exchangerate_$i"},2); if ($amount > 0) { $form->{fx}{$form->{fxgain_accno}}{$form->{"datepaid_$i"}} += $amount; } else { @@ -447,24 +487,29 @@ sub post_invoice { # set values which could be empty $form->{taxincluded} *= 1; - my $datepaid = ($form->{paid}) ? qq|'$form->{datepaid}'| : "NULL"; - my $duedate = ($form->{duedate}) ? qq|'$form->{duedate}'| : "NULL"; + ($null, $form->{department_id}) = split(/--/, $form->{department}); + $form->{department_id} *= 1; + # save AP record $query = qq|UPDATE ap set - invnumber = '$form->{invnumber}', - ordnumber = '$form->{ordnumber}', - transdate = '$form->{invdate}', + invnumber = |.$dbh->quote($form->{invnumber}).qq|, + ordnumber = |.$dbh->quote($form->{ordnumber}).qq|, + quonumber = |.$dbh->quote($form->{quonumber}).qq|, + transdate = '$form->{transdate}', vendor_id = $form->{vendor_id}, amount = $amount, netamount = $netamount, paid = $form->{paid}, - datepaid = $datepaid, - duedate = $duedate, + datepaid = |.$form->dbquote($form->{datepaid}, SQL_DATE).qq|, + duedate = |.$form->dbquote($form->{duedate}, SQL_DATE).qq|, invoice = '1', taxincluded = '$form->{taxincluded}', - notes = '$form->{notes}', - curr = '$form->{currency}' + notes = |.$dbh->quote($form->{notes}).qq|, + intnotes = |.$dbh->quote($form->{intnotes}).qq|, + curr = '$form->{currency}', + department_id = $form->{department_id}, + language_code = '$form->{language_code}' WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); @@ -473,10 +518,13 @@ sub post_invoice { $form->{name} =~ s/--$form->{vendor_id}//; $form->add_shipto($dbh, $form->{id}); - # delete zero entries - $query = qq|DELETE FROM acc_trans - WHERE amount = 0|; - $dbh->do($query) || $form->dberror($query); + my %audittrail = ( tablename => 'ap', + reference => $form->{invnumber}, + formname => $form->{type}, + action => 'posted', + id => $form->{id} ); + + $form->audittrail($dbh, "", \%audittrail); my $rc = $dbh->commit; $dbh->disconnect; @@ -526,12 +574,13 @@ sub reverse_invoice { while (my $pthref = $sth->fetchrow_hashref(NAME_lc)) { my $qty = $ref->{allocated}; + if (($ref->{allocated} + $pthref->{allocated}) > 0) { $qty = $pthref->{allocated} * -1; } my $amount = $form->round_amount($ref->{sellprice} * $qty, 2); - + #adjust allocated $form->update_balance($dbh, "invoice", @@ -551,6 +600,11 @@ sub reverse_invoice { qq|trans_id = $pthref->{trans_id} AND chart_id = $ref->{inventory_accno_id} AND transdate = '$pthref->{transdate}'|, $amount * -1); + $query = qq|DELETE FROM acc_trans + WHERE trans_id = $pthref->{trans_id} + AND amount = 0|; + $dbh->do($query) || $form->dberror($query); + last if (($ref->{allocated} -= $qty) <= 0); } $sth->finish; @@ -582,17 +636,17 @@ sub delete_invoice { # connect to database my $dbh = $form->dbconnect_noauto($myconfig); - - # check for other foreign currency transactions - $form->delete_exchangerate($dbh) if ($form->{currency} ne $form->{defaultcurrency}); + + my %audittrail = ( tablename => 'ap', + reference => $form->{invnumber}, + formname => $form->{type}, + action => 'deleted', + id => $form->{id} ); + + $form->audittrail($dbh, "", \%audittrail); &reverse_invoice($dbh, $form); - # delete zero entries - my $query = qq|DELETE FROM acc_trans - WHERE amount = 0|; - $dbh->do($query) || $form->dberror($query); - # delete AP record my $query = qq|DELETE FROM ap WHERE id = $form->{id}|; @@ -640,8 +694,8 @@ sub retrieve_invoice { 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, - d.ponumber AS invnumber, d.curr AS currencies, - current_date AS invdate + d.curr AS currencies, + current_date AS transdate FROM defaults d|; } my $sth = $dbh->prepare($query); @@ -655,8 +709,9 @@ sub retrieve_invoice { if ($form->{id}) { # retrieve invoice - $query = qq|SELECT a.invnumber, a.transdate AS invdate, a.duedate, - a.ordnumber, a.paid, a.taxincluded, a.notes, a.curr AS currency + $query = qq|SELECT a.invnumber, a.transdate, a.duedate, + a.ordnumber, a.quonumber, a.paid, a.taxincluded, a.notes, + a.intnotes, a.curr AS currency, a.vendor_id, a.language_code FROM ap a WHERE id = $form->{id}|; $sth = $dbh->prepare($query); @@ -666,8 +721,6 @@ sub retrieve_invoice { map { $form->{$_} = $ref->{$_} } keys %$ref; $sth->finish; - $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "sell"); - # get shipto $query = qq|SELECT * FROM shipto WHERE trans_id = $form->{id}|; @@ -682,11 +735,12 @@ sub retrieve_invoice { $query = qq|SELECT c1.accno AS inventory_accno, c2.accno AS income_accno, c3.accno AS expense_accno, - p.partnumber, i.description, i.qty, i.fxsellprice AS sellprice, + p.partnumber, i.description, i.qty, i.fxsellprice, i.sellprice, i.parts_id AS id, i.unit, p.bin, i.deliverydate, pr.projectnumber, - i.project_id, - pg.partsgroup + i.project_id, i.serialnumber, i.discount, + pg.partsgroup, p.partsgroup_id, p.partnumber AS sku, + t.description AS partsgrouptranslation FROM invoice i JOIN parts p ON (i.parts_id = p.id) LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id) @@ -694,33 +748,58 @@ sub retrieve_invoice { LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id) LEFT JOIN project pr ON (i.project_id = pr.id) LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id) - WHERE trans_id = $form->{id} + LEFT JOIN translation t ON (t.trans_id = p.partsgroup_id AND t.language_code = '$form->{language_code}') + WHERE i.trans_id = $form->{id} ORDER BY i.id|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); + # exchangerate defaults + &exchangerate_defaults($dbh, $form); + + # price matrix and vendor partnumber + $query = qq|SELECT partnumber + FROM partsvendor + WHERE parts_id = ? + AND vendor_id = $form->{vendor_id}|; + my $pmh = $dbh->prepare($query) || $form->dberror($query); + + # tax rates for part + $query = qq|SELECT c.accno + FROM chart c + JOIN partstax pt ON (pt.chart_id = c.id) + WHERE pt.parts_id = ?|; + my $tth = $dbh->prepare($query); + + my $ptref; + my $taxrate; + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { - # get tax rates for part - $query = qq|SELECT c.accno - FROM chart c, partstax pt - WHERE pt.chart_id = c.id - AND pt.parts_id = $ref->{id}|; - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); + ($decimalplaces) = ($ref->{fxsellprice} =~ /\.(\d+)/); + $decimalplaces = length $decimalplaces; + $decimalplaces = 2 unless $decimalplaces; + $tth->execute($ref->{id}); $ref->{taxaccounts} = ""; - my $taxrate = 0; + $taxrate = 0; - while (my $ptref = $sth->fetchrow_hashref(NAME_lc)) { + while ($ptref = $tth->fetchrow_hashref(NAME_lc)) { $ref->{taxaccounts} .= "$ptref->{accno} "; $taxrate += $form->{"$ptref->{accno}_rate"}; } - $sth->finish; + $tth->finish; chop $ref->{taxaccounts}; + # price matrix + $ref->{sellprice} = $form->round_amount($ref->{fxsellprice} * $form->{$form->{currency}}, 2); + &price_matrix($pmh, $ref, $decimalplaces, $form); + + $ref->{sellprice} = $ref->{fxsellprice}; $ref->{qty} *= -1; + + $ref->{partsgroup} = $ref->{partsgrouptranslation} if $ref->{partsgrouptranslation}; push @{ $form->{invoice_details} }, $ref; @@ -728,16 +807,6 @@ sub retrieve_invoice { $sth->finish; - } else { - - # up invoice number by 1 - $form->{invnumber}++; - - # save the new number - $query = qq|UPDATE defaults - SET ponumber = '$form->{invnumber}'|; - $dbh->do($query) || $form->dberror($query); - } @@ -757,27 +826,90 @@ sub get_vendor { my $dbh = $form->dbconnect($myconfig); my $dateformat = $myconfig->{dateformat}; - $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/; + if ($myconfig->{dateformat} !~ /^y/) { + my @a = split /\W/, $form->{transdate}; + $dateformat .= "yy" if (length $a[2] > 2); + } - my $duedate = ($form->{invdate}) ? "to_date('$form->{invdate}', '$dateformat')" : "current_date"; + if ($form->{transdate} !~ /\W/) { + $dateformat = 'yyyymmdd'; + } + + my $duedate; + + if ($myconfig->{dbdriver} eq 'DB2') { + $duedate = ($form->{transdate}) ? "date('$form->{transdate}') + v.terms DAYS" : "current_date + v.terms DAYS"; + } else { + $duedate = ($form->{transdate}) ? "to_date('$form->{transdate}', '$dateformat') + v.terms" : "current_date + v.terms"; + } $form->{vendor_id} *= 1; # get vendor - my $query = qq|SELECT taxincluded, terms, email, cc, bcc, - addr1, addr2, addr3, addr4, - $duedate + terms AS duedate - FROM vendor - WHERE id = $form->{vendor_id}|; + my $query = qq|SELECT v.name AS vendor, v.creditlimit, v.terms, + v.email, v.cc, v.bcc, v.taxincluded, + v.address1, v.address2, v.city, v.state, + v.zipcode, v.country, v.curr AS currency, v.language_code, + $duedate AS duedate, v.notes AS intnotes, + e.name AS employee, e.id AS employee_id + FROM vendor v + LEFT JOIN employee e ON (e.id = v.employee_id) + WHERE v.id = $form->{vendor_id}|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); $ref = $sth->fetchrow_hashref(NAME_lc); + + if ($form->{id}) { + map { delete $ref->{$_} } qw(currency taxincluded employee employee_id intnotes); + } + map { $form->{$_} = $ref->{$_} } keys %$ref; $sth->finish; + + # if no currency use defaultcurrency + $form->{currency} = ($form->{currency}) ? $form->{currency} : $form->{defaultcurrency}; + + $form->{exchangerate} = 0 if $form->{currency} eq $form->{defaultcurrency}; + if ($form->{transdate} && ($form->{currency} ne $form->{defaultcurrency})) { + $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{transdate}, "sell"); + } + $form->{forex} = $form->{exchangerate}; + + # if no employee, default to login + ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh) unless $form->{employee_id}; + + $form->{creditremaining} = $form->{creditlimit}; + $query = qq|SELECT SUM(amount - paid) + FROM ap + WHERE vendor_id = $form->{vendor_id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + ($form->{creditremaining}) -= $sth->fetchrow_array; + + $sth->finish; + $query = qq|SELECT o.amount, + (SELECT e.sell FROM exchangerate e + WHERE e.curr = o.curr + AND e.transdate = o.transdate) + FROM oe o + WHERE o.vendor_id = $form->{vendor_id} + AND o.quotation = '0' + AND o.closed = '0'|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my ($amount, $exch) = $sth->fetchrow_array) { + $exch = 1 unless $exch; + $form->{creditremaining} -= $amount * $exch; + } + $sth->finish; + + # get shipto if we do not convert an order or invoice if (!$form->{shipto}) { - map { delete $form->{$_} } qw(shiptoname shiptoaddr1 shiptoaddr2 shiptoaddr3 shiptoaddr4 shiptocontact shiptophone shiptofax shiptoemail); + map { delete $form->{$_} } qw(shiptoname shiptoaddress1 shiptoaddress2 shiptocity shiptostate shiptozipcode shiptocountry shiptocontact shiptophone shiptofax shiptoemail); $query = qq|SELECT * FROM shipto WHERE trans_id = $form->{vendor_id}|; @@ -791,9 +923,9 @@ sub get_vendor { # get taxes for vendor $query = qq|SELECT c.accno - FROM chart c, vendortax v - WHERE v.chart_id = c.id - AND v.vendor_id = $form->{vendor_id}|; + FROM chart c + JOIN vendortax v ON (v.chart_id = c.id) + WHERE v.vendor_id = $form->{vendor_id}|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -805,10 +937,10 @@ sub get_vendor { # get tax rates and description - $query = qq|SELECT c.accno, c.description, c.link, t.rate - FROM chart c, tax t - WHERE c.id = t.chart_id - AND c.link LIKE '%CT_tax%' + $query = qq|SELECT c.accno, c.description, c.link, t.rate, t.taxnumber + FROM chart c + JOIN tax t ON (c.id = t.chart_id) + WHERE c.link LIKE '%CT_tax%' ORDER BY accno|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -820,6 +952,7 @@ sub get_vendor { if ($vendortax{$ref->{accno}}) { $form->{"$ref->{accno}_rate"} = $ref->{rate}; $form->{"$ref->{accno}_description"} = $ref->{description}; + $form->{"$ref->{accno}_taxnumber"} = $ref->{taxnumber}; $form->{taxaccounts} .= "$ref->{accno} "; } @@ -838,24 +971,32 @@ sub get_vendor { chop $form->{taxpart}; chop $form->{taxservice}; - if (!$form->{id} && $form->{type} !~ /_order/) { + + if (!$form->{id} && $form->{type} !~ /_(order|quotation)/) { # setup last accounts used - $query = qq|SELECT c.accno, c.description, c.link, c.category - FROM chart c + $query = qq|SELECT c.accno, c.description, c.link, c.category, + ac.project_id, p.projectnumber, a.department_id, + d.description AS department + FROM chart c JOIN acc_trans ac ON (ac.chart_id = c.id) JOIN ap a ON (a.id = ac.trans_id) + LEFT JOIN project p ON (ac.project_id = p.id) + LEFT JOIN department d ON (a.department_id = d.id) WHERE a.vendor_id = $form->{vendor_id} - AND NOT (c.link LIKE '%_tax%' OR c.link LIKE '%_paid%') AND a.id IN (SELECT max(id) FROM ap - WHERE vendor_id = $form->{vendor_id})|; + WHERE vendor_id = $form->{vendor_id})|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - + my $i = 0; while ($ref = $sth->fetchrow_hashref(NAME_lc)) { - if ($ref->{category} eq 'E') { + $form->{department} = $ref->{department}; + $form->{department_id} = $ref->{department_id}; + + if ($ref->{link} =~ /_amount/) { $i++; $form->{"AP_amount_$i"} = "$ref->{accno}--$ref->{description}"; + $form->{"projectnumber_$i"} = "$ref->{projectnumber}--$ref->{project_id}"; } if ($ref->{category} eq 'L') { $form->{AP} = $form->{AP_1} = "$ref->{accno}--$ref->{description}"; @@ -874,10 +1015,11 @@ sub retrieve_item { my ($self, $myconfig, $form) = @_; my $i = $form->{rowcount}; + my $null; my $var; # don't include assemblies or obsolete parts - my $where = "NOT p.assembly = '1' AND NOT p.obsolete = '1'"; + my $where = "WHERE p.assembly = '0' AND p.obsolete = '0'"; if ($form->{"partnumber_$i"}) { $var = $form->like(lc $form->{"partnumber_$i"}); @@ -886,18 +1028,22 @@ sub retrieve_item { if ($form->{"description_$i"}) { $var = $form->like(lc $form->{"description_$i"}); - $where .= " AND lower(p.description) LIKE '$var'"; + if ($form->{language_code}) { + $where .= " AND lower(t1.description) LIKE '$var'"; + } else { + $where .= " AND lower(p.description) LIKE '$var'"; + } } if ($form->{"partsgroup_$i"}) { - $var = $form->like(lc $form->{"partsgroup_$i"}); - $where .= " AND lower(pg.partsgroup) LIKE '$var'"; + ($null, $var) = split /--/, $form->{"partsgroup_$i"}; + $where .= qq| AND p.partsgroup_id = $var|; } - + if ($form->{"description_$i"}) { - $where .= " ORDER BY description"; + $where .= " ORDER BY 3"; } else { - $where .= " ORDER BY partnumber"; + $where .= " ORDER BY 2"; } # connect to database @@ -907,33 +1053,67 @@ sub retrieve_item { c1.accno AS inventory_accno, c2.accno AS income_accno, c3.accno AS expense_accno, - pg.partsgroup + pg.partsgroup, p.partsgroup_id, + p.lastcost AS sellprice, p.unit, p.bin, p.onhand, + p.partnumber AS sku, p.weight, + t1.description AS translation, + t2.description AS grouptranslation FROM parts p LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id) LEFT JOIN chart c2 ON (p.income_accno_id = c2.id) LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id) LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id) - WHERE $where|; + LEFT JOIN translation t1 ON (t1.trans_id = p.id AND t1.language_code = '$form->{language_code}') + LEFT JOIN translation t2 ON (t2.trans_id = p.partsgroup_id AND t2.language_code = '$form->{language_code}') + $where|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); + + # foreign currency + &exchangerate_defaults($dbh, $form); - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { - # get tax rates for part - $query = qq|SELECT c.accno - FROM chart c - JOIN partstax pt ON (pt.chart_id = c.id) - WHERE pt.parts_id = $ref->{id}|; - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); + # taxes + $query = qq|SELECT c.accno + FROM chart c + JOIN partstax pt ON (pt.chart_id = c.id) + WHERE pt.parts_id = ?|; + my $tth = $dbh->prepare($query) || $form->dberror($query); + + # price matrix + $query = qq|SELECT p.* + FROM partsvendor p + WHERE p.parts_id = ? + AND vendor_id = $form->{vendor_id}|; + my $pmh = $dbh->prepare($query) || $form->dberror($query); + + my $ref; + my $ptref; + my $decimalplaces; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + + ($decimalplaces) = ($ref->{sellprice} =~ /\.(\d+)/); + $decimalplaces = length $decimalplaces; + $decimalplaces = 2 unless $decimalplaces; + + # get taxes for part + $tth->execute($ref->{id}); $ref->{taxaccounts} = ""; - while (my $ptref = $sth->fetchrow_hashref(NAME_lc)) { + while ($ptref = $tth->fetchrow_hashref(NAME_lc)) { $ref->{taxaccounts} .= "$ptref->{accno} "; } - $sth->finish; + $tth->finish; chop $ref->{taxaccounts}; + + # get vendor price and partnumber + &price_matrix($pmh, $ref, $decimalplaces, $form, $myconfig); + + $ref->{description} = $ref->{translation} if $ref->{translation}; + $ref->{partsgroup} = $ref->{grouptranslation} if $ref->{grouptranslation}; push @{ $form->{item_list} }, $ref; + } $sth->finish; @@ -942,6 +1122,72 @@ sub retrieve_item { } +sub exchangerate_defaults { + my ($dbh, $form) = @_; + + my $var; + + # get default currencies + my $query = qq|SELECT substr(curr,1,3), curr FROM defaults|; + my $eth = $dbh->prepare($query) || $form->dberror($query); + $eth->execute; + ($form->{defaultcurrency}, $form->{currencies}) = $eth->fetchrow_array; + $eth->finish; + + $query = qq|SELECT sell + FROM exchangerate + WHERE curr = ? + AND transdate = ?|; + my $eth1 = $dbh->prepare($query) || $form->dberror($query); + + $query = qq~SELECT max(transdate || ' ' || sell || ' ' || curr) + FROM exchangerate + WHERE curr = ?~; + my $eth2 = $dbh->prepare($query) || $form->dberror($query); + + # get exchange rates for transdate or max + foreach $var (split /:/, substr($form->{currencies},4)) { + $eth1->execute($var, $form->{transdate}); + ($form->{$var}) = $eth1->fetchrow_array; + if (! $form->{$var} ) { + $eth2->execute($var); + + ($form->{$var}) = $eth2->fetchrow_array; + ($null, $form->{$var}) = split / /, $form->{$var}; + $form->{$var} = 1 unless $form->{$var}; + $eth2->finish; + } + $eth1->finish; + } + + $form->{$form->{defaultcurrency}} = 1; + +} + + +sub price_matrix { + my ($pmh, $ref, $decimalplaces, $form, $myconfig) = @_; + + $pmh->execute($ref->{id}); + my $mref = $pmh->fetchrow_hashref(NAME_lc); + + if ($mref->{partnumber}) { + $ref->{partnumber} = $mref->{partnumber}; + } + + if ($mref->{lastcost}) { + # do a conversion + $ref->{sellprice} = $form->round_amount($mref->{lastcost} * $form->{$mref->{curr}}, $decimalplaces); + } + $pmh->finish; + + $ref->{sellprice} *= 1; + + # add 0:price to matrix + $ref->{pricematrix} = "0:$ref->{sellprice}"; + +} + sub vendor_details { my ($self, $myconfig, $form) = @_; @@ -950,8 +1196,10 @@ sub vendor_details { my $dbh = $form->dbconnect($myconfig); # get rest for the vendor - my $query = qq|SELECT vendornumber, name, addr1, addr2, addr3, addr4, - contact, phone as vendorphone, fax as vendorfax, vendornumber + my $query = qq|SELECT vendornumber, name, address1, address2, city, state, + zipcode, country, + contact, phone as vendorphone, fax as vendorfax, vendornumber, + taxnumber, sic_code AS sic, iban, bic FROM vendor WHERE id = $form->{vendor_id}|; my $sth = $dbh->prepare($query); diff --git a/sql-ledger/SL/IS.pm b/sql-ledger/SL/IS.pm index dc11e3677..788dd9568 100644 --- a/sql-ledger/SL/IS.pm +++ b/sql-ledger/SL/IS.pm @@ -1,12 +1,12 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 1998-2002 +# Copyright (C) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org # Web: http://www.sql-ledger.org # -# Contributors: +# Contributors: Jim Rawlings # # 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 @@ -32,12 +32,12 @@ package IS; sub invoice_details { my ($self, $myconfig, $form) = @_; - $form->{duedate} = $form->{invdate} unless ($form->{duedate}); + $form->{duedate} = $form->{transdate} unless ($form->{duedate}); # connect to database my $dbh = $form->dbconnect($myconfig); - my $query = qq|SELECT date '$form->{duedate}' - date '$form->{invdate}' + my $query = qq|SELECT date '$form->{duedate}' - date '$form->{transdate}' AS terms FROM defaults|; my $sth = $dbh->prepare($query); @@ -46,52 +46,121 @@ sub invoice_details { ($form->{terms}) = $sth->fetchrow_array; $sth->finish; + # this is for the template + $form->{invdate} = $form->{transdate}; + my $tax = 0; my $item; my $i; - my @partsgroup = (); + my @sortlist = (); + my $projectnumber; + my $projectnumber_id; + my $translation; my $partsgroup; - my %oid = ( 'Pg' => 'oid', - 'Oracle' => 'rowid' ); + + my %oid = ( 'Pg' => 'oid', + 'PgPP' => 'oid', + 'Oracle' => 'rowid', + 'DB2' => '1=1' + ); # sort items by partsgroup for $i (1 .. $form->{rowcount}) { + $projectnumber = ""; $partsgroup = ""; - if ($form->{"partsgroup_$i"} && $form->{groupitems}) { - $form->format_string("partsgroup_$i"); - $partsgroup = $form->{"partsgroup_$i"}; + $projectnumber_id = 0; + if ($form->{"projectnumber_$i"} && $form->{groupprojectnumber}) { + ($projectnumber, $projectnumber_id) = split /--/, $form->{"projectnumber_$i"}; } - push @partsgroup, [ $i, $partsgroup ]; + if ($form->{"partsgroup_$i"} && $form->{grouppartsgroup}) { + ($partsgroup) = split /--/, $form->{"partsgroup_$i"}; + } + push @sortlist, [ $i, "$projectnumber$partsgroup", $projectnumber, $projectnumber_id, $partsgroup ]; + + + # sort the whole thing by project and group + @sortlist = sort { $a->[1] cmp $b->[1] } @sortlist; + } + my @taxaccounts; + my %taxaccounts; + my $taxrate; + my $taxamount; + my $taxbase; + my $taxdiff; + + $query = qq|SELECT p.description, t.description + FROM project p + LEFT JOIN translation t ON (t.trans_id = p.id AND t.language_code = '$form->{language_code}') + WHERE id = ?|; + my $prh = $dbh->prepare($query) || $form->dberror($query); + + my $runningnumber = 1; my $sameitem = ""; - foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) { + my $subtotal; + my $k = scalar @sortlist; + my $j = 0; + + foreach $item (@sortlist) { $i = $item->[0]; + $j++; + + if ($form->{groupprojectnumber} || $form->{grouppartsgroup}) { + if ($item->[1] ne $sameitem) { + + $projectnumber = ""; + if ($form->{groupprojectnumber} && $item->[2]) { + # get project description + $prh->execute($item->[3]) || $form->dberror($query); + + ($projectnumber, $translation) = $prh->fetchrow_array; + $prh->finish; + + $projectnumber = ($translation) ? "$item->[2], $translation" : "$item->[2], $projectnumber"; + } + + if ($form->{grouppartsgroup} && $item->[4]) { + $projectnumber .= " / " if $projectnumber; + $projectnumber .= $item->[4]; + } - if ($item->[1] ne $sameitem) { - push(@{ $form->{description} }, qq|$item->[1]|); - $sameitem = $item->[1]; + $form->{projectnumber} = $projectnumber; + $form->format_string(projectnumber); - map { push(@{ $form->{$_} }, "") } qw(runningnumber number bin qty unit deliverydate sellprice listprice netprice discount linetotal); + push(@{ $form->{description} }, qq|$form->{projectnumber}|); + $sameitem = $item->[1]; + + map { push(@{ $form->{$_} }, "") } qw(runningnumber number sku serialnumber bin qty unit deliverydate projectnumber sellprice listprice netprice discount discountrate linetotal weight); + } } - + $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}); if ($form->{"qty_$i"} != 0) { + $form->{totalqty} += $form->{"qty_$i"}; + $form->{totalship} += $form->{"ship_$i"}; + $form->{totalweight} += ($form->{"qty_$i"} * $form->{"weight_$i"}); + # add number, description and qty to $form->{number}, .... - push(@{ $form->{runningnumber} }, $i); + push(@{ $form->{runningnumber} }, $runningnumber++); push(@{ $form->{number} }, qq|$form->{"partnumber_$i"}|); + push(@{ $form->{sku} }, qq|$form->{"sku_$i"}|); + push(@{ $form->{serialnumber} }, qq|$form->{"serialnumber_$i"}|); push(@{ $form->{bin} }, qq|$form->{"bin_$i"}|); push(@{ $form->{description} }, qq|$form->{"description_$i"}|); push(@{ $form->{qty} }, $form->format_amount($myconfig, $form->{"qty_$i"})); push(@{ $form->{unit} }, qq|$form->{"unit_$i"}|); push(@{ $form->{deliverydate} }, qq|$form->{"deliverydate_$i"}|); + push(@{ $form->{projectnumber} }, qq|$form->{"projectnumber_$i"}|); push(@{ $form->{sellprice} }, $form->{"sellprice_$i"}); # listprice push(@{ $form->{listprice} }, $form->{"listprice_$i"}); + + push(@{ $form->{weight} }, $form->{"weight_$i"}); my $sellprice = $form->parse_amount($myconfig, $form->{"sellprice_$i"}); my ($dec) = ($sellprice =~ /\.(\d+)/); @@ -111,45 +180,68 @@ sub invoice_details { $linetotal = ($linetotal != 0) ? $linetotal : " "; push(@{ $form->{discount} }, $discount); + push(@{ $form->{discountrate} }, $form->format_amount($myconfig, $form->{"discount_$i"})); $form->{total} += $linetotal; + # this is for the subtotals for grouping + $subtotal += $linetotal; + push(@{ $form->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2)); - my $taxrate = 0; - my ($taxamount, $taxbase); + @taxaccounts = split / /, $form->{"taxaccounts_$i"}; + $taxrate = 0; + $taxdiff = 0; - map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{"taxaccounts_$i"}; + map { $taxrate += $form->{"${_}_rate"} } @taxaccounts; if ($form->{taxincluded}) { # calculate tax - $taxamount = $linetotal * ($taxrate / (1 + $taxrate)); + $taxamount = $linetotal * $taxrate / (1 + $taxrate); $taxbase = $linetotal - $taxamount; } else { $taxamount = $linetotal * $taxrate; $taxbase = $linetotal; } - - if ($taxamount != 0) { - foreach my $item (split / /, $form->{"taxaccounts_$i"}) { + + if (@taxaccounts && $form->round_amount($taxamount, 2) == 0) { + if ($form->{taxincluded}) { + foreach $item (@taxaccounts) { + $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2); + + $taxaccounts{$item} += $taxamount; + $taxdiff += $taxamount; + + $taxbase{$item} += $taxbase; + } + $taxaccounts{$taxaccounts[0]} += $taxdiff; + } else { + foreach $item (@taxaccounts) { + $taxaccounts{$item} += $linetotal * $form->{"${item}_rate"}; + $taxbase{$item} += $taxbase; + } + } + } else { + foreach $item (@taxaccounts) { $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate; $taxbase{$item} += $taxbase; } } + if ($form->{"assembly_$i"}) { - $sameitem = ""; + my $sm = ""; # get parts and push them onto the stack my $sortorder = ""; - if ($form->{groupitems}) { + if ($form->{groupitems}) { $sortorder = qq|ORDER BY pg.partsgroup, a.$oid{$myconfig->{dbdriver}}|; } else { $sortorder = qq|ORDER BY a.$oid{$myconfig->{dbdriver}}|; } $query = qq|SELECT p.partnumber, p.description, p.unit, a.qty, - pg.partsgroup + pg.partsgroup, p.partnumber AS sku FROM assembly a JOIN parts p ON (a.parts_id = p.id) LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) @@ -160,33 +252,59 @@ sub invoice_details { $sth->execute || $form->dberror($query); while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { - if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) { - map { push(@{ $form->{$_} }, "") } qw(runningnumber number unit qty bin sellprice listprice netprice discount linetotal); - $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--"; - push(@{ $form->{description} }, $sameitem); + if ($form->{grouppartsgroup} && $ref->{partsgroup} ne $sameitem) { + map { push(@{ $form->{$_} }, "") } qw(runningnumber number sku serialnumber unit qty bin deliverydate projectnumber sellprice listprice netprice discount discountrate linetotal weight); + $sm = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--"; + push(@{ $form->{description} }, $sm); } - push(@{ $form->{number} }, qq|$ref->{partnumber}|); - push(@{ $form->{description} }, qq|$ref->{description}|); - push(@{ $form->{unit} }, qq|$ref->{unit}|); - push(@{ $form->{qty} }, $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"})); - - map { push(@{ $form->{$_} }, "") } qw(runningnumber bin sellprice listprice netprice discount linetotal); + map { $form->{"a_$_"} = $ref->{$_} } qw(partnumber description); + $form->format_string("a_partnumber", "a_description"); + + push(@{ $form->{description} }, $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}) . qq| -- $form->{"a_partnumber"}, $form->{"a_description"}|); + map { push(@{ $form->{$_} }, "") } qw(runningnumber number sku serialnumber unit qty bin deliverydate projectnumber sellprice listprice netprice discount discountrate linetotal weight); } $sth->finish; } - } + + # add subtotal + if ($form->{groupprojectnumber} || $form->{grouppartsgroup}) { + if ($subtotal) { + if ($j < $k) { + # look at next item + if ($sortlist[$j]->[1] ne $sameitem) { + map { push(@{ $form->{$_} }, "") } qw(runningnumber number sku serialnumber bin qty unit deliverydate projectnumber sellprice listprice netprice discount discountrate weight); + push(@{ $form->{description} }, $form->{groupsubtotaldescription}); + if (exists $form->{groupsubtotaldescription}) { + push(@{ $form->{linetotal} }, $form->format_amount($myconfig, $subtotal, 2)); + } else { + push(@{ $form->{linetotal} }, ""); + } + $subtotal = 0; + } + } else { + + # got last item + if (exists $form->{groupsubtotaldescription}) { + map { push(@{ $form->{$_} }, "") } qw(runningnumber number sku serialnumber bin qty unit deliverydate projectnumber sellprice listprice netprice discount discountrate weight); + push(@{ $form->{description} }, $form->{groupsubtotaldescription}); + push(@{ $form->{linetotal} }, $form->format_amount($myconfig, $subtotal, 2)); + } + } + } + } + } foreach my $item (sort keys %taxaccounts) { if ($form->round_amount($taxaccounts{$item}, 2) != 0) { push(@{ $form->{taxbase} }, $form->format_amount($myconfig, $taxbase{$item}, 2)); - + $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2); - + push(@{ $form->{tax} }, $form->format_amount($myconfig, $taxamount)); push(@{ $form->{taxdescription} }, $form->{"${item}_description"}); push(@{ $form->{taxrate} }, $form->format_amount($myconfig, $form->{"${item}_rate"} * 100)); @@ -202,22 +320,35 @@ sub invoice_details { push(@{ $form->{paymentaccount} }, $description); push(@{ $form->{paymentdate} }, $form->{"datepaid_$i"}); push(@{ $form->{paymentsource} }, $form->{"source_$i"}); + push(@{ $form->{paymentmemo} }, $form->{"memo_$i"}); $form->{paid} += $form->parse_amount($myconfig, $form->{"paid_$i"}); } } + map { $form->{$_} = $form->format_amount($myconfig, $form->{$_}) } qw(totalqty totalship totalweight); $form->{subtotal} = $form->format_amount($myconfig, $form->{total}, 2); $form->{invtotal} = ($form->{taxincluded}) ? $form->{total} : $form->{total} + $tax; + + use SL::CP; + my $c; + if ($form->{language_code}) { + $c = new CP $form->{language_code}; + } else { + $c = new CP $myconfig->{countrycode}; + } + $c->init; + my $whole; + ($whole, $form->{decimal}) = split /\./, $form->{invtotal}; + $form->{decimal} .= "00"; + $form->{decimal} = substr($form->{decimal}, 0, 2); + $form->{text_amount} = $c->num2text($whole); + $form->{total} = $form->format_amount($myconfig, $form->{invtotal} - $form->{paid}, 2); $form->{invtotal} = $form->format_amount($myconfig, $form->{invtotal}, 2); $form->{paid} = $form->format_amount($myconfig, $form->{paid}, 2); - # myconfig variables - map { $form->{$_} = $myconfig->{$_} } (qw(company address tel fax signature businessnumber)); - $form->{username} = $myconfig->{name}; - $dbh->disconnect; } @@ -248,8 +379,10 @@ sub customer_details { my $dbh = $form->dbconnect($myconfig); # get rest for the customer - my $query = qq|SELECT customernumber, name, addr1, addr2, addr3, addr4, - phone as customerphone, fax as customerfax, contact + my $query = qq|SELECT customernumber, name, address1, address2, city, + state, zipcode, country, + phone as customerphone, fax as customerfax, contact, + taxnumber, sic_code AS sic, iban, bic FROM customer WHERE id = $form->{customer_id}|; my $sth = $dbh->prepare($query); @@ -270,8 +403,19 @@ sub post_invoice { # connect to database, turn off autocommit my $dbh = $form->dbconnect_noauto($myconfig); - my ($query, $sth, $null, $project_id, $deliverydate); + my $query; + my $sth; + my $null; + my $project_id; my $exchangerate = 0; + + ($null, $form->{employee_id}) = split /--/, $form->{employee}; + unless ($form->{employee_id}) { + ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh); + } + + ($null, $form->{department_id}) = split(/--/, $form->{department}); + $form->{department_id} *= 1; if ($form->{id}) { @@ -282,8 +426,7 @@ sub post_invoice { $uid .= $form->{login}; $query = qq|INSERT INTO ar (invnumber, employee_id) - VALUES ('$uid', (SELECT id FROM employee - WHERE login = '$form->{login}') )|; + VALUES ('$uid', $form->{employee_id})|; $dbh->do($query) || $form->dberror($query); $query = qq|SELECT id FROM ar @@ -295,9 +438,6 @@ sub post_invoice { $sth->finish; } - - map { $form->{$_} =~ s/'/''/g } (qw(invnumber shippingpoint notes message)); - my ($netamount, $invoicediff) = (0, 0); my ($amount, $linetotal, $lastincomeaccno); @@ -315,8 +455,12 @@ sub post_invoice { if ($form->{"qty_$i"} != 0) { - map { $form->{"${_}_$i"} =~ s/'/''/g } (qw(partnumber description unit)); - + # project + $project_id = 'NULL'; + if ($form->{"projectnumber_$i"}) { + ($null, $project_id) = split /--/, $form->{"projectnumber_$i"}; + } + # undo discount formatting $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100; @@ -349,7 +493,7 @@ sub post_invoice { $netamount += $linetotal; - if ($taxamount != 0) { + if ($form->round_amount($taxamount, 2) != 0) { map { $form->{amount}{$form->{id}}{$_} += $taxamount * $form->{"${_}_rate"} / $taxrate } split / /, $form->{"taxaccounts_$i"}; } @@ -362,11 +506,10 @@ sub post_invoice { # 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); @@ -377,9 +520,9 @@ sub post_invoice { if ($form->{"assembly_$i"}) { # do not update if assembly consists of all services $query = qq|SELECT sum(p.inventory_accno_id) - FROM parts p, assembly a - WHERE a.parts_id = p.id - AND a.id = $form->{"id_$i"}|; + FROM parts p + JOIN assembly a ON (a.parts_id = p.id) + WHERE a.id = $form->{"id_$i"}|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -388,7 +531,7 @@ sub post_invoice { "parts", "onhand", qq|id = $form->{"id_$i"}|, - $form->{"qty_$i"} * -1); + $form->{"qty_$i"} * -1) unless $form->{shipped}; } $sth->finish; @@ -399,36 +542,35 @@ sub post_invoice { "parts", "onhand", qq|id = $form->{"id_$i"}|, - $form->{"qty_$i"} * -1); + $form->{"qty_$i"} * -1) unless $form->{shipped}; $allocated = &cogs($dbh, $form, $form->{"id_$i"}, $form->{"qty_$i"}); } } - $project_id = 'NULL'; - if ($form->{"project_id_$i"}) { - $project_id = $form->{"project_id_$i"}; - } - $deliverydate = ($form->{"deliverydate_$i"}) ? qq|'$form->{"deliverydate_$i"}'| : "NULL"; - + # save detail record in invoice table $query = qq|INSERT INTO invoice (trans_id, parts_id, description, qty, sellprice, fxsellprice, discount, allocated, assemblyitem, - unit, deliverydate, project_id) - VALUES ($form->{id}, $form->{"id_$i"}, - '$form->{"description_$i"}', $form->{"qty_$i"}, - $form->{"sellprice_$i"}, $fxsellprice, - $form->{"discount_$i"}, $allocated, 'f', - '$form->{"unit_$i"}', $deliverydate, $project_id)|; + unit, deliverydate, project_id, serialnumber) + VALUES ($form->{id}, $form->{"id_$i"}, | + .$dbh->quote($form->{"description_$i"}).qq|, + $form->{"qty_$i"}, $form->{"sellprice_$i"}, $fxsellprice, + $form->{"discount_$i"}, $allocated, 'f', | + .$dbh->quote($form->{"unit_$i"}).qq|, | + .$form->dbquote($form->{"deliverydate_$i"}, SQL_DATE).qq|, + $project_id, | + .$dbh->quote($form->{"serialnumber_$i"}).qq|)|; $dbh->do($query) || $form->dberror($query); } } - $form->{datepaid} = $form->{invdate}; + $form->{datepaid} = $form->{transdate}; # total payments, don't move we need it here + $form->{paid} = 0; for my $i (1 .. $form->{paidaccounts}) { $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"}); $form->{paid} += $form->{"paid_$i"}; @@ -472,12 +614,10 @@ sub post_invoice { } } - - $form->{amount}{$form->{id}}{$form->{AR}} = $netamount + $tax; + $diff = 0 if $form->{paidaccounts} < 2; - if ($form->{paid} != 0) { - $form->{paid} = $form->round_amount($form->{paid} * $form->{exchangerate} + $diff, 2); - } + $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; @@ -485,17 +625,18 @@ sub post_invoice { # update exchangerate if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) { - $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate}, $form->{exchangerate}, 0); + $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, $form->{exchangerate}, 0); } foreach my $trans_id (keys %{$form->{amount}}) { foreach my $accno (keys %{ $form->{amount}{$trans_id} }) { if (($form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2)) != 0) { $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, - transdate) + transdate) VALUES ($trans_id, (SELECT id FROM chart - WHERE accno = '$accno'), - $form->{amount}{$trans_id}{$accno}, '$form->{invdate}')|; + WHERE accno = '$accno'), + $form->{amount}{$trans_id}{$accno}, + '$form->{transdate}')|; $dbh->do($query) || $form->dberror($query); } } @@ -509,17 +650,29 @@ sub post_invoice { } } + # force AR entry if 0 - $form->{amount}{$form->{id}}{$form->{AR}} = 1 if ($form->{amount}{$form->{id}}{$form->{AR}} == 0); + $form->{amount}{$form->{id}}{$form->{AR}} = $form->{paid} if ($form->{amount}{$form->{id}}{$form->{AR}} == 0); # record payments and offsetting AR for my $i (1 .. $form->{paidaccounts}) { if ($form->{"paid_$i"} != 0) { my ($accno) = split /--/, $form->{"AR_paid_$i"}; - $form->{"datepaid_$i"} = $form->{invdate} unless ($form->{"datepaid_$i"}); + $form->{"datepaid_$i"} = $form->{transdate} unless ($form->{"datepaid_$i"}); $form->{datepaid} = $form->{"datepaid_$i"}; + $exchangerate = 0; + + if ($form->{currency} eq $form->{defaultcurrency}) { + $form->{"exchangerate_$i"} = 1; + } else { + $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy'); + + $form->{"exchangerate_$i"} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{"exchangerate_$i"}); + } + + # record AR $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $diff, 2); @@ -536,31 +689,20 @@ sub post_invoice { $form->{"paid_$i"} *= -1; $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, - source) + source, memo) VALUES ($form->{id}, (SELECT id FROM chart WHERE accno = '$accno'), - $form->{"paid_$i"}, '$form->{"datepaid_$i"}', - '$form->{"source_$i"}')|; + $form->{"paid_$i"}, '$form->{"datepaid_$i"}', | + .$dbh->quote($form->{"source_$i"}).qq|, | + .$dbh->quote($form->{"memo_$i"}).qq|)|; $dbh->do($query) || $form->dberror($query); - - $exchangerate = 0; - - if ($form->{currency} eq $form->{defaultcurrency}) { - $form->{"exchangerate_$i"} = 1; - } else { - $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy'); - - $form->{"exchangerate_$i"} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{"exchangerate_$i"}); - } - - + # exchangerate difference $form->{fx}{$accno}{$form->{"datepaid_$i"}} += $form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $diff; - # gain/loss - $amount = $form->{"paid_$i"} * $form->{exchangerate} - $form->{"paid_$i"} * $form->{"exchangerate_$i"}; + $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate},2) - $form->round_amount($form->{"paid_$i"} * $form->{"exchangerate_$i"},2); if ($amount > 0) { $form->{fx}{$form->{fxgain_accno}}{$form->{"datepaid_$i"}} += $amount; } else { @@ -599,39 +741,34 @@ sub post_invoice { # set values which could be empty to 0 $form->{terms} *= 1; $form->{taxincluded} *= 1; - my $datepaid = ($form->{paid}) ? qq|'$form->{datepaid}'| : "NULL"; - my $duedate = ($form->{duedate}) ? qq|'$form->{duedate}'| : "NULL"; - - # fill in subject if there is none - $form->{subject} = qq|$form->{label} $form->{invnumber}| unless $form->{subject}; - # if there is a message stuff it into the notes - my $cc = "Cc: $form->{cc}\\r\n" if $form->{cc}; - my $bcc = "Bcc: $form->{bcc}\\r\n" if $form->{bcc}; - $form->{notes} .= qq|\r -\r -[email]\r -To: $form->{email}\r -$cc${bcc}Subject: $form->{subject}\r -\r -Message: $form->{message}\r| if $form->{message}; + # if this is from a till + my $till = ($form->{till}) ? qq|'$form->{till}'| : "NULL"; + # save AR record $query = qq|UPDATE ar set - invnumber = '$form->{invnumber}', - ordnumber = '$form->{ordnumber}', - transdate = '$form->{invdate}', + invnumber = |.$dbh->quote($form->{invnumber}).qq|, + ordnumber = |.$dbh->quote($form->{ordnumber}).qq|, + quonumber = |.$dbh->quote($form->{quonumber}).qq|, + transdate = '$form->{transdate}', customer_id = $form->{customer_id}, amount = $amount, netamount = $netamount, paid = $form->{paid}, - datepaid = $datepaid, - duedate = $duedate, + datepaid = |.$form->dbquote($form->{datepaid}, SQL_DATE).qq|, + duedate = |.$form->dbquote($form->{duedate}, SQL_DATE).qq|, invoice = '1', - shippingpoint = '$form->{shippingpoint}', + shippingpoint = |.$dbh->quote($form->{shippingpoint}).qq|, + shipvia = |.$dbh->quote($form->{shipvia}).qq|, terms = $form->{terms}, - notes = '$form->{notes}', + notes = |.$dbh->quote($form->{notes}).qq|, + intnotes = |.$dbh->quote($form->{intnotes}).qq|, taxincluded = '$form->{taxincluded}', - curr = '$form->{currency}' + curr = '$form->{currency}', + department_id = $form->{department_id}, + employee_id = $form->{employee_id}, + till = $till, + language_code = '$form->{language_code}' WHERE id = $form->{id} |; $dbh->do($query) || $form->dberror($query); @@ -641,6 +778,17 @@ Message: $form->{message}\r| if $form->{message}; $form->{name} =~ s/--$form->{customer_id}//; $form->add_shipto($dbh, $form->{id}); + # save printed, emailed and queued + $form->save_status($dbh); + + my %audittrail = ( tablename => 'ar', + reference => $form->{invnumber}, + formname => $form->{type}, + action => 'posted', + id => $form->{id} ); + + $form->audittrail($dbh, "", \%audittrail); + my $rc = $dbh->commit; $dbh->disconnect; @@ -656,9 +804,9 @@ sub process_assembly { p.partnumber, p.description, p.unit, p.inventory_accno_id, p.income_accno_id, p.expense_accno_id - FROM assembly a, parts p - WHERE a.parts_id = p.id - AND a.id = $id|; + FROM assembly a + JOIN parts p ON (a.parts_id = p.id) + WHERE a.id = $id|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -670,8 +818,6 @@ sub process_assembly { $ref->{inventory_accno_id} *= 1; $ref->{expense_accno_id} *= 1; - map { $ref->{$_} =~ s/'/''/g } (qw(partnumber description unit)); - # multiply by number of assemblies $ref->{qty} *= $totalqty; @@ -688,9 +834,10 @@ sub process_assembly { $query = qq|INSERT INTO invoice (trans_id, description, parts_id, qty, sellprice, fxsellprice, allocated, assemblyitem, unit) VALUES - ($form->{id}, '$ref->{description}', - $ref->{parts_id}, $ref->{qty}, 0, 0, $allocated, 't', - '$ref->{unit}')|; + ($form->{id}, | + .$dbh->quote($ref->{description}).qq|, + $ref->{parts_id}, $ref->{qty}, 0, 0, $allocated, 't', | + .$dbh->quote($ref->{unit}).qq|)|; $dbh->do($query) || $form->dberror($query); } @@ -702,14 +849,12 @@ sub process_assembly { sub cogs { my ($dbh, $form, $id, $totalqty) = @_; - + my $query = qq|SELECT i.id, i.trans_id, i.qty, i.allocated, i.sellprice, - (SELECT c.accno FROM chart c - WHERE p.inventory_accno_id = c.id) - AS inventory_accno, - (SELECT c.accno FROM chart c - WHERE p.expense_accno_id = c.id) - AS expense_accno + (SELECT c.accno FROM chart c + WHERE p.inventory_accno_id = c.id) AS inventory_accno, + (SELECT c.accno FROM chart c + WHERE p.expense_accno_id = c.id) AS expense_accno FROM invoice i, parts p WHERE i.parts_id = p.id AND i.parts_id = $id @@ -762,9 +907,9 @@ sub reverse_invoice { # reverse inventory items my $query = qq|SELECT i.id, i.parts_id, i.qty, i.assemblyitem, p.assembly, p.inventory_accno_id - FROM invoice i, parts p - WHERE i.parts_id = p.id - AND i.trans_id = $form->{id}|; + FROM invoice i + JOIN parts p ON (i.parts_id = p.id) + WHERE i.trans_id = $form->{id}|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -773,7 +918,7 @@ sub reverse_invoice { if ($ref->{inventory_accno_id} || $ref->{assembly}) { # if the invoice item is not an assemblyitem adjust parts onhand - unless ($ref->{assemblyitem}) { + if (!$ref->{assemblyitem}) { # adjust onhand in parts table $form->update_balance($dbh, "parts", @@ -834,23 +979,54 @@ sub reverse_invoice { sub delete_invoice { - my ($self, $myconfig, $form) = @_; + my ($self, $myconfig, $form, $spool) = @_; # connect to database my $dbh = $form->dbconnect_noauto($myconfig); - # check for other foreign currency transactions - $form->delete_exchangerate($dbh) if ($form->{currency} ne $form->{defaultcurrency}); - &reverse_invoice($dbh, $form); + my %audittrail = ( tablename => 'ar', + reference => $form->{invnumber}, + formname => $form->{type}, + action => 'deleted', + id => $form->{id} ); + + $form->audittrail($dbh, "", \%audittrail); + # delete AR record my $query = qq|DELETE FROM ar WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); + # delete spool files + $query = qq|SELECT spoolfile FROM status + WHERE trans_id = $form->{id} + AND spoolfile IS NOT NULL|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my $spoolfile; + my @spoolfiles = (); + + while (($spoolfile) = $sth->fetchrow_array) { + push @spoolfiles, $spoolfile; + } + $sth->finish; + + # delete status entries + $query = qq|DELETE FROM status + WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + my $rc = $dbh->commit; $dbh->disconnect; + + if ($rc) { + foreach $spoolfile (@spoolfiles) { + unlink "$spool/$spoolfile" if $spoolfile; + } + } $rc; @@ -865,7 +1041,7 @@ sub retrieve_invoice { my $dbh = $form->dbconnect_noauto($myconfig); my $query; - + if ($form->{id}) { # get default accounts and last invoice number $query = qq|SELECT (SELECT c.accno FROM chart c @@ -891,7 +1067,7 @@ sub retrieve_invoice { 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, - d.invnumber, d.curr AS currencies, current_date AS invdate + d.curr AS currencies, current_date AS transdate FROM defaults d|; } my $sth = $dbh->prepare($query); @@ -905,11 +1081,14 @@ sub retrieve_invoice { if ($form->{id}) { # retrieve invoice - $query = qq|SELECT a.invnumber, a.ordnumber, a.transdate AS invdate, a.paid, - a.shippingpoint, a.terms, a.notes, a.duedate, a.taxincluded, - a.curr AS currency, (SELECT e.name FROM employee e - WHERE e.id = a.employee_id) AS employee + $query = qq|SELECT a.invnumber, a.ordnumber, a.quonumber, + a.transdate, a.paid, + a.shippingpoint, a.shipvia, a.terms, a.notes, a.intnotes, + a.duedate, a.taxincluded, a.curr AS currency, + a.employee_id, e.name AS employee, a.till, a.customer_id, + a.language_code FROM ar a + LEFT JOIN employee e ON (e.id = a.employee_id) WHERE a.id = $form->{id}|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -918,8 +1097,6 @@ sub retrieve_invoice { map { $form->{$_} = $ref->{$_} } keys %$ref; $sth->finish; - $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "buy"); - # get shipto $query = qq|SELECT * FROM shipto WHERE trans_id = $form->{id}|; @@ -929,70 +1106,82 @@ sub retrieve_invoice { $ref = $sth->fetchrow_hashref(NAME_lc); map { $form->{$_} = $ref->{$_} } keys %$ref; $sth->finish; - + # retrieve individual items - $query = qq|SELECT c1.accno AS inventory_accno, - c2.accno AS income_accno, - c3.accno AS expense_accno, - i.description, i.qty, i.fxsellprice AS sellprice, + $query = qq|SELECT (SELECT c.accno FROM chart c + WHERE p.inventory_accno_id = c.id) + AS inventory_accno, + (SELECT c.accno FROM chart c + WHERE p.income_accno_id = c.id) + AS income_accno, + (SELECT c.accno FROM chart c + WHERE p.expense_accno_id = c.id) + AS expense_accno, + i.description, i.qty, i.fxsellprice, i.sellprice, i.discount, i.parts_id AS id, i.unit, i.deliverydate, - pr.projectnumber, - i.project_id, + i.project_id, pr.projectnumber, i.serialnumber, p.partnumber, p.assembly, p.bin, - pg.partsgroup + pg.partsgroup, p.partsgroup_id, p.partnumber AS sku, + p.listprice, p.lastcost, p.weight, + t.description AS partsgrouptranslation FROM invoice i - JOIN parts p ON (i.parts_id = p.id) - LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id) - LEFT JOIN chart c2 ON (p.income_accno_id = c2.id) - LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id) - LEFT JOIN project pr ON (i.project_id = pr.id) - LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + 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 translation t ON (t.trans_id = p.partsgroup_id AND t.language_code = '$form->{language_code}') WHERE i.trans_id = $form->{id} AND NOT i.assemblyitem = '1' ORDER BY i.id|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); + # foreign currency + &exchangerate_defaults($dbh, $form); + + # query for price matrix + my $pmh = &price_matrix_query($dbh, $form); + + # taxes + $query = qq|SELECT c.accno + FROM chart c + JOIN partstax pt ON (pt.chart_id = c.id) + WHERE pt.parts_id = ?|; + my $tth = $dbh->prepare($query) || $form->dberror($query); + + my $taxrate; + my $ptref; + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { - # get taxes - $query = qq|SELECT c.accno - FROM chart c, partstax pt - WHERE pt.chart_id = c.id - AND pt.parts_id = $ref->{id}|; - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); + + ($decimalplaces) = ($ref->{fxsellprice} =~ /\.(\d+)/); + $decimalplaces = length $decimalplaces; + $decimalplaces = 2 unless $decimalplaces; + + $tth->execute($ref->{id}); $ref->{taxaccounts} = ""; - my $taxrate = 0; + $taxrate = 0; - while (my $ptref = $sth->fetchrow_hashref(NAME_lc)) { + while ($ptref = $tth->fetchrow_hashref(NAME_lc)) { $ref->{taxaccounts} .= "$ptref->{accno} "; $taxrate += $form->{"$ptref->{accno}_rate"}; } - $sth->finish; + $tth->finish; chop $ref->{taxaccounts}; + # price matrix + $ref->{sellprice} = ($ref->{fxsellprice} * $form->{$form->{currency}}); + &price_matrix($pmh, $ref, $form->{transdate}, $decimalplaces, $form, $myconfig, 1); + $ref->{sellprice} = $ref->{fxsellprice}; + + $ref->{partsgroup} = $ref->{partsgrouptranslation} if $ref->{partsgrouptranslation}; + push @{ $form->{invoice_details} }, $ref; } $sth->finish; - } else { - - $form->{shippingpoint} = $myconfig->{shippingpoint} unless $form->{shippingpoint}; - - # up invoice number by 1 - $form->{invnumber}++; - - # save the new number - $query = qq|UPDATE defaults - SET invnumber = '$form->{invnumber}'|; - $dbh->do($query) || $form->dberror($query); - - $form->get_employee($dbh); - } - my $rc = $dbh->commit; $dbh->disconnect; @@ -1006,27 +1195,60 @@ sub get_customer { # connect to database my $dbh = $form->dbconnect($myconfig); - + my $dateformat = $myconfig->{dateformat}; - $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/; - - my $duedate = ($form->{invdate}) ? "to_date('$form->{invdate}', '$dateformat')" : "current_date"; + if ($myconfig->{dateformat} !~ /^y/) { + my @a = split /\W/, $form->{transdate}; + $dateformat .= "yy" if (length $a[2] > 2); + } + + if ($form->{transdate} !~ /\W/) { + $dateformat = 'yyyymmdd'; + } + + my $duedate; + + if ($myconfig->{dbdriver} eq 'DB2') { + $duedate = ($form->{transdate}) ? "date('$form->{transdate}') + c.terms DAYS" : "current_date + c.terms DAYS"; + } else { + $duedate = ($form->{transdate}) ? "to_date('$form->{transdate}', '$dateformat') + c.terms" : "current_date + c.terms"; + } $form->{customer_id} *= 1; # get customer my $query = qq|SELECT c.name AS customer, c.discount, c.creditlimit, c.terms, c.email, c.cc, c.bcc, c.taxincluded, - c.addr1, c.addr2, c.addr3, c.addr4, - $duedate + c.terms AS duedate + c.address1, c.address2, c.city, c.state, + c.zipcode, c.country, c.curr AS currency, c.language_code, + $duedate AS duedate, c.notes AS intnotes, + b.discount AS tradediscount, b.description AS business, + e.name AS employee, e.id AS employee_id FROM customer c + LEFT JOIN business b ON (b.id = c.business_id) + LEFT JOIN employee e ON (e.id = c.employee_id) WHERE c.id = $form->{customer_id}|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); $ref = $sth->fetchrow_hashref(NAME_lc); + if ($form->{id}) { + map { delete $ref->{$_} } qw(currency taxincluded employee employee_id intnotes); + } + map { $form->{$_} = $ref->{$_} } keys %$ref; $sth->finish; + + # if no currency use defaultcurrency + $form->{currency} = ($form->{currency}) ? $form->{currency} : $form->{defaultcurrency}; + $form->{exchangerate} = 0 if $form->{currency} eq $form->{defaultcurrency}; + if ($form->{transdate} && ($form->{currency} ne $form->{defaultcurrency})) { + $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{transdate}, "buy"); + } + $form->{forex} = $form->{exchangerate}; + + # if no employee, default to login + ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh) unless $form->{employee_id}; $form->{creditremaining} = $form->{creditlimit}; $query = qq|SELECT SUM(amount - paid) @@ -1045,6 +1267,7 @@ sub get_customer { AND e.transdate = o.transdate) FROM oe o WHERE o.customer_id = $form->{customer_id} + AND o.quotation = '0' AND o.closed = '0'|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -1058,7 +1281,7 @@ sub get_customer { # get shipto if we did not converted an order or invoice if (!$form->{shipto}) { - map { delete $form->{$_} } qw(shiptoname shiptoaddr1 shiptoaddr2 shiptoaddr3 shiptoaddr4 shiptocontact shiptophone shiptofax shiptoemail); + map { delete $form->{$_} } qw(shiptoname shiptoaddress1 shiptoaddress2 shiptocity shiptostate shiptozipcode shiptocountry shiptocontact shiptophone shiptofax shiptoemail); $query = qq|SELECT * FROM shipto WHERE trans_id = $form->{customer_id}|; @@ -1072,9 +1295,9 @@ sub get_customer { # get taxes we charge for this customer $query = qq|SELECT c.accno - FROM chart c, customertax ct - WHERE ct.chart_id = c.id - AND ct.customer_id = $form->{customer_id}|; + FROM chart c + JOIN customertax ct ON (ct.chart_id = c.id) + WHERE ct.customer_id = $form->{customer_id}|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -1086,9 +1309,9 @@ sub get_customer { # get tax rates and description $query = qq|SELECT c.accno, c.description, t.rate, t.taxnumber - FROM chart c, tax t - WHERE c.id = t.chart_id - AND c.link LIKE '%CT_tax%' + FROM chart c + JOIN tax t ON (c.id = t.chart_id) + WHERE c.link LIKE '%CT_tax%' ORDER BY accno|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -1106,13 +1329,16 @@ sub get_customer { chop $form->{taxaccounts}; # setup last accounts used for this customer - if (!$form->{id} && $form->{type} !~ /_order/) { - $query = qq|SELECT c.accno, c.description, c.link, c.category + if (!$form->{id} && $form->{type} !~ /_(order|quotation)/) { + $query = qq|SELECT c.accno, c.description, c.link, c.category, + ac.project_id, p.projectnumber, a.department_id, + d.description AS department FROM chart c JOIN acc_trans ac ON (ac.chart_id = c.id) JOIN ar a ON (a.id = ac.trans_id) + LEFT JOIN project p ON (ac.project_id = p.id) + LEFT JOIN department d ON (d.id = a.department_id) WHERE a.customer_id = $form->{customer_id} - AND NOT (c.link LIKE '%_tax%' OR c.link LIKE '%_paid%') AND a.id IN (SELECT max(id) FROM ar WHERE customer_id = $form->{customer_id})|; $sth = $dbh->prepare($query); @@ -1120,9 +1346,13 @@ sub get_customer { my $i = 0; while ($ref = $sth->fetchrow_hashref(NAME_lc)) { - if ($ref->{category} eq 'I') { + $form->{department} = $ref->{department}; + $form->{department_id} = $ref->{department_id}; + + if ($ref->{link} =~ /_amount/) { $i++; $form->{"AR_amount_$i"} = "$ref->{accno}--$ref->{description}"; + $form->{"projectnumber_$i"} = "$ref->{projectnumber}--$ref->{project_id}"; } if ($ref->{category} eq 'A') { $form->{AR} = $form->{AR_1} = "$ref->{accno}--$ref->{description}"; @@ -1133,17 +1363,22 @@ sub get_customer { } $dbh->disconnect; - + } sub retrieve_item { my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); my $i = $form->{rowcount}; + my $null; my $var; - my $where = "NOT obsolete = '1'"; + + my $where = "WHERE p.obsolete = '0' AND NOT p.income_accno_id IS NULL"; if ($form->{"partnumber_$i"}) { $var = $form->like(lc $form->{"partnumber_$i"}); @@ -1151,72 +1386,93 @@ sub retrieve_item { } if ($form->{"description_$i"}) { $var = $form->like(lc $form->{"description_$i"}); - $where .= " AND lower(p.description) LIKE '$var'"; + if ($form->{language_code}) { + $where .= " AND lower(t1.description) LIKE '$var'"; + } else { + $where .= " AND lower(p.description) LIKE '$var'"; + } } if ($form->{"partsgroup_$i"}) { - $var = $form->like(lc $form->{"partsgroup_$i"}); - $where .= " AND lower(pg.partsgroup) LIKE '$var'"; + ($null, $var) = split /--/, $form->{"partsgroup_$i"}; + $var *= 1; + if ($var == 0) { + # search by partsgroup, this is for the POS + $where .= qq| AND pg.partsgroup = '$form->{"partsgroup_$i"}'|; + } else { + $where .= qq| AND p.partsgroup_id = $var|; + } } if ($form->{"description_$i"}) { - $where .= " ORDER BY description"; + $where .= " ORDER BY 3"; } else { - $where .= " ORDER BY partnumber"; + $where .= " ORDER BY 2"; } - # connect to database - my $dbh = $form->dbconnect($myconfig); - my $query = qq|SELECT p.id, p.partnumber, p.description, p.sellprice, - p.listprice, - c1.accno AS inventory_accno, - c2.accno AS income_accno, - c3.accno AS expense_accno, - p.unit, p.assembly, p.bin, p.onhand, p.makemodel, - pg.partsgroup + p.listprice, p.lastcost, + c1.accno AS inventory_accno, + c2.accno AS income_accno, + c3.accno AS expense_accno, + p.unit, p.assembly, p.bin, p.onhand, + pg.partsgroup, p.partsgroup_id, p.partnumber AS sku, + p.weight, + t1.description AS translation, + t2.description AS grouptranslation FROM parts p LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id) LEFT JOIN chart c2 ON (p.income_accno_id = c2.id) LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id) LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id) - WHERE $where|; + LEFT JOIN translation t1 ON (t1.trans_id = p.id AND t1.language_code = '$form->{language_code}') + LEFT JOIN translation t2 ON (t2.trans_id = p.partsgroup_id AND t2.language_code = '$form->{language_code}') + $where|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + my $ref; + my $ptref; + + # setup exchange rates + &exchangerate_defaults($dbh, $form); + + # taxes + $query = qq|SELECT c.accno + FROM chart c + JOIN partstax pt ON (c.id = pt.chart_id) + WHERE pt.parts_id = ?|; + my $tth = $dbh->prepare($query) || $form->dberror($query); + + # price matrix + my $pmh = &price_matrix_query($dbh, $form); + + my $transdate = $form->datetonum($form->{transdate}, $myconfig); + my $decimalplaces; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + + ($decimalplaces) = ($ref->{sellprice} =~ /\.(\d+)/); + $decimalplaces = length $decimalplaces; + $decimalplaces = 2 unless $decimalplaces; + # get taxes for part - $query = qq|SELECT c.accno - FROM chart c - JOIN partstax pt ON (c.id = pt.chart_id) - WHERE pt.parts_id = $ref->{id}|; - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); + $tth->execute($ref->{id}); $ref->{taxaccounts} = ""; - while (my $ptref = $sth->fetchrow_hashref(NAME_lc)) { + while ($ptref = $tth->fetchrow_hashref(NAME_lc)) { $ref->{taxaccounts} .= "$ptref->{accno} "; } - $sth->finish; + $tth->finish; chop $ref->{taxaccounts}; - # get makemodel - if ($ref->{makemodel}) { - $query = qq|SELECT name - FROM makemodel - WHERE parts_id = $ref->{id}|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - $ref->{makemodel} = ""; - while (my $ptref = $sth->fetchrow_hashref(NAME_lc)) { - $ref->{makemodel} .= "$ptref->{name}:"; - } - $sth->finish; - chop $ref->{makemodel}; - } + # get matrix + &price_matrix($pmh, $ref, $transdate, $decimalplaces, $form, $myconfig); + $ref->{description} = $ref->{translation} if $ref->{translation}; + $ref->{partsgroup} = $ref->{grouptranslation} if $ref->{grouptranslation}; + push @{ $form->{item_list} }, $ref; } @@ -1227,5 +1483,150 @@ sub retrieve_item { } +sub price_matrix_query { + my ($dbh, $form) = @_; + + my $query = qq|SELECT p.*, g.pricegroup + FROM partscustomer p + LEFT JOIN pricegroup g ON (g.id = p.pricegroup_id) + WHERE p.parts_id = ? + AND p.customer_id = $form->{customer_id} + + UNION + + SELECT p.*, g.pricegroup + FROM partscustomer p + LEFT JOIN pricegroup g ON (g.id = p.pricegroup_id) + JOIN customer c ON (c.pricegroup_id = g.id) + WHERE p.parts_id = ? + AND c.id = $form->{customer_id} + + UNION + + SELECT p.*, '' AS pricegroup + FROM partscustomer p + WHERE p.customer_id = 0 + AND p.pricegroup_id = 0 + AND p.parts_id = ? + + ORDER BY customer_id DESC, pricegroup_id DESC, pricebreak + + |; + my $sth = $dbh->prepare($query) || $form->dberror($query); + + $sth; + +} + + +sub price_matrix { + my ($pmh, $ref, $transdate, $decimalplaces, $form, $myconfig, $init) = @_; + + $pmh->execute($ref->{id}, $ref->{id}, $ref->{id}); + + $ref->{pricematrix} = ""; + my $customerprice; + my $pricegroup; + my $sellprice; + my $mref; + + while ($mref = $pmh->fetchrow_hashref(NAME_lc)) { + + $customerprice = 0; + $pricegroup = 0; + + # check date + if ($mref->{validfrom}) { + next if $transdate < $form->datetonum($mref->{validfrom}, $myconfig); + } + if ($mref->{validto}) { + next if $transdate > $form->datetonum($mref->{validto}, $myconfig); + } + + # convert price + $sellprice = $form->round_amount($mref->{sellprice} * $form->{$mref->{curr}}, $decimalplaces); + + if ($mref->{customer_id}) { + $ref->{sellprice} = $sellprice unless $mref->{pricebreak}; + $ref->{pricematrix} .= "$mref->{pricebreak}:$sellprice "; + $customerprice = 1; + } + + if ($mref->{pricegroup_id}) { + if (! $customerprice) { + $ref->{sellprice} = $sellprice unless $mref->{pricebreak}; + $ref->{pricematrix} .= "$mref->{pricebreak}:$sellprice "; + $pricegroup = 1; + } + } + + if (! $customerprice && ! $pricegroup) { + $ref->{sellprice} = $sellprice unless $mref->{pricebreak}; + $ref->{pricematrix} .= "$mref->{pricebreak}:$sellprice "; + } + + if ($form->{tradediscount}) { + $ref->{sellprice} = $form->round_amount($ref->{sellprice} / (1 - $form->{tradediscount}), $decimalplaces); + } + + } + $pmh->finish; + + if ($ref->{pricematrix} !~ /^0:/) { + if ($init) { + $sellprice = $form->round_amount($ref->{sellprice}, $decimalplaces); + } else { + $sellprice = $form->round_amount($ref->{sellprice} * (1 - $form->{tradediscount}), $decimalplaces); + } + $ref->{pricematrix} = "0:$sellprice ".$ref->{pricematrix}; + } + chop $ref->{pricematrix}; + +} + + +sub exchangerate_defaults { + my ($dbh, $form) = @_; + + my $var; + + # get default currencies + my $query = qq|SELECT substr(curr,1,3), curr FROM defaults|; + my $eth = $dbh->prepare($query) || $form->dberror($query); + $eth->execute; + ($form->{defaultcurrency}, $form->{currencies}) = $eth->fetchrow_array; + $eth->finish; + + $query = qq|SELECT buy + FROM exchangerate + WHERE curr = ? + AND transdate = ?|; + my $eth1 = $dbh->prepare($query) || $form->dberror($query); + + $query = qq~SELECT max(transdate || ' ' || buy || ' ' || curr) + FROM exchangerate + WHERE curr = ?~; + my $eth2 = $dbh->prepare($query) || $form->dberror($query); + + # get exchange rates for transdate or max + foreach $var (split /:/, substr($form->{currencies},4)) { + $eth1->execute($var, $form->{transdate}); + ($form->{$var}) = $eth1->fetchrow_array; + if (! $form->{$var} ) { + $eth2->execute($var); + + ($form->{$var}) = $eth2->fetchrow_array; + ($null, $form->{$var}) = split / /, $form->{$var}; + $form->{$var} = 1 unless $form->{$var}; + $eth2->finish; + } + $eth1->finish; + } + + $form->{$form->{defaultcurrency}} = 1; + +} + + 1; diff --git a/sql-ledger/SL/Inifile.pm b/sql-ledger/SL/Inifile.pm index e9de47a8f..8ccf4334d 100644 --- a/sql-ledger/SL/Inifile.pm +++ b/sql-ledger/SL/Inifile.pm @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2002 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -12,7 +12,7 @@ # 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 @@ -35,7 +35,8 @@ sub new { my $id = ""; my $skip; - + + $self ||= {}; $type = ref($self) || $self; open FH, "$file" or Form->error("$file : $!"); diff --git a/sql-ledger/SL/Mailer.pm b/sql-ledger/SL/Mailer.pm index 934ad3690..712b1d727 100644 --- a/sql-ledger/SL/Mailer.pm +++ b/sql-ledger/SL/Mailer.pm @@ -1,12 +1,12 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2002 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org # Web: http://www.sql-ledger.org # -# Contributors: +# 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 @@ -21,6 +21,10 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #====================================================================== +# +# mailer package +# +#====================================================================== package Mailer; @@ -54,7 +58,15 @@ sub send { my ($cc, $bcc); $cc = "Cc: $self->{cc}\n" if $self->{cc}; $bcc = "Bcc: $self->{bcc}\n" if $self->{bcc}; - + + foreach my $item (qw(from to cc bcc)) { + $self->{$item} =~ s/\\_/_/g; + $self->{$item} =~ s/\</{$item} =~ s/\$<\$/{$item} =~ s/\>/>/g; + $self->{$item} =~ s/\$>\$/>/g; + } + print OUT qq|From: $self->{from} To: $self->{to} ${cc}${bcc}Subject: $self->{subject} @@ -67,12 +79,15 @@ MIME-Version: 1.0 if ($self->{attachments}) { print OUT qq|Content-Type: multipart/mixed; boundary="$boundary" ---${boundary} +|; + if ($self->{message}) { + print OUT qq|--${boundary} Content-Type: $self->{contenttype}; charset="$self->{charset}" $self->{message} |; + } foreach my $attachment (@{ $self->{attachments} }) { diff --git a/sql-ledger/SL/Menu.pm b/sql-ledger/SL/Menu.pm index 661d35408..0df3067aa 100644 --- a/sql-ledger/SL/Menu.pm +++ b/sql-ledger/SL/Menu.pm @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2002 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -12,7 +12,7 @@ # 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 @@ -35,13 +35,13 @@ sub new { use SL::Inifile; my $self = Inifile->new($menufile, $level); - bless $self, $type; + bless $self, $type if $self; } sub menuitem { - my ($self, $myconfig, $form, $item) = @_; + my ($self, $myconfig, $form, $item, $level) = @_; my $module = $form->{script}; my $action = "section_menu"; @@ -56,9 +56,10 @@ sub menuitem { if ($self->{$item}{target}) { $target = $self->{$item}{target}; } + + $level = $form->escape($item); + my $str = qq|{path}&action=$action&level=$level&login=$form->{login}&timeout=$form->{timeout}&sessionid=$form->{sessionid}|; - my $level = $form->escape($item); - my $str = qq|{path}&action=$action&level=$level&login=$form->{login}&password=$form->{password}|; my @vars = qw(module action target href); if ($self->{$item}{href}) { @@ -68,20 +69,23 @@ sub menuitem { map { delete $self->{$item}{$_} } @vars; - + delete $self->{$item}{submenu}; + # add other params foreach my $key (keys %{ $self->{$item} }) { - $str .= "&".$form->escape($key,1)."="; + $str .= "&".$form->escape($key)."="; ($value, $conf) = split /=/, $self->{$item}{$key}, 2; $value = $myconfig->{$value}."/$conf" if ($conf); - $str .= $form->escape($value, 1); + $str .= $form->escape($value); } + $str .= qq|#id$form->{tag}| if $target eq 'acc_menu'; + if ($target) { $str .= qq| target=$target|; } - - $str .= ">"; + + $str .= qq|>|; } diff --git a/sql-ledger/SL/Num2text.pm b/sql-ledger/SL/Num2text.pm index f09121c23..06eee7183 100644 --- a/sql-ledger/SL/Num2text.pm +++ b/sql-ledger/SL/Num2text.pm @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2002 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -77,7 +77,7 @@ sub num2text { my @textnumber = (); # split amount into chunks of 3 - my @num = reverse split //, $amount; + my @num = reverse split //, abs($amount); my @numblock = (); my @a; my $i; diff --git a/sql-ledger/SL/OE.pm b/sql-ledger/SL/OE.pm index a742ca7a2..dfa424c31 100644 --- a/sql-ledger/SL/OE.pm +++ b/sql-ledger/SL/OE.pm @@ -23,6 +23,7 @@ #====================================================================== # # Order entry module +# Quotation # #====================================================================== @@ -36,46 +37,133 @@ sub transactions { my $dbh = $form->dbconnect($myconfig); my $query; + my $ordnumber = 'ordnumber'; + my $quotation = '0'; + my ($null, $department_id) = split /--/, $form->{department}; + my $department = " AND o.department_id = $department_id" if $department_id; + my $rate = ($form->{vc} eq 'customer') ? 'buy' : 'sell'; + + ($form->{transdatefrom}, $form->{transdateto}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month}; + + if ($form->{type} =~ /_quotation$/) { + $quotation = '1'; + $ordnumber = 'quonumber'; + } + my $number = $form->like(lc $form->{$ordnumber}); + my $name = $form->like(lc $form->{$form->{vc}}); + my $query = qq|SELECT o.id, o.ordnumber, o.transdate, o.reqdate, o.amount, ct.name, o.netamount, o.$form->{vc}_id, - (SELECT $rate FROM exchangerate ex - WHERE ex.curr = o.curr - AND ex.transdate = o.transdate) AS exchangerate, - o.closed - FROM oe o, $form->{vc} ct - WHERE o.$form->{vc}_id = ct.id|; - - my $ordnumber = $form->like(lc $form->{ordnumber}); + ex.$rate AS exchangerate, + o.closed, o.quonumber, o.shippingpoint, o.shipvia, + e.name AS employee, m.name AS manager, o.curr + FROM oe o + JOIN $form->{vc} ct ON (o.$form->{vc}_id = ct.id) + LEFT JOIN employee e ON (o.employee_id = e.id) + LEFT JOIN employee m ON (e.managerid = m.id) + LEFT JOIN exchangerate ex ON (ex.curr = o.curr + AND ex.transdate = o.transdate) + WHERE o.quotation = '$quotation' + $department|; + + my %ordinal = ( 'id' => 1, + 'ordnumber' => 2, + 'transdate' => 3, + 'reqdate' => 4, + 'name' => 6, + 'quonumber' => 11, + 'shipvia' => 13, + 'employee' => 14, + 'manager' => 15 + ); + + my @a = (transdate, $ordnumber, name); + push @a, "employee" if $form->{l_employee}; + if ($form->{type} !~ /(ship|receive)_order/) { + push @a, "manager" if $form->{l_manager}; + } + my $sortorder = $form->sort_order(\@a, \%ordinal); + + # build query if type eq (ship|receive)_order + if ($form->{type} =~ /(ship|receive)_order/) { + + my ($warehouse, $warehouse_id) = split /--/, $form->{warehouse}; + + $query = qq|SELECT DISTINCT o.id, o.ordnumber, o.transdate, + o.reqdate, o.amount, ct.name, o.netamount, o.$form->{vc}_id, + ex.$rate AS exchangerate, + o.closed, o.quonumber, o.shippingpoint, o.shipvia, + e.name AS employee, o.curr + FROM oe o + JOIN $form->{vc} ct ON (o.$form->{vc}_id = ct.id) + JOIN orderitems oi ON (oi.trans_id = o.id) + JOIN parts p ON (p.id = oi.parts_id)|; + + if ($warehouse_id && $form->{type} eq 'ship_order') { + $query .= qq| + JOIN inventory i ON (oi.parts_id = i.parts_id) + |; + } + + $query .= qq| + LEFT JOIN employee e ON (o.employee_id = e.id) + LEFT JOIN exchangerate ex ON (ex.curr = o.curr + AND ex.transdate = o.transdate) + WHERE o.quotation = '0' + AND (p.inventory_accno_id > 0 OR p.assembly = '1') + AND oi.qty != oi.ship + $department|; + + if ($warehouse_id && $form->{type} eq 'ship_order') { + $query .= qq| + AND i.warehouse_id = $warehouse_id + AND i.qty >= (oi.qty - oi.ship) + |; + } + + } + if ($form->{"$form->{vc}_id"}) { $query .= qq| AND o.$form->{vc}_id = $form->{"$form->{vc}_id"}|; } else { if ($form->{$form->{vc}}) { - my $name = $form->like(lc $form->{$form->{vc}}); - $query .= " AND lower(name) LIKE '$name'"; + $query .= " AND lower(ct.name) LIKE '$name'"; } } - unless ($form->{open} && $form->{closed}) { + if (!$form->{open} && !$form->{closed}) { + $query .= " AND o.id = 0"; + } elsif (!($form->{open} && $form->{closed})) { $query .= ($form->{open}) ? " AND o.closed = '0'" : " AND o.closed = '1'"; } - my $sortorder = join ', ', $form->sort_columns(qw(transdate ordnumber name)); - $sortorder = $form->{sort} unless $sortorder; - - $query .= " AND lower(ordnumber) LIKE '$ordnumber'" if $form->{ordnumber}; - $query .= " AND transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom}; - $query .= " AND transdate <= '$form->{transdateto}'" if $form->{transdateto}; + if ($form->{$ordnumber}) { + $query .= " AND lower($ordnumber) LIKE '$number'"; + } + if ($form->{shipvia}) { + $var = $form->like(lc $form->{shipvia}); + $query .= " AND lower(o.shipvia) LIKE '$var'"; + } + if ($form->{transdatefrom}) { + $query .= " AND o.transdate >= '$form->{transdatefrom}'"; + } + if ($form->{transdateto}) { + $query .= " AND o.transdate <= '$form->{transdateto}'"; + } + $query .= " ORDER by $sortorder"; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $oe = $sth->fetchrow_hashref(NAME_lc)) { - $oe->{exchangerate} = 1 unless $oe->{exchangerate}; - push @{ $form->{OE} }, $oe; + my %id = (); + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + $ref->{exchangerate} = 1 unless $ref->{exchangerate}; + push @{ $form->{OE} }, $ref if $ref->{id} != $id{$ref->{id}}; + $id{$ref->{id}} = $ref->{id}; } $sth->finish; @@ -84,17 +172,29 @@ sub transactions { } -sub save_order { +sub save { my ($self, $myconfig, $form) = @_; # connect to database, turn off autocommit my $dbh = $form->dbconnect_noauto($myconfig); - my ($query, $sth); + my $query; + my $sth; + my $null; my $exchangerate = 0; + ($null, $form->{employee_id}) = split /--/, $form->{employee}; + unless ($form->{employee_id}) { + ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh); + $form->{employee} = "$form->{employee}--$form->{employee_id}"; + } + + my $ml = ($form->{type} eq 'sales_order') ? 1 : -1; + if ($form->{id}) { - + + &adj_onhand($dbh, $form, $ml) if $form->{type} =~ /_order$/; + $query = qq|DELETE FROM orderitems WHERE trans_id = $form->{id}|; $dbh->do($query) || $form->dberror($query); @@ -108,8 +208,7 @@ sub save_order { $uid .= $form->{login}; $query = qq|INSERT INTO oe (ordnumber, employee_id) - VALUES ('$uid', (SELECT id FROM employee - WHERE login = '$form->{login}') )|; + VALUES ('$uid', $form->{employee_id})|; $dbh->do($query) || $form->dberror($query); $query = qq|SELECT id FROM oe @@ -119,28 +218,30 @@ sub save_order { ($form->{id}) = $sth->fetchrow_array; $sth->finish; + } - map { $form->{$_} =~ s/'/''/g } qw(ordnumber shippingpoint notes message); - - my ($amount, $linetotal, $discount, $project_id, $reqdate); - my ($taxrate, $taxamount, $fxsellprice); - my %taxbase = (); - my %taxaccounts = (); - my ($netamount, $tax) = (0, 0); + my $amount; + my $linetotal; + my $discount; + my $project_id; + my $taxrate; + my $taxamount; + my $fxsellprice; + my %taxbase; + my @taxaccounts; + my %taxaccounts; + my $netamount = 0; for my $i (1 .. $form->{rowcount}) { - - $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}); - - if ($form->{"qty_$i"} != 0) { - - map { $form->{"${_}_$i"} =~ s/'/''/g } qw(partnumber description unit); - - # set values to 0 if nothing entered - $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100; - $form->{"sellprice_$i"} = $form->parse_amount($myconfig, $form->{"sellprice_$i"}); + map { $form->{"${_}_$i"} = $form->parse_amount($myconfig, $form->{"${_}_$i"}) } qw(qty ship); + + $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100; + $form->{"sellprice_$i"} = $form->parse_amount($myconfig, $form->{"sellprice_$i"}); + + if ($form->{"qty_$i"}) { + $fxsellprice = $form->{"sellprice_$i"}; my ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/); @@ -150,9 +251,16 @@ sub save_order { $discount = $form->round_amount($form->{"sellprice_$i"} * $form->{"discount_$i"}, $decimalplaces); $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} - $discount, $decimalplaces); + $form->{"inventory_accno_$i"} *= 1; + $form->{"expense_accno_$i"} *= 1; + $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2); + + @taxaccounts = split / /, $form->{"taxaccounts_$i"}; $taxrate = 0; - map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{"taxaccounts_$i"}; + $taxdiff = 0; + + map { $taxrate += $form->{"${_}_rate"} } @taxaccounts; if ($form->{taxincluded}) { $taxamount = $linetotal * $taxrate / (1 + $taxrate); @@ -164,28 +272,54 @@ sub save_order { $taxbase = $linetotal; } - if ($taxamount != 0) { - foreach my $item (split / /, $form->{"taxaccounts_$i"}) { + if (@taxaccounts && $form->round_amount($taxamount, 2) == 0) { + if ($form->{taxincluded}) { + foreach $item (@taxaccounts) { + $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2); + + $taxaccounts{$item} += $taxamount; + $taxdiff += $taxamount; + + $taxbase{$item} += $taxbase; + } + $taxaccounts{$taxaccounts[0]} += $taxdiff; + } else { + foreach $item (@taxaccounts) { + $taxaccounts{$item} += $linetotal * $form->{"${item}_rate"}; + $taxbase{$item} += $taxbase; + } + } + } else { + foreach $item (@taxaccounts) { $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate; $taxbase{$item} += $taxbase; } } - + + $netamount += $form->{"sellprice_$i"} * $form->{"qty_$i"}; $project_id = 'NULL'; - if ($form->{"project_id_$i"}) { - $project_id = $form->{"project_id_$i"}; + if ($form->{"projectnumber_$i"}) { + ($null, $project_id) = split /--/, $form->{"projectnumber_$i"}; + $project_id *= 1; } - $reqdate = ($form->{"reqdate_$i"}) ? qq|'$form->{"reqdate_$i"}'| : "NULL"; # save detail record in orderitems table - $query = qq|INSERT INTO orderitems - (trans_id, parts_id, description, qty, sellprice, discount, - unit, reqdate, project_id) VALUES ( - $form->{id}, $form->{"id_$i"}, '$form->{"description_$i"}', - $form->{"qty_$i"}, $fxsellprice, $form->{"discount_$i"}, - '$form->{"unit_$i"}', $reqdate, $project_id)|; + $query = qq|INSERT INTO orderitems (|; + $query .= "id, " if $form->{"orderitems_id_$i"}; + $query .= qq|trans_id, parts_id, description, qty, sellprice, discount, + unit, reqdate, project_id, serialnumber, ship) + VALUES (|; + $query .= qq|$form->{"orderitems_id_$i"},| if $form->{"orderitems_id_$i"}; + $query .= qq|$form->{id}, $form->{"id_$i"}, | + .$dbh->quote($form->{"description_$i"}).qq|, + $form->{"qty_$i"}, $fxsellprice, $form->{"discount_$i"}, | + .$dbh->quote($form->{"unit_$i"}).qq|, | + .$form->dbquote($form->{"reqdate_$i"}, SQL_DATE).qq|, + $project_id, | + .$dbh->quote($form->{"serialnumber_$i"}).qq|, + $form->{"ship_$i"})|; $dbh->do($query) || $form->dberror($query); $form->{"sellprice_$i"} = $fxsellprice; @@ -195,15 +329,11 @@ sub save_order { # set values which could be empty - map { $form->{$_} *= 1 } qw(vendor_id customer_id taxincluded closed); + map { $form->{$_} *= 1 } qw(vendor_id customer_id taxincluded closed quotation); - $reqdate = ($form->{reqdate}) ? qq|'$form->{reqdate}'| : "NULL"; - # add up the tax - foreach my $item (sort keys %taxaccounts) { - $taxamount = $form->round_amount($taxaccounts{$item}, 2); - $tax += $taxamount; - } + my $tax = 0; + map { $tax += $form->round_amount($taxaccounts{$_}, 2) } keys %taxaccounts; $amount = $form->round_amount($netamount + $tax, 2); $netamount = $form->round_amount($netamount, 2); @@ -216,33 +346,32 @@ sub save_order { $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate}); - # fill in subject if there is none - $form->{subject} = qq|$form->{label} $form->{ordnumber}| unless $form->{subject}; - # if there is a message stuff it into the notes - my $cc = "Cc: $form->{cc}\\r\n" if $form->{cc}; - my $bcc = "Bcc: $form->{bcc}\\r\n" if $form->{bcc}; - $form->{notes} .= qq|\r -\r -[email]\r -To: $form->{email}\r -$cc${bcc}Subject: $form->{subject}\r -\r -Message: $form->{message}\r| if $form->{message}; + my $quotation = ($form->{type} =~ /_order$/) ? '0' : '1'; + + ($null, $form->{department_id}) = split(/--/, $form->{department}); + $form->{department_id} *= 1; # save OE record $query = qq|UPDATE oe set - ordnumber = '$form->{ordnumber}', - transdate = '$form->{orddate}', + ordnumber = |.$dbh->quote($form->{ordnumber}).qq|, + quonumber = |.$dbh->quote($form->{quonumber}).qq|, + transdate = '$form->{transdate}', vendor_id = $form->{vendor_id}, customer_id = $form->{customer_id}, amount = $amount, netamount = $netamount, - reqdate = $reqdate, + reqdate = |.$form->dbquote($form->{reqdate}, SQL_DATE).qq|, taxincluded = '$form->{taxincluded}', - shippingpoint = '$form->{shippingpoint}', - notes = '$form->{notes}', + shippingpoint = |.$dbh->quote($form->{shippingpoint}).qq|, + shipvia = |.$dbh->quote($form->{shipvia}).qq|, + notes = |.$dbh->quote($form->{notes}).qq|, + intnotes = |.$dbh->quote($form->{intnotes}).qq|, curr = '$form->{currency}', - closed = '$form->{closed}' + closed = '$form->{closed}', + quotation = '$quotation', + department_id = $form->{department_id}, + employee_id = $form->{employee_id}, + language_code = '$form->{language_code}' WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); @@ -252,16 +381,34 @@ Message: $form->{message}\r| if $form->{message}; $form->{name} = $form->{$form->{vc}}; $form->{name} =~ s/--$form->{"$form->{vc}_id"}//; $form->add_shipto($dbh, $form->{id}); - + + # save printed, emailed, queued + $form->save_status($dbh); + if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) { if ($form->{vc} eq 'customer') { - $form->update_exchangerate($dbh, $form->{currency}, $form->{orddate}, $form->{exchangerate}, 0); + $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, $form->{exchangerate}, 0); } if ($form->{vc} eq 'vendor') { - $form->update_exchangerate($dbh, $form->{currency}, $form->{orddate}, 0, $form->{exchangerate}); + $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, 0, $form->{exchangerate}); } } + + if ($form->{type} =~ /_order$/) { + # adjust onhand + &adj_onhand($dbh, $form, $ml * -1); + &adj_inventory($dbh, $myconfig, $form); + } + + my %audittrail = ( tablename => 'oe', + reference => ($form->{type} =~ /_order$/) ? $form->{ordnumber} : $form->{quonumber}, + formname => $form->{type}, + action => 'saved', + id => $form->{id} ); + + $form->audittrail($dbh, "", \%audittrail); + my $rc = $dbh->commit; $dbh->disconnect; @@ -271,38 +418,56 @@ Message: $form->{message}\r| if $form->{message}; -sub delete_order { - my ($self, $myconfig, $form) = @_; +sub delete { + my ($self, $myconfig, $form, $spool) = @_; # connect to database my $dbh = $form->dbconnect_noauto($myconfig); - my $query; + # delete spool files + my $query = qq|SELECT spoolfile FROM status + WHERE trans_id = $form->{id} + AND spoolfile IS NOT NULL|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); - # can't use $form->delete_exchangerate - if ($form->{currency} ne $form->{defaultcurrency}) { - $query = qq|SELECT transdate FROM acc_trans - WHERE ar.id = trans_id - AND ar.curr = '$form->{currency}' - AND transdate = '$form->{orddate}' - UNION SELECT transdate FROM acc_trans - WHERE ap.id = trans_id - AND ap.curr = '$form->{currency}' - AND transdate = '$form->{orddate}'|; - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - my ($transdate) = $sth->fetchrow_array; - $sth->finish; + my $spoolfile; + my @spoolfiles = (); + + while (($spoolfile) = $sth->fetchrow_array) { + push @spoolfiles, $spoolfile; + } + $sth->finish; + + + $query = qq|SELECT o.parts_id, o.ship, p.inventory_accno_id + FROM orderitems o + JOIN parts p ON (p.id = o.parts_id) + WHERE trans_id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); - if (!$transdate) { - $query = qq|DELETE FROM exchangerate - WHERE curr = '$form->{currency}' - AND transdate = '$form->{orddate}'|; - $dbh->do($query) || $self->dberror($query); + if ($form->{type} =~ /_order$/) { + $ml = ($form->{type} eq 'purchase_order') ? -1 : 1; + while (my ($id, $ship, $inv) = $sth->fetchrow_array) { + $form->update_balance($dbh, + "parts", + "onhand", + qq|id = $id|, + $ship * $ml) if $inv; } } - + $sth->finish; + + # delete inventory + $query = qq|DELETE FROM inventory + WHERE oe_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + # delete status entries + $query = qq|DELETE FROM status + WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); # delete OE record $query = qq|DELETE FROM oe @@ -318,22 +483,37 @@ sub delete_order { WHERE trans_id = $form->{id}|; $dbh->do($query) || $form->dberror($query); + my %audittrail = ( tablename => 'oe', + reference => ($form->{type} =~ /_order$/) ? $form->{ordnumber} : $form->{quonumber}, + formname => $form->{type}, + action => 'deleted', + id => $form->{id} ); + + $form->audittrail($dbh, "", \%audittrail); + my $rc = $dbh->commit; $dbh->disconnect; + if ($rc) { + foreach $spoolfile (@spoolfiles) { + unlink "$spool/$spoolfile" if $spoolfile; + } + } + $rc; } -sub retrieve_order { +sub retrieve { my ($self, $myconfig, $form) = @_; # connect to database - my $dbh = $form->dbconnect_noauto($myconfig); + my $dbh = $form->dbconnect($myconfig); my $query; + my $var; if ($form->{id}) { # get default accounts and last order number @@ -350,7 +530,6 @@ sub retrieve_order { d.curr AS currencies FROM defaults d|; } else { - my $ordnumber = ($form->{vc} eq 'customer') ? 'sonumber' : 'ponumber'; $query = qq|SELECT (SELECT c.accno FROM chart c WHERE d.inventory_accno_id = c.id) AS inventory_accno, (SELECT c.accno FROM chart c @@ -361,8 +540,8 @@ sub retrieve_order { 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, - $ordnumber AS ordnumber, d.curr AS currencies, - current_date AS orddate, current_date AS reqdate + d.curr AS currencies, + current_date AS transdate FROM defaults d|; } my $sth = $dbh->prepare($query); @@ -372,20 +551,21 @@ sub retrieve_order { map { $form->{$_} = $ref->{$_} } keys %$ref; $sth->finish; - ($form->{currency}) = split /:/, $form->{currencies}; if ($form->{id}) { # retrieve order - $query = qq|SELECT o.ordnumber, o.transdate AS orddate, o.reqdate, - o.taxincluded, o.shippingpoint, o.notes, o.curr AS currency, - (SELECT name FROM employee e - WHERE e.id = o.employee_id) AS employee, + $query = qq|SELECT o.ordnumber, o.transdate, o.reqdate, + o.taxincluded, o.shippingpoint, o.shipvia, o.notes, o.intnotes, + o.curr AS currency, e.name AS employee, o.employee_id, o.$form->{vc}_id, cv.name AS $form->{vc}, o.amount AS invtotal, - o.closed, o.reqdate - FROM oe o, $form->{vc} cv - WHERE o.$form->{vc}_id = cv.id - AND o.id = $form->{id}|; + o.closed, o.reqdate, o.quonumber, o.department_id, + d.description AS department, o.language_code + FROM oe o + JOIN $form->{vc} cv ON (o.$form->{vc}_id = cv.id) + LEFT JOIN employee e ON (o.employee_id = e.id) + LEFT JOIN department d ON (o.department_id = d.id) + WHERE o.id = $form->{id}|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -402,20 +582,41 @@ sub retrieve_order { $ref = $sth->fetchrow_hashref(NAME_lc); map { $form->{$_} = $ref->{$_} } keys %$ref; $sth->finish; - + + # get printed, emailed and queued + $query = qq|SELECT s.printed, s.emailed, s.spoolfile, s.formname + FROM status s + WHERE s.trans_id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + $form->{printed} .= "$ref->{formname} " if $ref->{printed}; + $form->{emailed} .= "$ref->{formname} " if $ref->{emailed}; + $form->{queued} .= "$ref->{formname} $ref->{spoolfile} " if $ref->{spoolfile}; + } + $sth->finish; + map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued); + + my %oid = ( 'Pg' => 'oid', + 'PgPP' => 'oid', 'Oracle' => 'rowid', - 'DB2' => '' ); + 'DB2' => '1=1' + ); # retrieve individual items - $query = qq|SELECT c1.accno AS inventory_accno, - c2.accno AS income_accno, - c3.accno AS expense_accno, + $query = qq|SELECT o.id AS orderitems_id, + c1.accno AS inventory_accno, + c2.accno AS income_accno, + c3.accno AS expense_accno, p.partnumber, p.assembly, o.description, o.qty, o.sellprice, o.parts_id AS id, o.unit, o.discount, p.bin, - o.reqdate, o.project_id, + o.reqdate, o.project_id, o.serialnumber, o.ship, pr.projectnumber, - pg.partsgroup + pg.partsgroup, p.partsgroup_id, p.partnumber AS sku, + p.listprice, p.lastcost, p.weight, + t.description AS partsgrouptranslation FROM orderitems o JOIN parts p ON (o.parts_id = p.id) LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id) @@ -423,116 +624,401 @@ sub retrieve_order { LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id) LEFT JOIN project pr ON (o.project_id = pr.id) LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) - WHERE trans_id = $form->{id} + LEFT JOIN translation t ON (t.trans_id = p.partsgroup_id AND t.language_code = '$form->{language_code}') + WHERE o.trans_id = $form->{id} ORDER BY o.$oid{$myconfig->{dbdriver}}|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); + # foreign exchange rates + &exchangerate_defaults($dbh, $form); + + # query for price matrix + my $pmh = &price_matrix_query($dbh, $form); + + # taxes + $query = qq|SELECT c.accno + FROM chart c + JOIN partstax pt ON (pt.chart_id = c.id) + WHERE pt.parts_id = ?|; + my $tth = $dbh->prepare($query) || $form->dberror($query); + + my $taxrate; + my $ptref; + my $sellprice; + my $listprice; + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { - # get tax rates for part - $query = qq|SELECT c.accno - FROM chart c, partstax pt - WHERE pt.chart_id = c.id - AND pt.parts_id = $ref->{id}|; - my $pth = $dbh->prepare($query); - $pth->execute || $form->dberror($query); + ($decimalplaces) = ($ref->{sellprice} =~ /\.(\d+)/); + $decimalplaces = length $decimalplaces; + $decimalplaces = 2 unless $decimalplaces; + $tth->execute($ref->{id}); $ref->{taxaccounts} = ""; - my $taxrate = 0; + $taxrate = 0; - while (my $ptref = $pth->fetchrow_hashref(NAME_lc)) { + while ($ptref = $tth->fetchrow_hashref(NAME_lc)) { $ref->{taxaccounts} .= "$ptref->{accno} "; $taxrate += $form->{"$ptref->{accno}_rate"}; } - $pth->finish; + $tth->finish; chop $ref->{taxaccounts}; - push @{ $form->{order_details} }, $ref; + # preserve prices + $sellprice = $ref->{sellprice}; + $listprice = $ref->{listprice}; + + # multiply by exchangerate + $ref->{sellprice} = $form->round_amount($ref->{sellprice} * $form->{$form->{currency}}, $decimalplaces); + $ref->{listprice} = $form->round_amount($ref->{listprice} * $form->{$form->{currency}}, $decimalplaces); + + # partnumber and price matrix + &price_matrix($pmh, $ref, $form->{transdate}, $decimalplaces, $form, $myconfig, 1); + + $ref->{sellprice} = $sellprice; + $ref->{listprice} = $listprice; + + $ref->{partsgroup} = $ref->{partsgrouptranslation} if $ref->{partsgrouptranslation}; + + push @{ $form->{form_details} }, $ref; } $sth->finish; } else { - my $ordnumber = ($form->{vc} eq 'customer') ? 'sonumber' : 'ponumber'; - # up order number by 1 - $form->{ordnumber}++; - - # save the new number - $query = qq|UPDATE defaults - SET $ordnumber = '$form->{ordnumber}'|; - $dbh->do($query) || $form->dberror($query); - - $form->get_employee($dbh); - # get last name used $form->lastname_used($dbh, $myconfig, $form->{vc}) unless $form->{"$form->{vc}_id"}; + delete $form->{notes}; } + + $dbh->disconnect; + +} + + +sub price_matrix_query { + my ($dbh, $form) = @_; + + my $query; + my $sth; + + if ($form->{customer_id}) { + $query = qq|SELECT p.*, g.pricegroup + FROM partscustomer p + LEFT JOIN pricegroup g ON (g.id = p.pricegroup_id) + WHERE p.parts_id = ? + AND p.customer_id = $form->{customer_id} + + UNION + + SELECT p.*, g.pricegroup + FROM partscustomer p + LEFT JOIN pricegroup g ON (g.id = p.pricegroup_id) + JOIN customer c ON (c.pricegroup_id = g.id) + WHERE p.parts_id = ? + AND c.id = $form->{customer_id} + + UNION + + SELECT p.*, '' AS pricegroup + FROM partscustomer p + WHERE p.customer_id = 0 + AND p.pricegroup_id = 0 + AND p.parts_id = ? + + ORDER BY customer_id DESC, pricegroup_id DESC, pricebreak + |; + $sth = $dbh->prepare($query) || $form->dberror($query); + } - $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{orddate}, ($form->{vc} eq 'customer') ? "buy" : "sell"); + if ($form->{vendor_id}) { + # price matrix and vendor's partnumber + $query = qq|SELECT partnumber + FROM partsvendor + WHERE parts_id = ? + AND vendor_id = $form->{vendor_id}|; + $sth = $dbh->prepare($query) || $form->dberror($query); + } - my $rc = $dbh->commit; - $dbh->disconnect; + $sth; - $rc; +} + + +sub price_matrix { + my ($pmh, $ref, $transdate, $decimalplaces, $form, $myconfig, $init) = @_; + + $ref->{pricematrix} = ""; + my $customerprice = 0; + my $pricegroup = 0; + my $sellprice; + my $mref; + # depends if this is a customer or vendor + if ($form->{customer_id}) { + $pmh->execute($ref->{id}, $ref->{id}, $ref->{id}); + + while ($mref = $pmh->fetchrow_hashref(NAME_lc)) { + + # check date + if ($mref->{validfrom}) { + next if $transdate < $form->datetonum($mref->{validfrom}, $myconfig); + } + if ($mref->{validto}) { + next if $transdate > $form->datetonum($mref->{validto}, $myconfig); + } + + # convert price + $sellprice = $form->round_amount($mref->{sellprice} * $form->{$mref->{curr}}, $decimalplaces); + + if ($mref->{customer_id}) { + $ref->{sellprice} = $sellprice unless $mref->{pricebreak}; + $ref->{pricematrix} .= "$mref->{pricebreak}:$sellprice "; + $customerprice = 1; + } + + if ($mref->{pricegroup_id}) { + if (! $customerprice) { + $ref->{sellprice} = $sellprice unless $mref->{pricebreak}; + $ref->{pricematrix} .= "$mref->{pricebreak}:$sellprice "; + $pricegroup = 1; + } + } + + if (! $customerprice && ! $pricegroup) { + $ref->{sellprice} = $sellprice unless $mref->{pricebreak}; + $ref->{pricematrix} .= "$mref->{pricebreak}:$sellprice "; + } + + } + $pmh->finish; + + if ($ref->{pricematrix} !~ /^0:/) { + if ($init) { + $sellprice = $form->round_amount($ref->{sellprice}, $decimalplaces); + } else { + $sellprice = $form->round_amount($ref->{sellprice} * (1 - $form->{tradediscount}), $decimalplaces); + } + $ref->{pricematrix} = "0:$sellprice ".$ref->{pricematrix}; + } + chop $ref->{pricematrix}; + + } + + + if ($form->{vendor_id}) { + $pmh->execute($ref->{id}); + + $mref = $pmh->fetchrow_hashref(NAME_lc); + + if ($mref->{partnumber}) { + $ref->{partnumber} = $mref->{partnumber}; + } + + if ($mref->{lastcost}) { + # do a conversion + $ref->{sellprice} = $form->round_amount($mref->{lastcost} * $form->{$mref->{curr}}, $decimalplaces); + } + $pmh->finish; + + $ref->{sellprice} *= 1; + + # add 0:price to matrix + $ref->{pricematrix} = "0:$ref->{sellprice}"; + + } + } +sub exchangerate_defaults { + my ($dbh, $form) = @_; + + my $var; + my $buysell = ($form->{vc} eq "customer") ? "buy" : "sell"; + + # get default currencies + my $query = qq|SELECT substr(curr,1,3), curr FROM defaults|; + my $eth = $dbh->prepare($query) || $form->dberror($query); + $eth->execute; + ($form->{defaultcurrency}, $form->{currencies}) = $eth->fetchrow_array; + $eth->finish; + + $query = qq|SELECT $buysell + FROM exchangerate + WHERE curr = ? + AND transdate = ?|; + my $eth1 = $dbh->prepare($query) || $form->dberror($query); + $query = qq~SELECT max(transdate || ' ' || $buysell || ' ' || curr) + FROM exchangerate + WHERE curr = ?~; + my $eth2 = $dbh->prepare($query) || $form->dberror($query); + + # get exchange rates for transdate or max + foreach $var (split /:/, substr($form->{currencies},4)) { + $eth1->execute($var, $form->{transdate}); + ($form->{$var}) = $eth1->fetchrow_array; + if (! $form->{$var} ) { + $eth2->execute($var); + + ($form->{$var}) = $eth2->fetchrow_array; + ($null, $form->{$var}) = split / /, $form->{$var}; + $form->{$var} = 1 unless $form->{$var}; + $eth2->finish; + } + $eth1->finish; + } + + $form->{$form->{defaultcurrency}} = 1; + +} + sub order_details { my ($self, $myconfig, $form) = @_; # connect to database my $dbh = $form->dbconnect($myconfig); + my $query; + my $sth; - my $tax = 0; my $item; my $i; - my @partsgroup = (); + my @sortlist = (); + my $projectnumber; + my $projectnumber_id; + my $translation; my $partsgroup; - my %oid = ( 'Pg' => 'oid', - 'Oracle' => 'rowid' ); - # sort items by partsgroup + my %oid = ( 'Pg' => 'oid', + 'PgPP' => 'oid', + 'Oracle' => 'rowid', + 'DB2' => '1=1' + ); + + # sort items by project and partsgroup for $i (1 .. $form->{rowcount}) { + $projectnumber = ""; $partsgroup = ""; - if ($form->{"partsgroup_$i"} && $form->{groupitems}) { - $form->format_string("partsgroup_$i"); - $partsgroup = $form->{"partsgroup_$i"}; + $projectnumber_id = 0; + if ($form->{"projectnumber_$i"} && $form->{groupprojectnumber}) { + ($projectnumber, $projectnumber_id) = split /--/, $form->{"projectnumber_$i"}; + } + if ($form->{"partsgroup_$i"} && $form->{grouppartsgroup}) { + ($partsgroup) = split /--/, $form->{"partsgroup_$i"}; } - push @partsgroup, [ $i, $partsgroup ]; + push @sortlist, [ $i, "$projectnumber$partsgroup", $projectnumber, $projectnumber_id, $partsgroup ]; + + # sort the whole thing by project and group + @sortlist = sort { $a->[1] cmp $b->[1] } @sortlist; + } - + + # if there is a warehouse limit picking + if ($form->{warehouse_id} && $form->{formname} =~ /(pick|packing)_list/) { + # run query to check for inventory + $query = qq|SELECT sum(qty) AS qty + FROM inventory + WHERE parts_id = ? + AND warehouse_id = ?|; + $sth = $dbh->prepare($query) || $form->dberror($query); + + for $i (1 .. $form->{rowcount}) { + $sth->execute($form->{"id_$i"}, $form->{warehouse_id}) || $form->dberror; + + ($qty) = $sth->fetchrow_array; + $sth->finish; + + $form->{"qty_$i"} = 0 if $qty == 0; + + if ($form->parse_amount($myconfig, $form->{"ship_$i"}) > $qty) { + $form->{"ship_$i"} = $form->format_amount($myconfig, $qty); + } + } + } + + my @taxaccounts; + my %taxaccounts; + my $taxrate; + my $taxamount; + my $taxbase; + my $taxdiff; + + $query = qq|SELECT p.description, t.description + FROM project p + LEFT JOIN translation t ON (t.trans_id = p.id AND t.language_code = '$form->{language_code}') + WHERE id = ?|; + my $prh = $dbh->prepare($query) || $form->dberror($query); + + my $runningnumber = 1; my $sameitem = ""; - foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) { + my $subtotal; + my $k = scalar @sortlist; + my $j = 0; + + foreach $item (@sortlist) { $i = $item->[0]; + $j++; + + if ($form->{groupprojectnumber} || $form->{grouppartsgroup}) { + if ($item->[1] ne $sameitem) { - if ($item->[1] ne $sameitem) { - push(@{ $form->{description} }, qq|$item->[1]|); - $sameitem = $item->[1]; + $projectnumber = ""; + if ($form->{groupprojectnumber} && $item->[2]) { + # get project description + $prh->execute($item->[3]) || $form->dberror($query); + + ($projectnumber, $translation) = $prh->fetchrow_array; + $prh->finish; + + $projectnumber = ($translation) ? "$item->[2], $translation" : "$item->[2], $projectnumber"; + } + + if ($form->{grouppartsgroup} && $item->[4]) { + $projectnumber .= " / " if $projectnumber; + $projectnumber .= $item->[4]; + } + + $form->{projectnumber} = $projectnumber; + $form->format_string(projectnumber); + + push(@{ $form->{description} }, qq|$form->{projectnumber}|); + $sameitem = $item->[1]; - map { push(@{ $form->{$_} }, "") } qw(runningnumber number bin qty unit reqdate sellprice listprice netprice discount linetotal); + map { push(@{ $form->{$_} }, "") } qw(runningnumber number sku qty ship unit bin serialnumber reqdate projectnumber sellprice listprice netprice discount discountrate linetotal weight); + } } $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}); if ($form->{"qty_$i"} != 0) { + $form->{totalqty} += $form->{"qty_$i"}; + $form->{totalship} += $form->{"ship_$i"}; + $form->{totalweight} += ($form->{"weight_$i"} * $form->{"qty_$i"}); + # add number, description and qty to $form->{number}, .... - push(@{ $form->{runningnumber} }, $i); + push(@{ $form->{runningnumber} }, $runningnumber++); push(@{ $form->{number} }, qq|$form->{"partnumber_$i"}|); + push(@{ $form->{sku} }, qq|$form->{"sku_$i"}|); push(@{ $form->{description} }, qq|$form->{"description_$i"}|); push(@{ $form->{qty} }, $form->format_amount($myconfig, $form->{"qty_$i"})); + push(@{ $form->{ship} }, $form->format_amount($myconfig, $form->{"ship_$i"})); push(@{ $form->{unit} }, qq|$form->{"unit_$i"}|); + push(@{ $form->{bin} }, qq|$form->{"bin_$i"}|); + push(@{ $form->{serialnumber} }, qq|$form->{"serialnumber_$i"}|); push(@{ $form->{reqdate} }, qq|$form->{"reqdate_$i"}|); + push(@{ $form->{projectnumber} }, qq|$form->{"projectnumber_$i"}|); push(@{ $form->{sellprice} }, $form->{"sellprice_$i"}); - + push(@{ $form->{listprice} }, $form->{"listprice_$i"}); + push(@{ $form->{weight} }, $form->{"weight_$i"}); + my $sellprice = $form->parse_amount($myconfig, $form->{"sellprice_$i"}); my ($dec) = ($sellprice =~ /\.(\d+)/); $dec = length $dec; @@ -551,13 +1037,16 @@ sub order_details { $linetotal = ($linetotal != 0) ? $linetotal : " "; push(@{ $form->{discount} }, $discount); + push(@{ $form->{discountrate} }, $form->format_amount($myconfig, $form->{"discount_$i"})); $form->{ordtotal} += $linetotal; + # this is for the subtotals for grouping + $subtotal += $linetotal; + push(@{ $form->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2)); - my ($taxamount, $taxbase); - my $taxrate = 0; + $taxrate = 0; map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{"taxaccounts_$i"}; @@ -571,7 +1060,7 @@ sub order_details { } - if ($taxamount != 0) { + if ($form->round_amount($taxamount, 2) != 0) { foreach my $item (split / /, $form->{"taxaccounts_$i"}) { $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate; $taxbase{$item} += $taxbase; @@ -579,55 +1068,54 @@ sub order_details { } 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}}|; - } - - $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 = '$form->{"id_$i"}' - $sortorder|; - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { - if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) { - map { push(@{ $form->{$_} }, "") } qw(runningnumber number unit bin qty sellprice listprice netprice discount linetotal); - $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--"; - push(@{ $form->{description} }, $sameitem); + $form->{stagger} = -1; + &assembly_details($dbh, $form, $form->{"id_$i"}, $oid{$myconfig->{dbdriver}}, $form->{"qty_$i"}); + } + + } + + # add subtotal + if ($form->{groupprojectnumber} || $form->{grouppartsgroup}) { + if ($subtotal) { + if ($j < $k) { + # look at next item + if ($sortlist[$j]->[1] ne $sameitem) { + + map { push(@{ $form->{$_} }, "") } qw(runningnumber number sku qty ship unit bin serialnumber reqdate projectnumber sellprice listprice netprice discount discountrate weight); + + push(@{ $form->{description} }, $form->{groupsubtotaldescription}); + + if (exists $form->{groupsubtotaldescription}) { + push(@{ $form->{linetotal} }, $form->format_amount($myconfig, $subtotal, 2)); + } else { + push(@{ $form->{linetotal} }, ""); + } + + $subtotal = 0; } + + } else { + + # got last item + if (exists $form->{groupsubtotaldescription}) { - push(@{ $form->{number} }, qq|$ref->{partnumber}|); - push(@{ $form->{description} }, qq|$ref->{description}|); - push(@{ $form->{unit} }, qq|$ref->{unit}|); - push(@{ $form->{qty} }, $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"})); + map { push(@{ $form->{$_} }, "") } qw(runningnumber number sku qty ship unit bin serialnumber reqdate projectnumber sellprice listprice netprice discount discountrate weight); - map { push(@{ $form->{$_} }, "") } qw(runningnumber bin sellprice listprice netprice discount linetotal); - + push(@{ $form->{description} }, $form->{groupsubtotaldescription}); + push(@{ $form->{linetotal} }, $form->format_amount($myconfig, $subtotal, 2)); + } } - $sth->finish; } - } } + my $tax = 0; foreach $item (sort keys %taxaccounts) { if ($form->round_amount($taxaccounts{$item}, 2) != 0) { push(@{ $form->{taxbase} }, $form->format_amount($myconfig, $taxbase{$item}, 2)); - $taxamount = $form->round_amount($taxaccounts{$item}, 2); - $tax += $taxamount; + $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2); push(@{ $form->{tax} }, $form->format_amount($myconfig, $taxamount, 2)); push(@{ $form->{taxdescription} }, $form->{"${item}_description"}); @@ -636,36 +1124,455 @@ sub order_details { } } - + map { $form->{$_} = $form->format_amount($myconfig, $form->{$_}) } qw(totalqty totalship totalweight); $form->{subtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2); $form->{ordtotal} = ($form->{taxincluded}) ? $form->{ordtotal} : $form->{ordtotal} + $tax; + + use SL::CP; + my $c; + if ($form->{language_code}) { + $c = new CP $form->{language_code}; + } else { + $c = new CP $myconfig->{countrycode}; + } + $c->init; + my $whole; + ($whole, $form->{decimal}) = split /\./, $form->{ordtotal}; + $form->{decimal} .= "00"; + $form->{decimal} = substr($form->{decimal}, 0, 2); + $form->{text_amount} = $c->num2text($whole); # format amounts - $form->{ordtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2); - - # myconfig variables - map { $form->{$_} = $myconfig->{$_} } (qw(company address tel fax signature businessnumber)); - $form->{username} = $myconfig->{name}; + $form->{quototal} = $form->{ordtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2); $dbh->disconnect; } +sub assembly_details { + my ($dbh, $form, $id, $oid, $qty) = @_; + + my $sm = ""; + my $spacer; + + $form->{stagger}++; + if ($form->{format} eq 'html') { + $spacer = " " x (3 * ($form->{stagger} - 1)) if $form->{stagger} > 1; + } + if ($form->{format} =~ /(postscript|pdf)/) { + if ($form->{stagger} > 1) { + $spacer = ($form->{stagger} - 1) * 3; + $spacer = '\rule{'.$spacer.'mm}{0mm}'; + } + } + + # get parts and push them onto the stack + my $sortorder = ""; + + if ($form->{grouppartsgroup}) { + $sortorder = qq|ORDER BY pg.partsgroup, a.$oid|; + } else { + $sortorder = qq|ORDER BY a.$oid|; + } + + my $where = ($form->{formname} eq 'work_order') ? "1 = 1" : "a.bom = '1'"; + + my $query = qq|SELECT p.partnumber, p.description, p.unit, a.qty, + pg.partsgroup, p.partnumber AS sku, p.assembly, p.id, p.bin + FROM assembly a + JOIN parts p ON (a.parts_id = p.id) + LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + WHERE $where + AND a.id = '$id' + $sortorder|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + + if ($form->{grouppartsgroup} && $ref->{partsgroup} ne $sm) { + map { push(@{ $form->{$_} }, "") } qw(number sku unit qty runningnumber ship bin serialnumber reqdate projectnumber sellprice listprice netprice discount discountrate linetotal); + $sm = ($ref->{partsgroup}) ? $ref->{partsgroup} : ""; + push(@{ $form->{description} }, "$spacer$sm"); + } + + if ($form->{stagger}) { + push(@{ $form->{description} }, qq|$spacer$ref->{sku}, $ref->{description}|); + map { push(@{ $form->{$_} }, "") } qw(number sku runningnumber ship serialnumber reqdate projectnumber sellprice listprice netprice discount discountrate linetotal); + } else { + push(@{ $form->{description} }, qq|$ref->{description}|); + push(@{ $form->{sku} }, $ref->{partnumber}); + push(@{ $form->{number} }, $ref->{partnumber}); + + map { push(@{ $form->{$_} }, "") } qw(runningnumber ship serialnumber reqdate projectnumber sellprice listprice netprice discount discountrate linetotal); + } + + push(@{ $form->{qty} }, $form->format_amount($myconfig, $ref->{qty} * $qty)); + map { push(@{ $form->{$_} }, $ref->{$_}) } qw(unit bin); + + + if ($ref->{assembly} && $form->{formname} eq 'work_order') { + &assembly_details($dbh, $form, $ref->{id}, $oid, $ref->{qty} * $qty); + } + + } + $sth->finish; + + $form->{stagger}--; + +} + + sub project_description { my ($self, $dbh, $id) = @_; my $query = qq|SELECT description FROM project WHERE id = $id|; + ($_) = $dbh->selectrow_array; + + $_; + +} + + +sub get_warehouses { + my ($self, $myconfig, $form) = @_; + + my $dbh = $form->dbconnect($myconfig); + # setup warehouses + my $query = qq|SELECT id, description + FROM warehouse + ORDER BY 2|; + my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - ($_) = $sth->fetchrow_array; + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_warehouses} }, $ref; + } + $sth->finish; + + $dbh->disconnect; + +} + + +sub save_inventory { + my ($self, $myconfig, $form) = @_; + + my ($null, $warehouse_id) = split /--/, $form->{warehouse}; + $warehouse_id *= 1; + + my $ml = ($form->{type} eq 'ship_order') ? -1 : 1; + + my $dbh = $form->dbconnect_noauto($myconfig); + my $sth; + my $wth; + my $serialnumber; + my $ship; + + my $employee_id; + ($null, $employee_id) = split /--/, $form->{employee}; + ($null, $employee_id) = $form->get_employee($dbh) if ! $employee_id; + + $query = qq|SELECT serialnumber, ship + FROM orderitems + WHERE trans_id = ? + AND id = ? + FOR UPDATE|; + $sth = $dbh->prepare($query) || $form->dberror($query); + + $query = qq|SELECT sum(qty) + FROM inventory + WHERE parts_id = ? + AND warehouse_id = ?|; + $wth = $dbh->prepare($query) || $form->dberror($query); + + + for my $i (1 .. $form->{rowcount}) { + + $ship = (abs($form->{"ship_$i"}) > abs($form->{"qty_$i"})) ? $form->{"qty_$i"} : $form->{"ship_$i"}; + + if ($warehouse_id && $form->{type} eq 'ship_order') { + + $wth->execute($form->{"id_$i"}, $warehouse_id) || $form->dberror; + + ($qty) = $wth->fetchrow_array; + $wth->finish; + + if ($ship > $qty) { + $ship = $qty; + } + } + + + if ($ship != 0) { + + $ship *= $ml; + $query = qq|INSERT INTO inventory (parts_id, warehouse_id, + qty, oe_id, orderitems_id, shippingdate, employee_id) + VALUES ($form->{"id_$i"}, $warehouse_id, + $ship, $form->{"id"}, + $form->{"orderitems_id_$i"}, '$form->{shippingdate}', + $employee_id)|; + $dbh->do($query) || $form->dberror($query); + + # add serialnumber, ship to orderitems + $sth->execute($form->{id}, $form->{"orderitems_id_$i"}) || $form->dberror; + ($serialnumber, $ship) = $sth->fetchrow_array; + $sth->finish; + + $serialnumber .= " " if $serialnumber; + $serialnumber .= qq|$form->{"serialnumber_$i"}|; + $ship += $form->{"ship_$i"}; + + $query = qq|UPDATE orderitems SET + serialnumber = '$serialnumber', + ship = $ship, + reqdate = '$form->{shippingdate}' + WHERE trans_id = $form->{id} + AND id = $form->{"orderitems_id_$i"}|; + $dbh->do($query) || $form->dberror($query); + + + # update order with ship via + $query = qq|UPDATE oe SET + shippingpoint = '$form->{shippingpoint}', + shipvia = '$form->{shipvia}' + WHERE id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + + # update onhand for parts + $form->update_balance($dbh, + "parts", + "onhand", + qq|id = $form->{"id_$i"}|, + $form->{"ship_$i"} * $ml); + + } + } + + my $rc = $dbh->commit; + $dbh->disconnect; + + $rc; + +} + + +sub adj_onhand { + my ($dbh, $form, $ml) = @_; + + my $query = qq|SELECT oi.parts_id, oi.ship, p.inventory_accno_id, p.assembly + FROM orderitems oi + JOIN parts p ON (p.id = oi.parts_id) + WHERE oi.trans_id = $form->{id}|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + $query = qq|SELECT sum(p.inventory_accno_id) + FROM parts p + JOIN assembly a ON (a.parts_id = p.id) + WHERE a.id = ?|; + my $ath = $dbh->prepare($query) || $form->dberror($query); + + my $ispa; + my $ref; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + + if ($ref->{inventory_accno_id} || $ref->{assembly}) { + + # do not update if assembly consists of all services + if ($ref->{assembly}) { + $ath->execute($ref->{parts_id}) || $form->dberror($query); + + ($ispa) = $ath->fetchrow_array; + $ath->finish; + + next unless $ispa; + + } + + # adjust onhand in parts table + $form->update_balance($dbh, + "parts", + "onhand", + qq|id = $ref->{parts_id}|, + $ref->{ship} * $ml); + } + } $sth->finish; - $_; +} + + +sub adj_inventory { + my ($dbh, $myconfig, $form) = @_; + + my %oid = ( 'Pg' => 'oid', + 'PgPP' => 'oid', + 'Oracle' => 'rowid', + 'DB2' => '1=1' + ); + + # increase/reduce qty in inventory table + my $query = qq|SELECT oi.id, oi.parts_id, oi.ship + FROM orderitems oi + WHERE oi.trans_id = $form->{id}|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + $query = qq|SELECT $oid{$myconfig->{dbdriver}} AS oid, qty, + (SELECT SUM(qty) FROM inventory + WHERE oe_id = $form->{id} + AND orderitems_id = ?) AS total + FROM inventory + WHERE oe_id = $form->{id} + AND orderitems_id = ?|; + my $ith = $dbh->prepare($query) || $form->dberror($query); + + my $qty; + my $ml = ($form->{type} =~ /(ship|sales)_order/) ? -1 : 1; + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + + $ith->execute($ref->{id}, $ref->{id}) || $form->dberror($query); + + while (my $inv = $ith->fetchrow_hashref(NAME_lc)) { + + if (($qty = (($inv->{total} * $ml) - $ref->{ship})) >= 0) { + $qty = $inv->{qty} if ($qty > ($inv->{qty} * $ml)); + + $form->update_balance($dbh, + "inventory", + "qty", + qq|$oid{$myconfig->{dbdriver}} = $inv->{oid}|, + $qty * -1 * $ml); + } + } + $ith->finish; + + } + $sth->finish; + + # delete inventory entries if qty = 0 + $query = qq|DELETE FROM inventory + WHERE oe_id = $form->{id} + AND qty = 0|; + $dbh->do($query) || $form->dberror($query); + +} + + +sub get_inventory { + my ($self, $myconfig, $form) = @_; + + my ($null, $warehouse_id) = split /--/, $form->{warehouse}; + $warehouse_id *= 1; + + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT p.id, p.partnumber, p.description, p.onhand, + pg.partsgroup + FROM parts p + LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id) + WHERE p.onhand > 0|; + + if ($form->{partnumber}) { + $var = $form->like(lc $form->{partnumber}); + $query .= " + AND lower(p.partnumber) LIKE '$var'"; + } + if ($form->{description}) { + $var = $form->like(lc $form->{description}); + $query .= " + AND lower(p.description) LIKE '$var'"; + } + if ($form->{partsgroup}) { + $var = $form->like(lc $form->{partsgroup}); + $query .= " + AND lower(pg.partsgroup) LIKE '$var'"; + } + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + + $query = qq|SELECT sum(i.qty), w.description, w.id + FROM inventory i + LEFT JOIN warehouse w ON (w.id = i.warehouse_id) + WHERE i.parts_id = ? + AND i.warehouse_id != $warehouse_id + GROUP BY w.description, w.id|; + $wth = $dbh->prepare($query) || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + + $wth->execute($ref->{id}) || $form->dberror; + + while (($qty, $warehouse, $warehouse_id) = $wth->fetchrow_array) { + push @{ $form->{all_inventory} }, {'id' => $ref->{id}, + 'partnumber' => $ref->{partnumber}, + 'description' => $ref->{description}, + 'partsgroup' => $ref->{partsgroup}, + 'qty' => $qty, + 'warehouse_id' => $warehouse_id, + 'warehouse' => $warehouse} if $qty > 0; + } + $wth->finish; + } + $sth->finish; + + $dbh->disconnect; + + # sort inventory + @{ $form->{all_inventory} } = sort { $a->{$form->{sort}} cmp $b->{$form->{sort}} } @{ $form->{all_inventory} }; + +} + + +sub transfer { + my ($self, $myconfig, $form) = @_; + + my $dbh = $form->dbconnect_noauto($myconfig); + + my $query = qq|INSERT INTO inventory + (warehouse_id, parts_id, qty, shippingdate, employee_id) + VALUES (?, ?, ?, ?, ?)|; + $sth = $dbh->prepare($query) || $form->dberror($query); + + ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh); + + my @a = localtime; $a[5] += 1900; $a[4]++; + $shippingdate = "$a[5]-$a[4]-$a[3]"; + + for my $i (1 .. $form->{rowcount}) { + $qty = $form->parse_amount($myconfig, $form->{"transfer_$i"}); + + $qty = $form->{"qty_$i"} if ($qty > $form->{"qty_$i"}); + + if ($qty) { + # to warehouse + $sth->execute($form->{warehouse_id}, $form->{"id_$i"}, $qty, $shippingdate, $form->{employee_id}) || $form->dberror; + + $sth->finish; + + # from warehouse + $sth->execute($form->{"warehouse_id_$i"}, $form->{"id_$i"}, $qty * -1, $shippingdate, $form->{employee_id}) || $form->dberror; + + $sth->finish; + } + } + + my $rc = $dbh->commit; + $dbh->disconnect; + + $rc; } diff --git a/sql-ledger/SL/OP.pm b/sql-ledger/SL/OP.pm new file mode 100644 index 000000000..184566c14 --- /dev/null +++ b/sql-ledger/SL/OP.pm @@ -0,0 +1,118 @@ +#===================================================================== +# SQL-Ledger Accounting +# Copyright (C) 2003 +# +# 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. +#====================================================================== +# +# Overpayment function +# used in AR, AP, IS, IR, OE, CP +# +#====================================================================== + +package OP; + +sub overpayment { + my ($self, $myconfig, $form, $dbh, $amount, $ml) = @_; + + my $fxamount = $form->round_amount($amount * $form->{exchangerate}, 2); + my ($paymentaccno) = split /--/, $form->{account}; + + my $vc_id = "$form->{vc}_id"; + + my $uid = time; + $uid .= $form->{login}; + + # add AR/AP header transaction with a payment + $query = qq|INSERT INTO $form->{arap} (invnumber, employee_id) + VALUES ('$uid', (SELECT id FROM employee + WHERE login = '$form->{login}'))|; + $dbh->do($query) || $form->dberror($query); + + $query = qq|SELECT id FROM $form->{arap} + WHERE invnumber = '$uid'|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + ($uid) = $sth->fetchrow_array; + $sth->finish; + + my $invnumber = $form->{invnumber}; + if (! $invnumber) { + $invnumber = $form->update_defaults($myconfig, ($form->{arap} eq 'ar') ? "sinumber" : "vinumber", $dbh); + } + + $query = qq|UPDATE $form->{arap} set + invnumber = |.$dbh->quote($invnumber).qq|, + $vc_id = $form->{"$form->{vc}_id"}, + transdate = '$form->{datepaid}', + datepaid = '$form->{datepaid}', + duedate = '$form->{datepaid}', + netamount = 0, + amount = 0, + paid = $fxamount, + curr = '$form->{currency}', + department_id = $form->{department_id} + WHERE id = $uid|; + $dbh->do($query) || $form->dberror($query); + + # add AR/AP + ($accno) = split /--/, $form->{$form->{ARAP}}; + + $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate, amount) + VALUES ($uid, (SELECT id FROM chart + WHERE accno = '$accno'), + '$form->{datepaid}', $fxamount * $ml)|; + $dbh->do($query) || $form->dberror($query); + + # add payment + $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate, + amount, source, memo) + VALUES ($uid, (SELECT id FROM chart + WHERE accno = '$paymentaccno'), + '$form->{datepaid}', $amount * $ml * -1, | + .$dbh->quote($form->{source}).qq|, | + .$dbh->quote($form->{memo}).qq|)|; + $dbh->do($query) || $form->dberror($query); + + # add exchangerate difference + if ($fxamount != $amount) { + $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate, + amount, cleared, fx_transaction) + VALUES ($uid, (SELECT id FROM chart + WHERE accno = '$paymentaccno'), + '$form->{datepaid}', ($fxamount - $amount) * $ml * -1, + '1', '1')|; + $dbh->do($query) || $form->dberror($query); + } + + my %audittrail = ( tablename => $form->{arap}, + reference => $invnumber, + formname => ($form->{arap} eq 'ar') ? 'deposit' : 'pre-payment', + action => 'posted', + id => $uid ); + + $form->audittrail($dbh, "", \%audittrail); + +} + + +1; + diff --git a/sql-ledger/SL/PE.pm b/sql-ledger/SL/PE.pm index dec04bb4f..f0850a7cf 100644 --- a/sql-ledger/SL/PE.pm +++ b/sql-ledger/SL/PE.pm @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 1998-2002 +# Copyright (C) 2003 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -36,7 +36,11 @@ sub projects { # connect to database my $dbh = $form->dbconnect($myconfig); - my $sortorder = ($form->{sort}) ? $form->{sort} : "projectnumber"; + $form->{sort} = "projectnumber" unless $form->{sort}; + my @a = ($form->{sort}); + my %ordinal = ( projectnumber => 2, + description => 3 ); + my $sortorder = $form->sort_order(\@a, \%ordinal); my $query = qq|SELECT id, projectnumber, description FROM project @@ -103,14 +107,24 @@ sub get_project { # check if it is orphaned $query = qq|SELECT count(*) FROM acc_trans - WHERE project_id = $form->{id}|; + WHERE project_id = $form->{id} + UNION + SELECT count(*) + FROM invoice + WHERE project_id = $form->{id} + UNION + SELECT count(*) + FROM orderitems + WHERE project_id = $form->{id} + |; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - ($form->{orphaned}) = $sth->fetchrow_array; - $form->{orphaned} = !$form->{orphaned}; - + while (my ($count) = $sth->fetchrow_array) { + $form->{orphaned} += $count; + } $sth->finish; + $form->{orphaned} = !$form->{orphaned}; $dbh->disconnect; @@ -123,17 +137,17 @@ sub save_project { # connect to database my $dbh = $form->dbconnect($myconfig); - map { $form->{$_} =~ s/'/''/g } (projectnumber, description); - if ($form->{id}) { $query = qq|UPDATE project SET - projectnumber = '$form->{projectnumber}', - description = '$form->{description}' + projectnumber = |.$dbh->quote($form->{projectnumber}).qq|, + description = |.$dbh->quote($form->{description}).qq| WHERE id = $form->{id}|; } else { $query = qq|INSERT INTO project (projectnumber, description) - VALUES ('$form->{projectnumber}', '$form->{description}')|; + VALUES (| + .$dbh->quote($form->{projectnumber}).qq|, | + .$dbh->quote($form->{description}).qq|)|; } $dbh->do($query) || $form->dberror($query); @@ -150,7 +164,9 @@ sub partsgroups { # connect to database my $dbh = $form->dbconnect($myconfig); - my $sortorder = ($form->{sort}) ? $form->{sort} : "partsgroup"; + $form->{sort} = "partsgroup" unless $form->{partsgroup}; + my @a = (partsgroup); + my $sortorder = $form->sort_order(\@a); my $query = qq|SELECT g.* FROM partsgroup g|; @@ -201,17 +217,14 @@ sub save_partsgroup { # connect to database my $dbh = $form->dbconnect($myconfig); - map { $form->{$_} =~ s/'/''/g } (partsgroup); - - if ($form->{id}) { $query = qq|UPDATE partsgroup SET - partsgroup = '$form->{partsgroup}' + partsgroup = |.$dbh->quote($form->{partsgroup}).qq| WHERE id = $form->{id}|; } else { $query = qq|INSERT INTO partsgroup (partsgroup) - VALUES ('$form->{partsgroup}')|; + VALUES (|.$dbh->quote($form->{partsgroup}).qq|)|; } $dbh->do($query) || $form->dberror($query); @@ -255,22 +268,372 @@ sub get_partsgroup { } +sub pricegroups { + my ($self, $myconfig, $form) = @_; + + my $var; + + # connect to database + my $dbh = $form->dbconnect($myconfig); -sub delete_tuple { + $form->{sort} = "pricegroup" unless $form->{sort}; + my @a = (pricegroup); + my $sortorder = $form->sort_order(\@a); + + my $query = qq|SELECT g.* + FROM pricegroup g|; + + my $where = "1 = 1"; + + if ($form->{pricegroup}) { + $var = $form->like(lc $form->{pricegroup}); + $where .= " AND lower(pricegroup) LIKE '$var'"; + } + $query .= qq| + WHERE $where + ORDER BY $sortorder|; + + if ($form->{status} eq 'orphaned') { + $query = qq|SELECT g.* + FROM pricegroup g + WHERE $where + AND g.id NOT IN (SELECT DISTINCT pricegroup_id + FROM partscustomer) + ORDER BY $sortorder|; + } + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my $i = 0; + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{item_list} }, $ref; + $i++; + } + + $sth->finish; + $dbh->disconnect; + + $i; + +} + + +sub save_pricegroup { my ($self, $myconfig, $form) = @_; # connect to database my $dbh = $form->dbconnect($myconfig); + if ($form->{id}) { + $query = qq|UPDATE pricegroup SET + pricegroup = |.$dbh->quote($form->{pricegroup}).qq| + WHERE id = $form->{id}|; + } else { + $query = qq|INSERT INTO pricegroup + (pricegroup) + VALUES (|.$dbh->quote($form->{pricegroup}).qq|)|; + } + $dbh->do($query) || $form->dberror($query); + + $dbh->disconnect; + +} + + +sub get_pricegroup { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT * + FROM pricegroup + WHERE id = $form->{id}|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my $ref = $sth->fetchrow_hashref(NAME_lc); + + map { $form->{$_} = $ref->{$_} } keys %$ref; + + $sth->finish; + + # check if it is orphaned + $query = qq|SELECT count(*) + FROM partscustomer + WHERE pricegroup_id = $form->{id}|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + ($form->{orphaned}) = $sth->fetchrow_array; + $form->{orphaned} = !$form->{orphaned}; + + $sth->finish; + + $dbh->disconnect; + +} + + +sub delete_tuple { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect_noauto($myconfig); + $query = qq|DELETE FROM $form->{type} WHERE id = $form->{id}|; $dbh->do($query) || $form->dberror($query); + if ($form->{type} !~ /pricegroup/) { + $query = qq|DELETE FROM translation + WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + } + + $dbh->commit; + $dbh->disconnect; + +} + + +sub description_translations { + my ($self, $myconfig, $form) = @_; + + my $where = "1 = 1\n"; + my $var; + my $ref; + + map { $where .= "AND lower(p.$_) LIKE '".$form->like(lc $form->{$_})."'\n" if $form->{$_} } qw(partnumber description); + + $where .= " AND p.obsolete = '0'"; + $where .= " AND p.id = $form->{id}" if $form->{id}; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my %ordinal = ( 'partnumber' => 2, + 'description' => 3 + ); + + my @a = qw(partnumber description); + my $sortorder = $form->sort_order(\@a, \%ordinal); + + my $query = qq|SELECT l.description AS language, t.description AS translation, + l.code + FROM translation t + JOIN language l ON (l.code = t.language_code) + WHERE trans_id = ? + ORDER BY 1|; + my $tth = $dbh->prepare($query); + + $query = qq|SELECT p.id, p.partnumber, p.description + FROM parts p + WHERE $where + ORDER BY $sortorder|; + + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my $tra; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{translations} }, $ref; + + # get translations for description + $tth->execute($ref->{id}) || $form->dberror; + + while ($tra = $tth->fetchrow_hashref(NAME_lc)) { + $form->{trans_id} = $ref->{id}; + $tra->{id} = $ref->{id}; + push @{ $form->{translations} }, $tra; + } + + } + $sth->finish; + + &get_language("", $dbh, $form) if $form->{id}; + + $dbh->disconnect; + +} + + +sub partsgroup_translations { + my ($self, $myconfig, $form) = @_; + + my $where = "1 = 1\n"; + my $ref; + + if ($form->{description}) { + $where .= "AND lower(p.partsgroup) LIKE '".$form->like(lc $form->{description})."'"; + } + $where .= " AND p.id = $form->{id}" if $form->{id}; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my $query = qq|SELECT l.description AS language, t.description AS translation, + l.code + FROM translation t + JOIN language l ON (l.code = t.language_code) + WHERE trans_id = ? + ORDER BY 1|; + my $tth = $dbh->prepare($query); + + $form->sort_order(); + + $query = qq|SELECT p.id, p.partsgroup AS description + FROM partsgroup p + WHERE $where + ORDER BY 2 $form->{direction}|; + + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my $tra; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{translations} }, $ref; + + # get translations for partsgroup + $tth->execute($ref->{id}) || $form->dberror; + + while ($tra = $tth->fetchrow_hashref(NAME_lc)) { + $form->{trans_id} = $ref->{id}; + push @{ $form->{translations} }, $tra; + } + + } + $sth->finish; + + &get_language("", $dbh, $form) if $form->{id}; + + $dbh->disconnect; + +} + + +sub project_translations { + my ($self, $myconfig, $form) = @_; + + my $where = "1 = 1\n"; + my $var; + my $ref; + + map { $where .= "AND lower(p.$_) LIKE '".$form->like(lc $form->{$_})."'\n" if $form->{$_} } qw(projectnumber description); + + $where .= " AND p.id = $form->{id}" if $form->{id}; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + my %ordinal = ( 'projectnumber' => 2, + 'description' => 3 + ); + + my @a = qw(projectnumber description); + my $sortorder = $form->sort_order(\@a, \%ordinal); + + my $query = qq|SELECT l.description AS language, t.description AS translation, + l.code + FROM translation t + JOIN language l ON (l.code = t.language_code) + WHERE trans_id = ? + ORDER BY 1|; + my $tth = $dbh->prepare($query); + + $query = qq|SELECT p.id, p.projectnumber, p.description + FROM project p + WHERE $where + ORDER BY $sortorder|; + + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my $tra; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{translations} }, $ref; + + # get translations for description + $tth->execute($ref->{id}) || $form->dberror; + + while ($tra = $tth->fetchrow_hashref(NAME_lc)) { + $form->{trans_id} = $ref->{id}; + $tra->{id} = $ref->{id}; + push @{ $form->{translations} }, $tra; + } + + } + $sth->finish; + + &get_language("", $dbh, $form) if $form->{id}; + + $dbh->disconnect; + +} + + +sub get_language { + my ($self, $dbh, $form) = @_; + + # get language + my $query = qq|SELECT * + FROM language + ORDER BY 2|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_language} }, $ref; + } + $sth->finish; + +} + + +sub save_translation { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect_noauto($myconfig); + + my $query = qq|DELETE FROM translation + WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $query = qq|INSERT INTO translation (trans_id, language_code, description) + VALUES ($form->{id}, ?, ?)|; + my $sth = $dbh->prepare($query) || $form->dberror($query); + + foreach my $i (1 .. $form->{translation_rows}) { + if ($form->{"language_code_$i"}) { + $sth->execute($form->{"language_code_$i"}, $form->{"translation_$i"}); + $sth->finish; + } + } + $dbh->commit; $dbh->disconnect; } +sub delete_translation { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + $query = qq|DELETE FROM translation + WHERE trans_id = $form->{id}|; + $dbh->do($query) || $form->dberror($query); + + $dbh->disconnect; + +} + 1; diff --git a/sql-ledger/SL/RC.pm b/sql-ledger/SL/RC.pm index 9957d7349..2a8bf9410 100644 --- a/sql-ledger/SL/RC.pm +++ b/sql-ledger/SL/RC.pm @@ -38,7 +38,7 @@ sub paymentaccounts { my $query = qq|SELECT accno, description FROM chart WHERE link LIKE '%_paid%' - AND category = 'A' + AND (category = 'A' OR category = 'L') ORDER BY accno|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); @@ -47,6 +47,9 @@ sub paymentaccounts { push @{ $form->{PR} }, $ref; } $sth->finish; + + $form->all_years($dbh, $myconfig); + $dbh->disconnect; } @@ -58,92 +61,356 @@ sub payment_transactions { # connect to database, turn AutoCommit off my $dbh = $form->dbconnect_noauto($myconfig); - my ($query, $sth); - - # get cleared balance - if ($form->{fromdate}) { - $query = qq|SELECT sum(a.amount) - FROM acc_trans a, chart c - WHERE a.transdate < date '$form->{fromdate}' - AND a.cleared = '1' - AND c.id = a.chart_id - AND c.accno = '$form->{accno}' - |; - } else { - $query = qq|SELECT sum(a.amount) - FROM acc_trans a, chart c - WHERE a.cleared = '1' - AND c.id = a.chart_id - AND c.accno = '$form->{accno}' - |; - } + my $query; + my $sth; + + $query = qq|SELECT category FROM chart + WHERE accno = '$form->{accno}'|; + ($form->{category}) = $dbh->selectrow_array($query); - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); + my $cleared; - ($form->{beginningbalance}) = $sth->fetchrow_array; + ($form->{fromdate}, $form->{todate}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month}; - $sth->finish; + my $transdate = qq| AND ac.transdate < date '$form->{fromdate}'|; - my %oid = ( 'Pg' => 'ac.oid', - 'Oracle' => 'ac.rowid'); - - $query = qq|SELECT c.name, ac.source, ac.transdate, ac.cleared, - ac.fx_transaction, ac.amount, a.id, - $oid{$myconfig->{dbdriver}} AS oid - FROM customer c, acc_trans ac, ar a, chart ch - WHERE c.id = a.customer_id - AND ac.cleared = '0' - AND ac.trans_id = a.id - AND ac.chart_id = ch.id - AND ch.accno = '$form->{accno}' + if (! $form->{fromdate}) { + $cleared = qq| AND ac.cleared = '1'|; + $transdate = ""; + } + + # get beginning balance + $query = qq|SELECT sum(ac.amount) + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + WHERE c.accno = '$form->{accno}' + $transdate + $cleared |; - - $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate}; - $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate}; - - - $query .= qq| - - UNION - SELECT v.name, ac.source, ac.transdate, ac.cleared, - ac.fx_transaction, ac.amount, a.id, - $oid{$myconfig->{dbdriver}} AS oid - FROM vendor v, acc_trans ac, ap a, chart ch - WHERE v.id = a.vendor_id - AND ac.cleared = '0' - AND ac.trans_id = a.id - AND ac.chart_id = ch.id - AND ch.accno = '$form->{accno}' - |; - - $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate}; - $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate}; - - $query .= qq| + ($form->{beginningbalance}) = $dbh->selectrow_array($query); + + # fx balance + $query = qq|SELECT sum(ac.amount) + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + WHERE c.accno = '$form->{accno}' + AND ac.fx_transaction = '1' + $transdate + $cleared + |; + ($form->{fx_balance}) = $dbh->selectrow_array($query); - UNION - SELECT g.description, ac.source, ac.transdate, ac.cleared, - ac.fx_transaction, ac.amount, g.id, - $oid{$myconfig->{dbdriver}} AS oid - FROM gl g, acc_trans ac, chart ch - WHERE g.id = ac.trans_id - AND ac.cleared = '0' - AND ac.trans_id = g.id - AND ac.chart_id = ch.id - AND ch.accno = '$form->{accno}' + + $transdate = ""; + if ($form->{todate}) { + $transdate = qq| AND ac.transdate <= date '$form->{todate}'|; + } + + # get statement balance + $query = qq|SELECT sum(ac.amount) + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + WHERE c.accno = '$form->{accno}' + $transdate + |; + ($form->{endingbalance}) = $dbh->selectrow_array($query); + + # fx balance + $query = qq|SELECT sum(ac.amount) + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + WHERE c.accno = '$form->{accno}' + AND ac.fx_transaction = '1' + $transdate |; + ($form->{fx_endingbalance}) = $dbh->selectrow_array($query); - $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate}; - $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate}; - $query .= " ORDER BY 3,7,8"; + $cleared = qq| AND ac.cleared = '0'| unless $form->{fromdate}; + + if ($form->{report}) { + $cleared = qq| AND NOT (ac.cleared = '0' OR ac.cleared = '1')|; + if ($form->{cleared}) { + $cleared = qq| AND ac.cleared = '1'|; + } + if ($form->{outstanding}) { + $cleared = ($form->{cleared}) ? "" : qq| AND ac.cleared = '0'|; + } + if (! $form->{fromdate}) { + $form->{beginningbalance} = 0; + $form->{fx_balance} = 0; + } + } + + + if ($form->{summary}) { + $query = qq|SELECT ac.transdate, ac.source, + sum(ac.amount) AS amount, ac.cleared + FROM acc_trans ac + JOIN chart ch ON (ac.chart_id = ch.id) + WHERE ch.accno = '$form->{accno}' + AND ac.amount >= 0 + AND ac.fx_transaction = '0' + $cleared|; + $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate}; + $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate}; + $query .= " GROUP BY ac.source, ac.transdate, ac.cleared"; + $query .= qq| + UNION + SELECT ac.transdate, ac.source, + sum(ac.amount) AS amount, ac.cleared + FROM acc_trans ac + JOIN chart ch ON (ac.chart_id = ch.id) + WHERE ch.accno = '$form->{accno}' + AND ac.amount < 0 + AND ac.fx_transaction = '0' + $cleared|; + $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate}; + $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate}; + $query .= " GROUP BY ac.source, ac.transdate, ac.cleared"; + + $query .= " ORDER BY 1,2"; + + } else { + + $query = qq|SELECT ac.transdate, ac.source, ac.fx_transaction, + ac.amount, ac.cleared, g.id, g.description + FROM acc_trans ac + JOIN chart ch ON (ac.chart_id = ch.id) + JOIN gl g ON (g.id = ac.trans_id) + WHERE ch.accno = '$form->{accno}' + AND ac.fx_transaction = '0' + $cleared|; + $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate}; + $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate}; + + $query .= qq| + UNION + SELECT ac.transdate, ac.source, ac.fx_transaction, + ac.amount, ac.cleared, a.id, n.name + FROM acc_trans ac + JOIN chart ch ON (ac.chart_id = ch.id) + JOIN ar a ON (a.id = ac.trans_id) + JOIN customer n ON (n.id = a.customer_id) + WHERE ch.accno = '$form->{accno}' + AND ac.fx_transaction = '0' + $cleared|; + $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate}; + $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate}; + + $query .= qq| + UNION + SELECT ac.transdate, ac.source, ac.fx_transaction, + ac.amount, ac.cleared, a.id, n.name + FROM acc_trans ac + JOIN chart ch ON (ac.chart_id = ch.id) + JOIN ap a ON (a.id = ac.trans_id) + JOIN vendor n ON (n.id = a.vendor_id) + WHERE ch.accno = '$form->{accno}' + AND ac.fx_transaction = '0' + $cleared|; + $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate}; + $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate}; + + $query .= " ORDER BY 1,2,3"; + } $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - while (my $pr = $sth->fetchrow_hashref(NAME_lc)) { - push @{ $form->{PR} }, $pr; + my $dr; + my $cr; + my $fxs; + + if ($form->{summary}) { + $query = qq|SELECT ac.amount, ac.cleared + FROM acc_trans ac + JOIN ar a ON (a.id = ac.trans_id) + JOIN customer n ON (n.id = a.customer_id) + WHERE ac.fx_transaction = '1' + AND n.name = ? + AND ac.transdate = ? + AND ac.trans_id IN (SELECT id FROM ar a + JOIN acc_trans ac ON (a.id = ac.trans_id) + WHERE ac.source = ?) + AND ac.cleared = ? + AND NOT + (ac.chart_id IN + (SELECT fxgain_accno_id FROM defaults + UNION + SELECT fxloss_accno_id FROM defaults)) + |; + + $query .= qq| + UNION + SELECT ac.amount, ac.cleared + FROM acc_trans ac + JOIN ap a ON (a.id = ac.trans_id) + JOIN vendor n ON (n.id = a.vendor_id) + WHERE ac.fx_transaction = '1' + AND n.name = ? + AND ac.transdate = ? + AND ac.trans_id IN (SELECT id FROM ap a + JOIN acc_trans ac ON (a.id = ac.trans_id) + WHERE ac.source = ?) + AND ac.cleared = ? + AND NOT + (ac.chart_id IN + (SELECT fxgain_accno_id FROM defaults + UNION + SELECT fxloss_accno_id FROM defaults)) + |; + + } else { + + $query = qq|SELECT ac.amount, ac.cleared + FROM acc_trans ac + WHERE ac.trans_id = ? + AND ac.fx_transaction = '1' + $cleared + AND NOT + (ac.chart_id IN + (SELECT fxgain_accno_id FROM defaults + UNION + SELECT fxloss_accno_id FROM defaults)) + |; + + } + + $fxs = $dbh->prepare($query); + + + if ($form->{summary}) { + $query = qq|SELECT c.name + FROM customer c + JOIN ar a ON (c.id = a.customer_id) + JOIN acc_trans ac ON (a.id = ac.trans_id) + WHERE ac.transdate = ? + AND ac.source = ? + AND ac.amount > 0 + $cleared + UNION + SELECT v.name + FROM vendor v + JOIN ap a ON (v.id = a.vendor_id) + JOIN acc_trans ac ON (a.id = ac.trans_id) + WHERE ac.transdate = ? + AND ac.source = ? + AND ac.amount > 0 + $cleared + UNION + SELECT g.description + FROM gl g + JOIN acc_trans ac ON (g.id = ac.trans_id) + WHERE ac.transdate = ? + AND ac.source = ? + AND ac.amount > 0 + $cleared + |; + + $query .= " ORDER BY 1"; + $dr = $dbh->prepare($query); + + + $query = qq|SELECT c.name + FROM customer c + JOIN ar a ON (c.id = a.customer_id) + JOIN acc_trans ac ON (a.id = ac.trans_id) + WHERE ac.transdate = ? + AND ac.source = ? + AND ac.amount < 0 + $cleared + UNION + SELECT v.name + FROM vendor v + JOIN ap a ON (v.id = a.vendor_id) + JOIN acc_trans ac ON (a.id = ac.trans_id) + WHERE ac.transdate = ? + AND ac.source = ? + AND ac.amount < 0 + $cleared + UNION + SELECT g.description + FROM gl g + JOIN acc_trans ac ON (g.id = ac.trans_id) + WHERE ac.transdate = ? + AND ac.source = ? + AND ac.amount < 0 + $cleared + |; + + $query .= " ORDER BY 1"; + $cr = $dbh->prepare($query); + } + + + my $name; + my $ref; + my $xfref; + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + + if ($form->{summary}) { + + if ($ref->{amount} > 0) { + $dr->execute($ref->{transdate}, $ref->{source}, $ref->{transdate}, $ref->{source}, $ref->{transdate}, $ref->{source}); + $ref->{oldcleared} = $ref->{cleared}; + $ref->{name} = (); + while (($name) = $dr->fetchrow_array) { + push @{ $ref->{name} }, $name; + } + $dr->finish; + } else { + + $cr->execute($ref->{transdate}, $ref->{source}, $ref->{transdate}, $ref->{source}, $ref->{transdate}, $ref->{source}); + $ref->{oldcleared} = $ref->{cleared}; + $ref->{name} = (); + while (($name) = $cr->fetchrow_array) { + push @{ $ref->{name} }, $name; + } + $cr->finish; + + } + + } else { + push @{ $ref->{name} }, $ref->{description}; + } + + push @{ $form->{PR} }, $ref; + + # include fx transactions + $amount = 0; + $addfx = 0; + $ref->{oldcleared} = $ref->{cleared}; + if ($form->{summary}) { + foreach $name (@{ $ref->{name} }) { + $fxs->execute($name, $ref->{transdate}, $ref->{source}, $ref->{cleared}, $name, $ref->{transdate}, $ref->{source}, $ref->{cleared}); + while ($fxref = $fxs->fetchrow_hashref(NAME_lc)) { + $addfx = 1; + $amount += $fxref->{amount}; + } + $fxs->finish; + } + } else { + $fxs->execute($ref->{id}); + while ($fxref = $fxs->fetchrow_hashref(NAME_lc)) { + $addfx = 1; + $amount += $fxref->{amount}; + } + $fxs->finish; + } + + if ($addfx) { + $fxref = (); + map { $fxref->{$_} = $ref->{$_} } keys %$ref; + $fxref->{fx_transaction} = 1; + $fxref->{name} = (); + $fxref->{source} = ""; + $fxref->{transdate} = ""; + $fxref->{amount} = $amount; + push @{ $form->{PR} }, $fxref; + } + } $sth->finish; @@ -158,22 +425,43 @@ sub reconcile { # connect to database my $dbh = $form->dbconnect($myconfig); - my ($query, $i); - my %oid = ( 'Pg' => 'oid', - 'Oracle' => 'rowid'); + my $query = qq|SELECT id FROM chart + WHERE accno = '$form->{accno}'|; + my ($chart_id) = $dbh->selectrow_array($query); + $chart_id *= 1; + + $query = qq|SELECT trans_id FROM acc_trans + WHERE source = ? + AND transdate = ? + AND cleared = '0'|; + my $sth = $dbh->prepare($query) || $form->dberror($query); + + my $i; + my $trans_id; + + $query = qq|UPDATE acc_trans SET cleared = '1' + WHERE cleared = '0' + AND trans_id = ? + AND transdate = ? + AND chart_id = $chart_id|; + my $tth = $dbh->prepare($query) || $form->dberror($query); # clear flags for $i (1 .. $form->{rowcount}) { - if ($form->{"cleared_$i"}) { - $query = qq|UPDATE acc_trans SET cleared = '1' - WHERE $oid{$myconfig->{dbdriver}} = $form->{"oid_$i"}|; - $dbh->do($query) || $form->dberror($query); - - # clear fx_transaction - if ($form->{"fxoid_$i"}) { - $query = qq|UPDATE acc_trans SET cleared = '1' - WHERE $oid{$myconfig->{dbdriver}} = $form->{"fxoid_$i"}|; - $dbh->do($query) || $form->dberror($query); + if ($form->{"cleared_$i"} && ! $form->{"oldcleared_$i"}) { + if ($form->{summary}) { + $sth->execute($form->{"source_$i"}, $form->{"transdate_$i"}) || $form->dberror; + + while (($trans_id) = $sth->fetchrow_array) { + $tth->execute($trans_id, $form->{"transdate_$i"}) || $form->dberror; + $tth->finish; + } + $sth->finish; + + } else { + + $tth->execute($form->{"id_$i"}, $form->{"transdate_$i"}) || $form->dberror; + $tth->finish; } } } diff --git a/sql-ledger/SL/RP.pm b/sql-ledger/SL/RP.pm index 3f07bb525..791b22bba 100644 --- a/sql-ledger/SL/RP.pm +++ b/sql-ledger/SL/RP.pm @@ -1,12 +1,13 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 1998-2002 +# Copyright (C) 2001 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org # Web: http://www.sql-ledger.org # # Contributors: Benjamin Lee +# Jim Rawlings # # 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 @@ -29,6 +30,82 @@ package RP; +sub yearend_statement { + my ($self, $myconfig, $form) = @_; + + # connect to database + my $dbh = $form->dbconnect($myconfig); + + # if todate < existing yearends, delete GL and yearends + my $query = qq|SELECT trans_id FROM yearend + WHERE transdate >= '$form->{todate}'|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my @trans_id = (); + my $id; + while (($id) = $sth->fetchrow_array) { + push @trans_id, $id; + } + $sth->finish; + + $query = qq|DELETE FROM gl + WHERE id = ?|; + $sth = $dbh->prepare($query) || $form->dberror($query); + + $query = qq|DELETE FROM acc_trans + WHERE trans_id = ?|; + my $ath = $dbh->prepare($query) || $form->dberror($query); + + foreach $id (@trans_id) { + $sth->execute($id); + $ath->execute($id); + } + $sth->finish; + + + my $last_period = 0; + my @categories = qw(I E); + my $category; + + $form->{decimalplaces} *= 1; + + &get_accounts($dbh, 0, $form->{fromdate}, $form->{todate}, $form, \@categories); + + # disconnect + $dbh->disconnect; + + + # now we got $form->{I}{accno}{ } + # and $form->{E}{accno}{ } + + my %account = ( 'I' => { 'label' => 'income', + 'labels' => 'income', + 'ml' => 1 }, + 'E' => { 'label' => 'expense', + 'labels' => 'expenses', + 'ml' => -1 } + ); + + foreach $category (@categories) { + foreach $key (sort keys %{ $form->{$category} }) { + if ($form->{$category}{$key}{charttype} eq 'A') { + $form->{"total_$account{$category}{labels}_this_period"} += $form->{$category}{$key}{this} * $account{$category}{ml}; + } + } + } + + + # totals for income and expenses + $form->{total_income_this_period} = $form->round_amount($form->{total_income_this_period}, $form->{decimalplaces}); + $form->{total_expenses_this_period} = $form->round_amount($form->{total_expenses_this_period}, $form->{decimalplaces}); + + # total for income/loss + $form->{total_this_period} = $form->{total_income_this_period} - $form->{total_expenses_this_period}; + +} + + sub income_statement { my ($self, $myconfig, $form) = @_; @@ -41,13 +118,25 @@ sub income_statement { $form->{decimalplaces} *= 1; - &get_accounts($dbh, $last_period, $form->{fromdate}, $form->{todate}, $form, \@categories); + if (! ($form->{fromdate} || $form->{todate})) { + if ($form->{fromyear} && $form->{frommonth}) { + ($form->{fromdate}, $form->{todate}) = $form->from_to($form->{fromyear}, $form->{frommonth}, $form->{interval}); + } + } + &get_accounts($dbh, $last_period, $form->{fromdate}, $form->{todate}, $form, \@categories, 1); + + if (! ($form->{comparefromdate} || $form->{comparetodate})) { + if ($form->{compareyear} && $form->{comparemonth}) { + ($form->{comparefromdate}, $form->{comparetodate}) = $form->from_to($form->{compareyear}, $form->{comparemonth}, $form->{interval}); + } + } + # if there are any compare dates if ($form->{comparefromdate} || $form->{comparetodate}) { $last_period = 1; - &get_accounts($dbh, $last_period, $form->{comparefromdate}, $form->{comparetodate}, $form, \@categories); + &get_accounts($dbh, $last_period, $form->{comparefromdate}, $form->{comparetodate}, $form, \@categories, 1); } @@ -134,7 +223,7 @@ sub income_statement { } - + # totals for income and expenses $form->{total_income_this_period} = $form->round_amount($form->{total_income_this_period}, $form->{decimalplaces}); $form->{total_expenses_this_period} = $form->round_amount($form->{total_expenses_this_period}, $form->{decimalplaces}); @@ -160,7 +249,6 @@ sub income_statement { } - sub balance_sheet { my ($self, $myconfig, $form) = @_; @@ -168,8 +256,16 @@ sub balance_sheet { my $dbh = $form->dbconnect($myconfig); my $last_period = 0; - my @categories = qw(A L Q); + my @categories = qw(A C L Q); + my $null; + + if (! $form->{asofdate}) { + if ($form->{asofyear} && $form->{asofmonth}) { + ($null, $form->{asofdate}) = $form->from_to($form->{asofyear}, $form->{asofmonth}); + } + } + # if there are any dates construct a where if ($form->{asofdate}) { @@ -180,13 +276,19 @@ sub balance_sheet { $form->{decimalplaces} *= 1; - &get_accounts($dbh, $last_period, "", $form->{asofdate}, $form, \@categories); + &get_accounts($dbh, $last_period, "", $form->{asofdate}, $form, \@categories, 1); + + if (! $form->{compareasofdate}) { + if ($form->{compareasofyear} && $form->{compareasofmonth}) { + ($null, $form->{compareasofdate}) = $form->from_to($form->{compareasofyear}, $form->{compareasofmonth}); + } + } # if there are any compare dates if ($form->{compareasofdate}) { $last_period = 1; - &get_accounts($dbh, $last_period, "", $form->{compareasofdate}, $form, \@categories); + &get_accounts($dbh, $last_period, "", $form->{compareasofdate}, $form, \@categories, 1); $form->{last_period} = "$form->{compareasofdate}"; @@ -212,11 +314,11 @@ sub balance_sheet { 'labels' => 'liabilities', 'ml' => 1 }, 'Q' => { 'label' => 'equity', - 'labels' => 'equities', + 'labels' => 'equity', 'ml' => 1 } ); - foreach $category (@categories) { + foreach $category (grep { !/C/ } @categories) { foreach $key (sort keys %{ $form->{$category} }) { @@ -284,9 +386,9 @@ sub balance_sheet { # totals for assets, liabilities $form->{total_assets_this_period} = $form->round_amount($form->{total_assets_this_period}, $form->{decimalplaces}); $form->{total_liabilities_this_period} = $form->round_amount($form->{total_liabilities_this_period}, $form->{decimalplaces}); - + $form->{total_equity_this_period} = $form->round_amount($form->{total_equity_this_period}, $form->{decimalplaces}); - # calculate retained earnings + # calculate earnings $form->{earnings_this_period} = $form->{total_assets_this_period} - $form->{total_liabilities_this_period} - $form->{total_equity_this_period}; push(@{$form->{equity_this_period}}, $form->format_amount($myconfig, $form->{earnings_this_period}, $form->{decimalplaces}, "- ")); @@ -301,7 +403,7 @@ sub balance_sheet { # totals for assets, liabilities $form->{total_assets_last_period} = $form->round_amount($form->{total_assets_last_period}, $form->{decimalplaces}); $form->{total_liabilities_last_period} = $form->round_amount($form->{total_liabilities_last_period}, $form->{decimalplaces}); - + $form->{total_equity_last_period} = $form->round_amount($form->{total_equity_last_period}, $form->{decimalplaces}); # calculate retained earnings $form->{earnings_last_period} = $form->{total_assets_last_period} - $form->{total_liabilities_last_period} - $form->{total_equity_last_period}; @@ -327,17 +429,28 @@ sub balance_sheet { $form->{total_liabilities_this_period} = $form->format_amount($myconfig, $form->{total_liabilities_this_period}, $form->{decimalplaces}, "- "); $form->{total_equity_this_period} = $form->format_amount($myconfig, $form->{total_equity_this_period}, $form->{decimalplaces}, "- "); - -} +} sub get_accounts { - my ($dbh, $last_period, $fromdate, $todate, $form, $categories) = @_; + my ($dbh, $last_period, $fromdate, $todate, $form, $categories, $yearend) = @_; + my $department_id; + my $project_id; + + ($null, $department_id) = split /--/, $form->{department}; + ($null, $project_id) = split /--/, $form->{projectnumber}; + my $query; - my $where = "WHERE 1 = 1"; - my $subwhere; + my $dpt_where; + my $dpt_join; + my $project; + my $where = "1 = 1"; + my $glwhere = ""; + my $projectwhere = ""; + my $subwhere = ""; + my $yearendwhere = "1 = 1"; my $item; my $category = "AND ("; @@ -380,18 +493,59 @@ sub get_accounts { $sth->finish; - $where .= " AND ac.transdate >= '$fromdate'" if $fromdate; + if ($fromdate) { + $where .= " AND ac.transdate >= '$fromdate'"; + $projectwhere .= " AND transdate >= '$fromdate'"; + if ($form->{method} eq 'cash') { + $subwhere .= " AND transdate >= '$fromdate'"; + $glwhere = " AND ac.transdate >= '$fromdate'"; + } + } if ($todate) { $where .= " AND ac.transdate <= '$todate'"; - $subwhere = " AND transdate <= '$todate'"; + $projectwhere .= " AND transdate <= '$todate'"; + $subwhere .= " AND transdate <= '$todate'"; + $yearendwhere = "ac.transdate < '$todate'"; + } + + if ($yearend) { + $ywhere = " AND ac.trans_id NOT IN + (SELECT trans_id FROM yearend)"; + + if ($fromdate) { + $ywhere = " AND ac.trans_id NOT IN + (SELECT trans_id FROM yearend + WHERE transdate >= '$fromdate')"; + if ($todate) { + $ywhere = " AND ac.trans_id NOT IN + (SELECT trans_id FROM yearend + WHERE transdate >= '$fromdate' + AND transdate <= '$todate')"; + } + } + + if ($todate) { + $ywhere = " AND ac.trans_id NOT IN + (SELECT trans_id FROM yearend + WHERE transdate <= '$todate')"; + } + } + + if ($department_id) + { + $dpt_join = qq| + JOIN department t ON (a.department_id = t.id) + |; + $dpt_where = qq| + AND t.id = $department_id + |; } - - if ($form->{project_id}) + if ($project_id) { $project = qq| - AND ac.project_id = $form->{project_id} + AND ac.project_id = $project_id |; } @@ -410,7 +564,10 @@ sub get_accounts { JOIN chart c ON (c.id = ac.chart_id) JOIN ar a ON (a.id = ac.trans_id) JOIN gifi g ON (g.accno = c.gifi_accno) - $where + $dpt_join + WHERE $where + $ywhere + $dpt_where $category AND ac.trans_id IN ( @@ -423,14 +580,17 @@ sub get_accounts { $project GROUP BY g.accno, g.description, c.category - UNION + UNION ALL SELECT '' AS accno, SUM(ac.amount) AS amount, '' AS description, c.category FROM acc_trans ac JOIN chart c ON (c.id = ac.chart_id) JOIN ar a ON (a.id = ac.trans_id) - $where + $dpt_join + WHERE $where + $ywhere + $dpt_where $category AND c.gifi_accno = '' AND ac.trans_id IN @@ -444,7 +604,7 @@ sub get_accounts { $project GROUP BY c.category - UNION + UNION ALL SELECT g.accno, sum(ac.amount) AS amount, g.description, c.category @@ -452,7 +612,10 @@ sub get_accounts { JOIN chart c ON (c.id = ac.chart_id) JOIN ap a ON (a.id = ac.trans_id) JOIN gifi g ON (g.accno = c.gifi_accno) - $where + $dpt_join + WHERE $where + $ywhere + $dpt_where $category AND ac.trans_id IN ( @@ -465,14 +628,17 @@ sub get_accounts { $project GROUP BY g.accno, g.description, c.category - UNION + UNION ALL SELECT '' AS accno, SUM(ac.amount) AS amount, '' AS description, c.category FROM acc_trans ac JOIN chart c ON (c.id = ac.chart_id) JOIN ap a ON (a.id = ac.trans_id) - $where + $dpt_join + WHERE $where + $ywhere + $dpt_where $category AND c.gifi_accno = '' AND ac.trans_id IN @@ -486,7 +652,7 @@ sub get_accounts { $project GROUP BY c.category - UNION + UNION ALL -- add gl @@ -496,20 +662,28 @@ sub get_accounts { JOIN chart c ON (c.id = ac.chart_id) JOIN gifi g ON (g.accno = c.gifi_accno) JOIN gl a ON (a.id = ac.trans_id) - $where + $dpt_join + WHERE $where + $ywhere + $glwhere + $dpt_where $category AND NOT (c.link = 'AR' OR c.link = 'AP') $project GROUP BY g.accno, g.description, c.category - UNION + UNION ALL SELECT '' AS accno, SUM(ac.amount) AS amount, '' AS description, c.category FROM acc_trans ac JOIN chart c ON (c.id = ac.chart_id) JOIN gl a ON (a.id = ac.trans_id) - $where + $dpt_join + WHERE $where + $ywhere + $glwhere + $dpt_where $category AND c.gifi_accno = '' AND NOT (c.link = 'AR' OR c.link = 'AP') @@ -517,8 +691,126 @@ sub get_accounts { GROUP BY c.category |; + if ($yearend) { + + # this is for the yearend + + $query .= qq| + + UNION ALL + + SELECT g.accno, sum(ac.amount) AS amount, + g.description, c.category + FROM yearend y + JOIN acc_trans ac ON (ac.trans_id = y.trans_id) + JOIN chart c ON (c.id = ac.chart_id) + JOIN gifi g ON (g.accno = c.accno) + $dpt_join + WHERE $yearendwhere + AND c.category = 'Q' + $dpt_where + $project + GROUP BY g.accno, g.description, c.category + |; + } + + if ($project_id) { + + $query .= qq| + + UNION ALL + + SELECT g.accno AS accno, SUM(ac.sellprice * ac.qty) AS amount, + g.description AS description, c.category + FROM invoice ac + JOIN ar a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.income_accno_id = c.id) + JOIN gifi g ON (g.accno = c.gifi_accno) + $dpt_join + WHERE 1 = 1 $projectwhere + $ywhere + AND c.category = 'I' + $dpt_where + AND ac.trans_id IN + ( + SELECT trans_id + FROM acc_trans + JOIN chart ON (chart_id = id) + WHERE link LIKE '%AR_paid%' + $subwhere + ) + $project + GROUP BY g.accno, g.description, c.category + + UNION ALL + + SELECT g.accno AS accno, SUM(ac.sellprice * ac.qty) AS amount, + g.description AS description, c.category + FROM invoice ac + JOIN ap a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.expense_accno_id = c.id) + JOIN gifi g ON (g.accno = c.gifi_accno) + $dpt_join + WHERE 1 = 1 $projectwhere + AND p.inventory_accno_id IS NULL + AND p.assembly = '0' + $ywhere + AND c.category = 'E' + $dpt_where + AND ac.trans_id IN + ( + SELECT trans_id + FROM acc_trans + JOIN chart ON (chart_id = id) + WHERE link LIKE '%AP_paid%' + $subwhere + ) + $project + GROUP BY g.accno, g.description, c.category + + UNION ALL + + SELECT g.accno AS accno, SUM(ac.sellprice * ac.allocated) * -1 AS amount, + g.description AS description, c.category + FROM invoice ac + JOIN ap a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.expense_accno_id = c.id) + JOIN gifi g ON (g.accno = c.gifi_accno) + $dpt_join + WHERE 1 = 1 $projectwhere + AND ac.assemblyitem = '0' + $ywhere + AND c.category = 'E' + $dpt_where + AND ac.trans_id IN + ( + SELECT trans_id + FROM acc_trans + JOIN chart ON (chart_id = id) + WHERE link LIKE '%AP_paid%' + $subwhere + ) + $project + GROUP BY g.accno, g.description, c.category + |; + } + } else { + if ($department_id) + { + $dpt_join = qq| + JOIN dpt_trans t ON (t.trans_id = ac.trans_id) + |; + $dpt_where = qq| + AND t.department_id = $department_id + |; + + } + $query = qq| SELECT g.accno, SUM(ac.amount) AS amount, @@ -526,32 +818,121 @@ sub get_accounts { FROM acc_trans ac JOIN chart c ON (c.id = ac.chart_id) JOIN gifi g ON (c.gifi_accno = g.accno) - $where + $dpt_join + WHERE $where + $ywhere + $dpt_from $category $project GROUP BY g.accno, g.description, c.category - UNION + UNION ALL SELECT '' AS accno, SUM(ac.amount) AS amount, '' AS description, c.category FROM acc_trans ac JOIN chart c ON (c.id = ac.chart_id) - $where + $dpt_join + WHERE $where + $ywhere + $dpt_from $category AND c.gifi_accno = '' $project - GROUP by c.category + GROUP BY c.category |; - + + if ($yearend) { + + # this is for the yearend + + $query .= qq| + + UNION ALL + + SELECT g.accno, sum(ac.amount) AS amount, + g.description, c.category + FROM yearend y + JOIN acc_trans ac ON (ac.trans_id = y.trans_id) + JOIN chart c ON (c.id = ac.chart_id) + JOIN gifi g ON (g.accno = c.accno) + $dpt_join + WHERE $yearendwhere + AND c.category = 'Q' + $dpt_where + $project + GROUP BY g.accno, g.description, c.category + |; + } + + if ($project_id) + { + + $query .= qq| + + UNION ALL + + SELECT g.accno AS accno, SUM(ac.sellprice * ac.qty) AS amount, + g.description AS description, c.category + FROM invoice ac + JOIN ar a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.income_accno_id = c.id) + JOIN gifi g ON (c.gifi_accno = g.accno) + $dpt_join + WHERE 1 = 1 $projectwhere + $ywhere + AND c.category = 'I' + $dpt_where + $project + GROUP BY g.accno, g.description, c.category + + UNION ALL + + SELECT g.accno AS accno, SUM(ac.sellprice * ac.qty) AS amount, + g.description AS description, c.category + FROM invoice ac + JOIN ap a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.expense_accno_id = c.id) + JOIN gifi g ON (c.gifi_accno = g.accno) + $dpt_join + WHERE 1 = 1 $projectwhere + AND p.inventory_accno_id IS NULL + AND p.assembly = '0' + $ywhere + AND c.category = 'E' + $dpt_where + $project + GROUP BY g.accno, g.description, c.category + + UNION ALL + + SELECT g.accno AS accno, SUM(ac.sellprice * ac.allocated) * -1 AS amount, + g.description AS description, c.category + FROM invoice ac + JOIN ap a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.expense_accno_id = c.id) + JOIN gifi g ON (c.gifi_accno = g.accno) + $dpt_join + WHERE 1 = 1 $projectwhere + AND ac.assemblyitem = '0' + $ywhere + AND c.category = 'E' + $dpt_where + $project + GROUP BY g.accno, g.description, c.category + |; + } + } - } else { + } else { # standard account if ($form->{method} eq 'cash') { - $query = qq| SELECT c.accno, sum(ac.amount) AS amount, @@ -559,7 +940,10 @@ sub get_accounts { FROM acc_trans ac JOIN chart c ON (c.id = ac.chart_id) JOIN ar a ON (a.id = ac.trans_id) - $where + $dpt_join + WHERE $where + $ywhere + $dpt_where $category AND ac.trans_id IN ( @@ -573,14 +957,17 @@ sub get_accounts { $project GROUP BY c.accno, c.description, c.category - UNION + UNION ALL SELECT c.accno, sum(ac.amount) AS amount, c.description, c.category FROM acc_trans ac JOIN chart c ON (c.id = ac.chart_id) JOIN ap a ON (a.id = ac.trans_id) - $where + $dpt_join + WHERE $where + $ywhere + $dpt_where $category AND ac.trans_id IN ( @@ -594,57 +981,262 @@ sub get_accounts { $project GROUP BY c.accno, c.description, c.category - UNION + UNION ALL SELECT c.accno, sum(ac.amount) AS amount, c.description, c.category FROM acc_trans ac JOIN chart c ON (c.id = ac.chart_id) JOIN gl a ON (a.id = ac.trans_id) - $where + $dpt_join + WHERE $where + $ywhere + $glwhere + $dpt_from $category AND NOT (c.link = 'AR' OR c.link = 'AP') $project GROUP BY c.accno, c.description, c.category |; - - } else { - - $query = qq| - - SELECT c.accno, sum(ac.amount) AS amount, + + if ($yearend) { + + # this is for the yearend + + $query .= qq| + + UNION ALL + + SELECT c.accno, sum(ac.amount) AS amount, c.description, c.category - FROM acc_trans ac + FROM yearend y + JOIN acc_trans ac ON (ac.trans_id = y.trans_id) JOIN chart c ON (c.id = ac.chart_id) - $where - $category + $dpt_join + WHERE $yearendwhere + AND c.category = 'Q' + $dpt_where $project GROUP BY c.accno, c.description, c.category |; + } - } - - } + + if ($project_id) + { + $query .= qq| + + UNION ALL + + SELECT c.accno AS accno, SUM(ac.sellprice * ac.qty) AS amount, + c.description AS description, c.category + FROM invoice ac + JOIN ar a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.income_accno_id = c.id) + $dpt_join + WHERE 1 = 1 $projectwhere + $ywhere + AND c.category = 'I' + $dpt_where + AND ac.trans_id IN + ( + SELECT trans_id + FROM acc_trans + JOIN chart ON (chart_id = id) + WHERE link LIKE '%AR_paid%' + $subwhere + ) - my @accno; - my $accno; - my $ref; - - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); + $project + GROUP BY c.accno, c.description, c.category - while ($ref = $sth->fetchrow_hashref(NAME_lc)) - { + UNION ALL + + SELECT c.accno AS accno, SUM(ac.sellprice * ac.qty) AS amount, + c.description AS description, c.category + FROM invoice ac + JOIN ap a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.expense_accno_id = c.id) + $dpt_join + WHERE 1 = 1 $projectwhere + AND p.inventory_accno_id IS NULL + AND p.assembly = '0' + $ywhere + AND c.category = 'E' + $dpt_where + AND ac.trans_id IN + ( + SELECT trans_id + FROM acc_trans + JOIN chart ON (chart_id = id) + WHERE link LIKE '%AP_paid%' + $subwhere + ) + + $project + GROUP BY c.accno, c.description, c.category + + UNION ALL + + SELECT c.accno AS accno, SUM(ac.sellprice * ac.allocated) * -1 AS amount, + c.description AS description, c.category + FROM invoice ac + JOIN ap a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.expense_accno_id = c.id) + $dpt_join + WHERE 1 = 1 $projectwhere + AND ac.assemblyitem = '0' + $ywhere + AND c.category = 'E' + $dpt_where + AND ac.trans_id IN + ( + SELECT trans_id + FROM acc_trans + JOIN chart ON (chart_id = id) + WHERE link LIKE '%AP_paid%' + $subwhere + ) + + $project + GROUP BY c.accno, c.description, c.category + |; + } + + } else { + + if ($department_id) + { + $dpt_join = qq| + JOIN dpt_trans t ON (t.trans_id = ac.trans_id) + |; + $dpt_where = qq| + AND t.department_id = $department_id + |; + } + + + $query = qq| + + SELECT c.accno, sum(ac.amount) AS amount, + c.description, c.category + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + $dpt_join + WHERE $where + $ywhere + $dpt_where + $category + $project + GROUP BY c.accno, c.description, c.category + |; + + if ($yearend) { + + # this is for the yearend + + $query .= qq| + + UNION ALL + + SELECT c.accno, sum(ac.amount) AS amount, + c.description, c.category + FROM yearend y + JOIN acc_trans ac ON (ac.trans_id = y.trans_id) + JOIN chart c ON (c.id = ac.chart_id) + $dpt_join + WHERE $yearendwhere + AND c.category = 'Q' + $dpt_where + $project + GROUP BY c.accno, c.description, c.category + |; + } + + + if ($project_id) + { + + $query .= qq| + + UNION ALL + + SELECT c.accno AS accno, SUM(ac.sellprice * ac.qty) AS amount, + c.description AS description, c.category + FROM invoice ac + JOIN ar a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.income_accno_id = c.id) + $dpt_join + WHERE 1 = 1 $projectwhere + $ywhere + AND c.category = 'I' + $dpt_where + $project + GROUP BY c.accno, c.description, c.category + + UNION ALL + + SELECT c.accno AS accno, SUM(ac.sellprice * ac.qty) AS amount, + c.description AS description, c.category + FROM invoice ac + JOIN ap a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.expense_accno_id = c.id) + $dpt_join + WHERE 1 = 1 $projectwhere + AND p.inventory_accno_id IS NULL + AND p.assembly = '0' + $ywhere + AND c.category = 'E' + $dpt_where + $project + GROUP BY c.accno, c.description, c.category + + UNION ALL + + SELECT c.accno AS accno, SUM(ac.sellprice * ac.allocated) * -1 AS amount, + c.description AS description, c.category + FROM invoice ac + JOIN ap a ON (a.id = ac.trans_id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c on (p.expense_accno_id = c.id) + $dpt_join + WHERE 1 = 1 $projectwhere + AND ac.assemblyitem = '0' + $ywhere + AND c.category = 'E' + $dpt_where + $project + GROUP BY c.accno, c.description, c.category + |; + + } + } + } + + my @accno; + my $accno; + my $ref; + + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while ($ref = $sth->fetchrow_hashref(NAME_lc)) + { if ($ref->{category} eq 'C') { $ref->{category} = 'A'; } - + # get last heading account @accno = grep { $_ le "$ref->{accno}" } @headingaccounts; $accno = pop @accno; - if ($accno) { + if ($accno && ($accno ne $ref->{accno}) ) { if ($last_period) { $form->{$ref->{category}}{$accno}{last} += $ref->{amount}; @@ -681,7 +1273,7 @@ sub get_accounts { -sub trial_balance_details { +sub trial_balance { my ($self, $myconfig, $form) = @_; my $dbh = $form->dbconnect($myconfig); @@ -689,40 +1281,72 @@ sub trial_balance_details { my ($query, $sth, $ref); my %balance = (); my %trb = (); + my $null; + my $department_id; + my $project_id; + my @headingaccounts = (); + my $dpt_where; + my $dpt_join; + my $project; - my $where = "WHERE 1 = 1"; + my $where = "1 = 1"; + my $invwhere = $where; + + ($null, $department_id) = split /--/, $form->{department}; + ($null, $project_id) = split /--/, $form->{projectnumber}; - if ($form->{project_id}) { - $where .= qq| - AND a.project_id = $form->{project_id} + if ($department_id) { + $dpt_join = qq| + JOIN dpt_trans t ON (ac.trans_id = t.trans_id) + |; + $dpt_where = qq| + AND t.department_id = $department_id |; } + + # project_id only applies to getting transactions + # it has nothing to do with a trial balance + # but we use the same function to collect information + + if ($project_id) { + $project = qq| + AND ac.project_id = $project_id + |; + } + + ($form->{fromdate}, $form->{todate}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month}; + # get beginning balances if ($form->{fromdate}) { if ($form->{accounttype} eq 'gifi') { - $query = qq|SELECT g.accno, c.category, SUM(a.amount) AS amount, + $query = qq|SELECT g.accno, c.category, SUM(ac.amount) AS amount, g.description - FROM acc_trans a - JOIN chart c ON (a.chart_id = c.id) + FROM acc_trans ac + JOIN chart c ON (ac.chart_id = c.id) JOIN gifi g ON (c.gifi_accno = g.accno) - $where - AND a.transdate < '$form->{fromdate}' + $dpt_join + WHERE ac.transdate < '$form->{fromdate}' + $dpt_where + $project GROUP BY g.accno, c.category, g.description |; } else { - $query = qq|SELECT c.accno, c.category, SUM(a.amount) AS amount, + $query = qq|SELECT c.accno, c.category, SUM(ac.amount) AS amount, c.description - FROM acc_trans a - JOIN chart c ON (a.chart_id = c.id) - $where - AND a.transdate < '$form->{fromdate}' + FROM acc_trans ac + JOIN chart c ON (ac.chart_id = c.id) + $dpt_join + WHERE ac.transdate < '$form->{fromdate}' + $dpt_where + $project GROUP BY c.accno, c.category, c.description |; + } $sth = $dbh->prepare($query); @@ -761,7 +1385,6 @@ sub trial_balance_details { $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - my @headingaccounts = (); while ($ref = $sth->fetchrow_hashref(NAME_lc)) { $trb{$ref->{accno}}{description} = $ref->{description}; @@ -776,10 +1399,12 @@ sub trial_balance_details { if ($form->{fromdate} || $form->{todate}) { if ($form->{fromdate}) { - $where .= " AND a.transdate >= '$form->{fromdate}'"; + $where .= " AND ac.transdate >= '$form->{fromdate}'"; + $invwhere .= " AND a.transdate >= '$form->{fromdate}'"; } if ($form->{todate}) { - $where .= " AND a.transdate <= '$form->{todate}'"; + $where .= " AND ac.transdate <= '$form->{todate}'"; + $invwhere .= " AND a.transdate <= '$form->{todate}'"; } } @@ -787,82 +1412,214 @@ sub trial_balance_details { if ($form->{accounttype} eq 'gifi') { $query = qq|SELECT g.accno, g.description, c.category, - SUM(a.amount) AS amount - FROM acc_trans a - JOIN chart c ON (c.id = a.chart_id) + SUM(ac.amount) AS amount + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) JOIN gifi g ON (c.gifi_accno = g.accno) - $where + $dpt_join + WHERE $where + $dpt_where + $project GROUP BY g.accno, g.description, c.category - - UNION + |; + + if ($project_id) { - SELECT '' AS accno, '' AS description, c.category, - SUM(a.amount) AS amount - FROM acc_trans a - JOIN chart c ON (c.id = a.chart_id) - $where - AND c.gifi_accno = '' - GROUP BY c.category + $query .= qq| + + -- sold items + + UNION ALL + + SELECT g.accno, g.description, c.category, + SUM(ac.sellprice * ac.qty) AS amount + FROM invoice ac + JOIN ar a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.income_accno_id = c.id) + JOIN gifi g ON (c.gifi_accno = g.accno) + $dpt_join + WHERE $invwhere + $dpt_where + $project + GROUP BY g.accno, g.description, c.category + + UNION ALL + + -- bought services + + SELECT g.accno, g.description, c.category, + SUM(ac.sellprice * ac.qty) AS amount + FROM invoice ac + JOIN ap a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.expense_accno_id = c.id) + JOIN gifi g ON (c.gifi_accno = g.accno) + $dpt_join + WHERE $invwhere + AND p.inventory_accno_id IS NULL + AND p.assembly = '0' + $dpt_where + $project + GROUP BY g.accno, g.description, c.category + + -- COGS + + UNION ALL + + SELECT g.accno, g.description, c.category, + SUM(ac.sellprice * ac.allocated) * -1 AS amount + FROM invoice ac + JOIN ap a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.expense_accno_id = c.id) + JOIN gifi g ON (c.gifi_accno = g.accno) + $dpt_join + WHERE $invwhere + AND ac.assemblyitem = '0' + $dpt_where + $project + GROUP BY g.accno, g.description, c.category + + |; + } + + $query .= qq| ORDER BY accno|; } else { $query = qq|SELECT c.accno, c.description, c.category, - SUM(a.amount) AS amount - FROM acc_trans a - JOIN chart c ON (c.id = a.chart_id) - $where + SUM(ac.amount) AS amount + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + $dpt_join + WHERE $where + $dpt_where + $project GROUP BY c.accno, c.description, c.category + |; + + if ($project_id) { + + $query .= qq| + + -- sold items + + UNION ALL + + SELECT c.accno, c.description, c.category, + SUM(ac.sellprice * ac.qty) AS amount + FROM invoice ac + JOIN ar a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.income_accno_id = c.id) + $dpt_join + WHERE $invwhere + $dpt_where + $project + GROUP BY c.accno, c.description, c.category + + UNION ALL + + -- bought services + + SELECT c.accno, c.description, c.category, + SUM(ac.sellprice * ac.qty) AS amount + FROM invoice ac + JOIN ap a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.expense_accno_id = c.id) + $dpt_join + WHERE $invwhere + AND p.inventory_accno_id IS NULL + AND p.assembly = '0' + $dpt_where + $project + GROUP BY c.accno, c.description, c.category + + -- cogs + + UNION ALL + + SELECT c.accno, c.description, c.category, + SUM(ac.sellprice * ac.allocated) * -1 AS amount + FROM invoice ac + JOIN ap a ON (ac.trans_id = a.id) + JOIN parts p ON (ac.parts_id = p.id) + JOIN chart c ON (p.expense_accno_id = c.id) + $dpt_join + WHERE $invwhere + AND ac.assemblyitem = '0' + $dpt_where + $project + GROUP BY c.accno, c.description, c.category + + |; + } + + $query .= qq| ORDER BY accno|; } - + $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); - # prepare query for each account - - $query = qq|SELECT (SELECT SUM(a.amount) * -1 - FROM acc_trans a - JOIN chart c ON (c.id = a.chart_id) - $where - AND a.amount < 0 + $query = qq|SELECT (SELECT SUM(ac.amount) * -1 + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + $dpt_join + WHERE $where + $dpt_where + $project + AND ac.amount < 0 AND c.accno = ?) AS debit, - (SELECT SUM(a.amount) - FROM acc_trans a - JOIN chart c ON (c.id = a.chart_id) - $where - AND a.amount > 0 + + (SELECT SUM(ac.amount) + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + $dpt_join + WHERE $where + $dpt_where + $project + AND ac.amount > 0 AND c.accno = ?) AS credit |; if ($form->{accounttype} eq 'gifi') { - $query = qq|SELECT (SELECT SUM(a.amount) * -1 - FROM acc_trans a - JOIN chart c ON (c.id = a.chart_id) - $where - AND a.amount < 0 + $query = qq|SELECT (SELECT SUM(ac.amount) * -1 + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + $dpt_join + WHERE $where + $dpt_where + $project + AND ac.amount < 0 AND c.gifi_accno = ?) AS debit, - (SELECT SUM(a.amount) - FROM acc_trans a - JOIN chart c ON (c.id = a.chart_id) - $where - AND a.amount > 0 + + (SELECT SUM(ac.amount) + FROM acc_trans ac + JOIN chart c ON (c.id = ac.chart_id) + $dpt_join + WHERE $where + $dpt_where + $project + AND ac.amount > 0 AND c.gifi_accno = ?) AS credit|; } - - $drcr = $dbh->prepare($query); - # calculate the debit and credit in the period + $drcr = $dbh->prepare($query); + + # calculate debit and credit for the period while ($ref = $sth->fetchrow_hashref(NAME_lc)) { $trb{$ref->{accno}}{description} = $ref->{description}; $trb{$ref->{accno}}{charttype} = 'A'; $trb{$ref->{accno}}{category} = $ref->{category}; $trb{$ref->{accno}}{amount} += $ref->{amount}; - } $sth->finish; @@ -870,29 +1627,41 @@ sub trial_balance_details { foreach my $accno (sort keys %trb) { $ref = (); - + $ref->{accno} = $accno; map { $ref->{$_} = $trb{$accno}{$_} } qw(description category charttype amount); $ref->{balance} = $form->round_amount($balance{$ref->{accno}}, 2); if ($trb{$accno}{charttype} eq 'A') { - # get DR/CR - $drcr->execute($ref->{accno}, $ref->{accno}) || $form->dberror($query); - - ($debit, $credit) = (0,0); - while (($debit, $credit) = $drcr->fetchrow_array) { - $ref->{debit} += $debit; - $ref->{credit} += $credit; + if ($project_id) { + + if ($ref->{amount} < 0) { + $ref->{debit} = $ref->{amount} * -1; + } else { + $ref->{credit} = $ref->{amount}; + } + next if $form->round_amount($ref->{amount}, 2) == 0; + + } else { + + # get DR/CR + $drcr->execute($ref->{accno}, $ref->{accno}); + + ($debit, $credit) = (0,0); + while (($debit, $credit) = $drcr->fetchrow_array) { + $ref->{debit} += $debit; + $ref->{credit} += $credit; + } + $drcr->finish; + } - $drcr->finish; $ref->{debit} = $form->round_amount($ref->{debit}, 2); $ref->{credit} = $form->round_amount($ref->{credit}, 2); } - # add subtotal @accno = grep { $_ le "$ref->{accno}" } @headingaccounts; $accno = pop @accno; @@ -900,7 +1669,7 @@ sub trial_balance_details { $trb{$accno}{debit} += $ref->{debit}; $trb{$accno}{credit} += $ref->{credit}; } - + push @{ $form->{TB} }, $ref; } @@ -920,7 +1689,6 @@ sub trial_balance_details { } - sub aging { my ($self, $myconfig, $form) = @_; @@ -928,10 +1696,15 @@ sub aging { my $dbh = $form->dbconnect($myconfig); my $invoice = ($form->{arap} eq 'ar') ? 'is' : 'ir'; + ($null, $form->{todate}) = $form->from_to($form->{year}, $form->{month}) if $form->{year} && $form->{month}; + $form->{todate} = $form->current_date($myconfig) unless ($form->{todate}); + my $where = "1 = 1"; my $name; + my $null; + my $ref; if ($form->{"$form->{ct}_id"}) { $where .= qq| AND ct.id = $form->{"$form->{ct}_id"}|; @@ -942,11 +1715,22 @@ sub aging { } } + my $dpt_join; + if ($form->{department}) { + ($null, $department_id) = split /--/, $form->{department}; + $dpt_join = qq| + JOIN department d ON (a.department_id = d.id) + |; + + $where .= qq| AND a.department_id = $department_id|; + } + # select outstanding vendors or customers, depends on $ct - my $query = qq|SELECT DISTINCT ct.id, ct.name - FROM $form->{ct} ct, $form->{arap} a + my $query = qq|SELECT DISTINCT ct.id, ct.name, ct.language_code + FROM $form->{ct} ct + JOIN $form->{arap} a ON (a.$form->{ct}_id = ct.id) + $dpt_join WHERE $where - AND a.$form->{ct}_id = ct.id AND a.paid != a.amount AND (a.transdate <= '$form->{todate}') ORDER BY ct.name|; @@ -955,115 +1739,140 @@ sub aging { $sth->execute || $form->dberror; my $buysell = ($form->{arap} eq 'ar') ? 'buy' : 'sell'; + + my %interval = ( 'Pg' => { + 'c0' => "(date '$form->{todate}' - interval '0 days')", + 'c30' => "(date '$form->{todate}' - interval '30 days')", + 'c60' => "(date '$form->{todate}' - interval '60 days')", + 'c90' => "(date '$form->{todate}' - interval '90 days')" }, + 'DB2' => { + 'c0' => "(date ('$form->{todate}') - 0 days)", + 'c30' => "(date ('$form->{todate}') - 30 days)", + 'c60' => "(date ('$form->{todate}') - 60 days)", + 'c90' => "(date ('$form->{todate}') - 90 days)" } + ); + + $interval{Oracle} = $interval{PgPP} = $interval{Pg}; + # for each company that has some stuff outstanding - while ( my ($id) = $sth->fetchrow_array ) { + my $id; + while (($id, $null, $language_code) = $sth->fetchrow_array ) { $query = qq| - --- between 0-30 days - - SELECT $form->{ct}.id AS ctid, $form->{ct}.name, - addr1, addr2, addr3, addr4, contact, - phone as customerphone, fax as customerfax, $form->{ct}number, - "invnumber", "transdate", - (amount - paid) as "c0", 0.00 as "c30", 0.00 as "c60", 0.00 as "c90", - "duedate", invoice, $form->{arap}.id, - (SELECT $buysell FROM exchangerate - WHERE $form->{arap}.curr = exchangerate.curr - AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate - FROM $form->{arap}, $form->{ct} - WHERE paid != amount - AND $form->{arap}.$form->{ct}_id = $form->{ct}.id - AND $form->{ct}.id = $id + SELECT c.id AS ctid, c.name, + c.address1, c.address2, c.city, c.state, c.zipcode, c.country, + c.contact, c.email, + c.phone as customerphone, c.fax as customerfax, c.$form->{ct}number, + a.invnumber, a.transdate, a.till, a.ordnumber, a.notes, + (a.amount - a.paid) as c0, 0.00 as c30, 0.00 as c60, 0.00 as c90, + a.duedate, a.invoice, a.id, + (SELECT $buysell FROM exchangerate e + WHERE a.curr = e.curr + AND e.transdate = a.transdate) AS exchangerate + FROM $form->{arap} a + JOIN $form->{ct} c ON (a.$form->{ct}_id = c.id) + WHERE a.paid != a.amount + AND c.id = $id AND ( - transdate <= (date '$form->{todate}' - interval '0 days') - AND transdate >= (date '$form->{todate}' - interval '30 days') + a.transdate <= $interval{$myconfig->{dbdriver}}{c0} + AND a.transdate >= $interval{$myconfig->{dbdriver}}{c30} ) UNION --- between 31-60 days - - SELECT $form->{ct}.id AS ctid, $form->{ct}.name, - addr1, addr2, addr3, addr4, contact, - phone as customerphone, fax as customerfax, $form->{ct}number, - "invnumber", "transdate", - 0.00 as "c0", (amount - paid) as "c30", 0.00 as "c60", 0.00 as "c90", - "duedate", invoice, $form->{arap}.id, - (SELECT $buysell FROM exchangerate - WHERE $form->{arap}.curr = exchangerate.curr - AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate - FROM $form->{arap}, $form->{ct} - WHERE paid != amount - AND $form->{arap}.$form->{ct}_id = $form->{ct}.id - AND $form->{ct}.id = $id + SELECT c.id AS ctid, c.name, + c.address1, c.address2, c.city, c.state, c.zipcode, c.country, + c.contact, c.email, + c.phone as customerphone, c.fax as customerfax, c.$form->{ct}number, + a.invnumber, a.transdate, a.till, a.ordnumber, a.notes, + 0.00 as c0, (a.amount - a.paid) as c30, 0.00 as c60, 0.00 as c90, + a.duedate, a.invoice, a.id, + (SELECT $buysell FROM exchangerate e + WHERE a.curr = e.curr + AND e.transdate = a.transdate) AS exchangerate + FROM $form->{arap} a + JOIN $form->{ct} c ON (a.$form->{ct}_id = c.id) + WHERE a.paid != a.amount + AND c.id = $id AND ( - transdate < (date '$form->{todate}' - interval '30 days') - AND transdate >= (date '$form->{todate}' - interval '60 days') + a.transdate < $interval{$myconfig->{dbdriver}}{c30} + AND a.transdate >= $interval{$myconfig->{dbdriver}}{c60} ) UNION --- between 61-90 days - - SELECT $form->{ct}.id AS ctid, $form->{ct}.name, - addr1, addr2, addr3, addr4, contact, - phone as customerphone, fax as customerfax, $form->{ct}number, - "invnumber", "transdate", - 0.00 as "c0", 0.00 as "c30", (amount - paid) as "c60", 0.00 as "c90", - "duedate", invoice, $form->{arap}.id, - (SELECT $buysell FROM exchangerate - WHERE $form->{arap}.curr = exchangerate.curr - AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate - FROM $form->{arap}, $form->{ct} - WHERE paid != amount - AND $form->{arap}.$form->{ct}_id = $form->{ct}.id - AND $form->{ct}.id = $id + SELECT c.id AS ctid, c.name, + c.address1, c.address2, c.city, c.state, c.zipcode, c.country, + c.contact, c.email, + c.phone as customerphone, c.fax as customerfax, c.$form->{ct}number, + a.invnumber, a.transdate, a.till, a.ordnumber, a.notes, + 0.00 as c0, 0.00 as c30, (a.amount - a.paid) as c60, 0.00 as c90, + a.duedate, a.invoice, a.id, + (SELECT $buysell FROM exchangerate e + WHERE a.curr = e.curr + AND e.transdate = a.transdate) AS exchangerate + FROM $form->{arap} a + JOIN $form->{ct} c ON (a.$form->{ct}_id = c.id) + WHERE a.paid != a.amount + AND c.id = $id AND ( - transdate < (date '$form->{todate}' - interval '60 days') - AND transdate >= (date '$form->{todate}' - interval '90 days') + a.transdate < $interval{$myconfig->{dbdriver}}{c60} + AND a.transdate >= $interval{$myconfig->{dbdriver}}{c90} ) UNION --- over 90 days - - SELECT $form->{ct}.id AS ctid, $form->{ct}.name, - addr1, addr2, addr3, addr4, contact, - phone as customerphone, fax as customerfax, $form->{ct}number, - "invnumber", "transdate", - 0.00 as "c0", 0.00 as "c30", 0.00 as "c60", (amount - paid) as "c90", - "duedate", invoice, $form->{arap}.id, - (SELECT $buysell FROM exchangerate - WHERE $form->{arap}.curr = exchangerate.curr - AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate - FROM $form->{arap}, $form->{ct} - WHERE paid != amount - AND $form->{arap}.$form->{ct}_id = $form->{ct}.id - AND $form->{ct}.id = $id - AND transdate < (date '$form->{todate}' - interval '90 days') + SELECT c.id AS ctid, c.name, + c.address1, c.address2, c.city, c.state, c.zipcode, c.country, + c.contact, c.email, + c.phone as customerphone, c.fax as customerfax, c.$form->{ct}number, + a.invnumber, a.transdate, a.till, a.ordnumber, a.notes, + 0.00 as c0, 0.00 as c30, 0.00 as c60, (a.amount - a.paid) as c90, + a.duedate, a.invoice, a.id, + (SELECT $buysell FROM exchangerate e + WHERE a.curr = e.curr + AND e.transdate = a.transdate) AS exchangerate + FROM $form->{arap} a + JOIN $form->{ct} c ON (a.$form->{ct}_id = c.id) + WHERE a.paid != a.amount + AND c.id = $id + AND a.transdate < $interval{$myconfig->{dbdriver}}{c90} ORDER BY - ctid, invnumber, transdate + ctid, transdate, invnumber |; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror; - while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { $ref->{module} = ($ref->{invoice}) ? $invoice : $form->{arap}; + $ref->{module} = 'ps' if $ref->{till}; $ref->{exchangerate} = 1 unless $ref->{exchangerate}; + $ref->{language_code} = $language_code; push @{ $form->{AG} }, $ref; } $sth->finish; } + $sth->finish; + + # get language + my $query = qq|SELECT * + FROM language + ORDER BY 2|; + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + while ($ref = $sth->fetchrow_hashref(NAME_lc)) { + push @{ $form->{all_language} }, $ref; + } $sth->finish; + # disconnect $dbh->disconnect; @@ -1079,11 +1888,8 @@ sub get_customer { my $query = qq|SELECT name, email, cc, bcc FROM $form->{ct} ct WHERE ct.id = $form->{"$form->{ct}_id"}|; - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror; - - ($form->{$form->{ct}}, $form->{email}, $form->{cc}, $form->{bcc}) = $sth->fetchrow_array; - $sth->finish; + ($form->{$form->{ct}}, $form->{email}, $form->{cc}, $form->{bcc}) = $dbh->selectrow_array($query); + $dbh->disconnect; } @@ -1096,29 +1902,34 @@ sub get_taxaccounts { my $dbh = $form->dbconnect($myconfig); # get tax accounts - my $query = qq|SELECT accno, description - FROM chart - WHERE link LIKE '%CT_tax%' - ORDER BY accno|; + my $query = qq|SELECT c.accno, c.description, t.rate, c.link + FROM chart c, tax t + WHERE c.link LIKE '%CT_tax%' + AND c.id = t.chart_id + ORDER BY c.accno|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror; - while ( my ($accno, $description) = $sth->fetchrow_array ) { - push @{ $form->{taxaccounts} }, "$accno--$description"; + my $ref = (); + while ($ref = $sth->fetchrow_hashref(NAME_lc) ) { + push @{ $form->{taxaccounts} }, $ref; } $sth->finish; # get gifi tax accounts - my $query = qq|SELECT DISTINCT ON (g.accno) g.accno, g.description - FROM gifi g, chart c + my $query = qq|SELECT DISTINCT g.accno, g.description, + sum(t.rate) AS rate + FROM gifi g, chart c, tax t WHERE g.accno = c.gifi_accno + AND c.id = t.chart_id AND c.link LIKE '%CT_tax%' + GROUP BY g.accno, g.description ORDER BY accno|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror; - while ( my ($accno, $description) = $sth->fetchrow_array ) { - push @{ $form->{gifi_taxaccounts} }, "$accno--$description"; + while ($ref = $sth->fetchrow_hashref(NAME_lc) ) { + push @{ $form->{gifi_taxaccounts} }, $ref; } $sth->finish; @@ -1134,34 +1945,52 @@ sub tax_report { # connect to database my $dbh = $form->dbconnect($myconfig); + my ($null, $department_id) = split /--/, $form->{department}; + # build WHERE - my $where = qq|WHERE ac.trans_id = a.id - AND ac.chart_id = ch.id|; - + my $where = "1 = 1"; + my $cashwhere = ""; - if ($form->{accno} =~ /^gifi_/) { - my ($null, $accno) = split /_/, $form->{accno}; - $where .= qq| AND ch.gifi_accno = '$accno'|; - } else { - $where .= qq| AND ch.accno = '$form->{accno}'|; + if ($department_id) { + $where .= qq| + AND a.department_id = $department_id + |; } + + my $query; + my $sth; + my $accno; + my $rate; + + if ($form->{accno}) { + if ($form->{accno} =~ /^gifi_/) { + ($null, $accno) = split /_/, $form->{accno}; + $rate = $form->{"$form->{accno}_rate"}; + $accno = qq| AND ch.gifi_accno = '$accno'|; + } else { + $accno = $form->{accno}; + $rate = $form->{"$form->{accno}_rate"}; + $accno = qq| AND ch.accno = '$accno'|; + } + } + $rate *= 1; my $table; + my $ARAP; if ($form->{db} eq 'ar') { - $where .= " AND n.id = a.customer_id"; $table = "customer"; + $ARAP = "AR"; } if ($form->{db} eq 'ap') { - $where .= " AND n.id = a.vendor_id"; $table = "vendor"; + $ARAP = "AP"; } - my $transdate = ($form->{cashbased}) ? "a.datepaid" : "ac.transdate"; - if ($form->{cashbased}) { - $where .= " AND a.amount = a.paid"; - } + my $transdate = "a.transdate"; + ($form->{fromdate}, $form->{todate}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month}; + # if there are any dates construct a where if ($form->{fromdate} || $form->{todate}) { if ($form->{fromdate}) { @@ -1171,29 +2000,372 @@ sub tax_report { $where .= " AND $transdate <= '$form->{todate}'"; } } + + + if ($form->{method} eq 'cash') { + $transdate = "a.datepaid"; + + my $todate = ($form->{todate}) ? $form->{todate} : $form->current_date($myconfig); + + $cashwhere = qq| + AND ac.trans_id IN + ( + SELECT trans_id + FROM acc_trans + JOIN chart ON (chart_id = id) + WHERE link LIKE '%${ARAP}_paid%' + AND $transdate <= '$todate' + AND a.paid = a.amount + ) + |; + + } + + + my $ml = ($form->{db} eq 'ar') ? 1 : -1; - my $query = qq|SELECT a.id, a.invoice, $transdate AS transdate, a.invnumber, - n.name, a.netamount,|; - my $sortorder = join ', ', $form->sort_columns(qw(transdate invnumber name)); - $sortorder = $form->{sort} unless $sortorder; + my %ordinal = ( 'transdate' => 3, + 'invnumber' => 4, + 'name' => 5 + ); - if ($form->{db} eq 'ar') { - $query .= " ac.amount AS tax"; - } - if ($form->{db} eq 'ap') { - $query .= " ac.amount * -1 AS tax"; + my @a = qw(transdate invnumber name); + my $sortorder = $form->sort_order(\@a, \%ordinal); + + $rate = 1 unless $rate; + + if ($form->{summary}) { + + $query = qq|SELECT a.id, '0' AS invoice, $transdate AS transdate, + a.invnumber, n.name, a.netamount, + ac.amount * $ml AS tax, + a.till + FROM acc_trans ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN chart ch ON (ch.id = ac.chart_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE $where + $accno + AND a.invoice = '0' + $cashwhere + + UNION + + SELECT a.id, '1' AS invoice, $transdate AS transdate, + a.invnumber, n.name, + sum(ac.sellprice * ac.qty) * $ml AS netamount, + sum(ac.sellprice * ac.qty) * $rate * $ml AS tax, + a.till + FROM invoice ac + JOIN partstax pt ON (pt.parts_id = ac.parts_id) + JOIN chart ch ON (ch.id = pt.chart_id) + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN $table n ON (n.id = a.${table}_id) + JOIN ${table}tax t ON (t.${table}_id = n.id AND t.chart_id = ch.id) + WHERE $where + $accno + AND a.invoice = '1' + $cashwhere + GROUP BY a.id, a.invoice, $transdate, a.invnumber, n.name, + a.till + |; + + if ($form->{fromdate}) { + # include open transactions from previous period + if ($cashwhere) { + $query .= qq| + UNION + + SELECT a.id, '0' AS invoice, $transdate AS transdate, + a.invnumber, n.name, a.netamount, + ac.amount * $ml AS tax, + a.till + FROM acc_trans ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN chart ch ON (ch.id = ac.chart_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE a.datepaid >= '$form->{fromdate}' + $accno + AND a.invoice = '0' + $cashwhere + + UNION + + SELECT a.id, '1' AS invoice, $transdate AS transdate, + a.invnumber, n.name, + sum(ac.sellprice * ac.qty) * $ml AS netamount, + sum(ac.sellprice * ac.qty) * $rate * $ml AS tax, + a.till + FROM invoice ac + JOIN partstax pt ON (pt.parts_id = ac.parts_id) + JOIN chart ch ON (ch.id = pt.chart_id) + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN $table n ON (n.id = a.${table}_id) + JOIN ${table}tax t ON (t.${table}_id = n.id AND t.chart_id = ch.id) + WHERE a.datepaid >= '$form->{fromdate}' + $accno + AND a.invoice = '1' + $cashwhere + GROUP BY a.id, a.invoice, $transdate, a.invnumber, n.name, + a.till + |; + } + } + + + } else { + + $query = qq|SELECT a.id, '0' AS invoice, $transdate AS transdate, + a.invnumber, n.name, a.netamount, + ac.amount * $ml AS tax, + a.notes AS description, a.till + FROM acc_trans ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN chart ch ON (ch.id = ac.chart_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE $where + $accno + AND a.invoice = '0' + $cashwhere + + UNION + + SELECT a.id, '1' AS invoice, $transdate AS transdate, + a.invnumber, n.name, + i.sellprice * i.qty * $ml AS netamount, + i.sellprice * i.qty * $rate * $ml AS tax, + i.description, a.till + FROM acc_trans ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN chart ch ON (ch.id = ac.chart_id) + JOIN $table n ON (n.id = a.${table}_id) + JOIN ${table}tax t ON (t.${table}_id = n.id AND t.chart_id = ch.id) + JOIN invoice i ON (i.trans_id = a.id) + JOIN partstax pt ON (pt.parts_id = i.parts_id AND pt.chart_id = ch.id) + WHERE $where + $accno + AND a.invoice = '1' + $cashwhere + |; + + if ($form->{fromdate}) { + if ($cashwhere) { + $query .= qq| + UNION + + SELECT a.id, '0' AS invoice, $transdate AS transdate, + a.invnumber, n.name, a.netamount, + ac.amount * $ml AS tax, + a.notes AS description, a.till + FROM acc_trans ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN chart ch ON (ch.id = ac.chart_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE a.datepaid >= '$form->{fromdate}' + $accno + AND a.invoice = '0' + $cashwhere + + UNION + + SELECT a.id, '1' AS invoice, $transdate AS transdate, + a.invnumber, n.name, + i.sellprice * i.qty * $ml AS netamount, + i.sellprice * i.qty * $rate * $ml AS tax, + i.description, a.till + FROM acc_trans ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN chart ch ON (ch.id = ac.chart_id) + JOIN $table n ON (n.id = a.${table}_id) + JOIN ${table}tax t ON (t.${table}_id = n.id AND t.chart_id = ch.id) + JOIN invoice i ON (i.trans_id = a.id) + JOIN partstax pt ON (pt.parts_id = i.parts_id AND pt.chart_id = ch.id) + WHERE a.datepaid >= '$form->{fromdate}' + $accno + AND a.invoice = '1' + $cashwhere + |; + } + } + } + + + if ($form->{report} =~ /nontaxable/) { + + if ($form->{summary}) { + # only gather up non-taxable transactions + $query = qq|SELECT a.id, '0' AS invoice, $transdate AS transdate, + a.invnumber, n.name, a.netamount, a.till + FROM acc_trans ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE $where + AND a.invoice = '0' + AND a.netamount = a.amount + $cashwhere + GROUP BY a.id, $transdate, a.invnumber, n.name, a.netamount, + a.till + + UNION + + SELECT a.id, '1' AS invoice, $transdate AS transdate, + a.invnumber, n.name, + sum(ac.sellprice * ac.qty) * $ml AS netamount, a.till + FROM invoice ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE $where + AND a.invoice = '1' + AND ( + a.${table}_id NOT IN ( + SELECT ${table}_id FROM ${table}tax t (${table}_id) + ) OR + ac.parts_id NOT IN ( + SELECT parts_id FROM partstax p (parts_id) + ) + ) + $cashwhere + GROUP BY a.id, a.invnumber, $transdate, n.name, a.till + |; + + if ($form->{fromdate}) { + if ($cashwhere) { + $query .= qq| + UNION + + SELECT a.id, '0' AS invoice, $transdate AS transdate, + a.invnumber, n.name, a.netamount, a.till + FROM acc_trans ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE a.datepaid >= '$form->{fromdate}' + AND a.invoice = '0' + AND a.netamount = a.amount + $cashwhere + GROUP BY a.id, $transdate, a.invnumber, n.name, a.netamount, + a.till + + UNION + + SELECT a.id, '1' AS invoice, $transdate AS transdate, + a.invnumber, n.name, + sum(ac.sellprice * ac.qty) * $ml AS netamount, a.till + FROM invoice ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE a.datepaid >= '$form->{fromdate}' + AND a.invoice = '1' + AND ( + a.${table}_id NOT IN ( + SELECT ${table}_id FROM ${table}tax t (${table}_id) + ) OR + ac.parts_id NOT IN ( + SELECT parts_id FROM partstax p (parts_id) + ) + ) + $cashwhere + GROUP BY a.id, a.invnumber, $transdate, n.name, a.till + |; + } + } + + } else { + + # gather up details for non-taxable transactions + $query = qq|SELECT a.id, '0' AS invoice, $transdate AS transdate, + a.invnumber, n.name, a.netamount, + a.notes AS description, a.till + FROM acc_trans ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE $where + AND a.invoice = '0' + AND a.netamount = a.amount + $cashwhere + GROUP BY a.id, $transdate, a.invnumber, n.name, a.netamount, + a.notes, a.till + + UNION + + SELECT a.id, '1' AS invoice, $transdate AS transdate, + a.invnumber, n.name, + sum(ac.sellprice * ac.qty) * $ml AS netamount, + ac.description, a.till + FROM invoice ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE $where + AND a.invoice = '1' + AND ( + a.${table}_id NOT IN ( + SELECT ${table}_id FROM ${table}tax t (${table}_id) + ) OR + ac.parts_id NOT IN ( + SELECT parts_id FROM partstax p (parts_id) + ) + ) + $cashwhere + GROUP BY a.id, a.invnumber, $transdate, n.name, + ac.description, a.till + |; + + if ($form->{fromdate}) { + if ($cashwhere) { + $query .= qq| + UNION + + SELECT a.id, '0' AS invoice, $transdate AS transdate, + a.invnumber, n.name, a.netamount, + a.notes AS description, a.till + FROM acc_trans ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE a.datepaid >= '$form->{fromdate}' + AND a.invoice = '0' + AND a.netamount = a.amount + $cashwhere + GROUP BY a.id, $transdate, a.invnumber, n.name, a.netamount, + a.notes, a.till + + UNION + + SELECT a.id, '1' AS invoice, $transdate AS transdate, + a.invnumber, n.name, + sum(ac.sellprice * ac.qty) * $ml AS netamount, + ac.description, a.till + FROM invoice ac + JOIN $form->{db} a ON (a.id = ac.trans_id) + JOIN $table n ON (n.id = a.${table}_id) + WHERE a.datepaid >= '$form->{fromdate}' + AND a.invoice = '1' + AND ( + a.${table}_id NOT IN ( + SELECT ${table}_id FROM ${table}tax t (${table}_id) + ) OR + ac.parts_id NOT IN ( + SELECT parts_id FROM partstax p (parts_id) + ) + ) + $cashwhere + GROUP BY a.id, a.invnumber, $transdate, n.name, + ac.description, a.till + |; + } + } + + } } + $query .= qq| - FROM acc_trans ac, "$form->{db}" a, "$table" n, chart ch - $where - ORDER by $sortorder|; + ORDER by $sortorder|; - my $sth = $dbh->prepare($query); + $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); while ( my $ref = $sth->fetchrow_hashref(NAME_lc)) { - push @{ $form->{TR} }, $ref; + $ref->{tax} = $form->round_amount($ref->{tax}, 2); + push @{ $form->{TR} }, $ref if $ref->{netamount} != 0; } $sth->finish; @@ -1208,21 +2380,23 @@ sub paymentaccounts { # connect to database, turn AutoCommit off my $dbh = $form->dbconnect_noauto($myconfig); - my $arap = uc $form->{db}; - $arap .= "_paid"; + my $ARAP = uc $form->{db}; # get A(R|P)_paid accounts my $query = qq|SELECT accno, description FROM chart - WHERE link LIKE '%$arap%'|; + WHERE link LIKE '%${ARAP}_paid%' + ORDER BY accno|; my $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { push @{ $form->{PR} }, $ref; } - $sth->finish; + + $form->all_years($dbh, $myconfig); + $dbh->disconnect; } @@ -1242,9 +2416,62 @@ sub payments { if ($form->{db} eq 'ap') { $table = 'vendor'; } + + + my $query; + my $sth; + my $dpt_join; + my $where; + my $var; + + if ($form->{department_id}) { + $dpt_join = qq| + JOIN dpt_trans t ON (t.trans_id = ac.trans_id) + |; + + $where = qq| + AND t.department_id = $form->{department_id} + |; + } + + ($form->{fromdate}, $form->{todate}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month}; - my ($query, $sth); + if ($form->{fromdate}) { + $where .= " AND ac.transdate >= '$form->{fromdate}'"; + } + if ($form->{todate}) { + $where .= " AND ac.transdate <= '$form->{todate}'"; + } + if (!$form->{fx_transaction}) { + $where .= " AND ac.fx_transaction = '0'"; + } + + if ($form->{description}) { + $var = $form->like(lc $form->{description}); + $where .= " AND lower(c.name) LIKE '$var'"; + } + if ($form->{source}) { + $var = $form->like(lc $form->{source}); + $where .= " AND lower(ac.source) LIKE '$var'"; + } + if ($form->{memo}) { + $var = $form->like(lc $form->{memo}); + $where .= " AND lower(ac.memo) LIKE '$var'"; + } + + my %ordinal = ( 'name' => 1, + 'transdate' => 2, + 'source' => 4, + 'employee' => 6, + 'till' => 7 + ); + + my @a = qw(name transdate employee); + my $sortorder = $form->sort_order(\@a, \%ordinal); + my $glwhere = $where; + $glwhere =~ s/\(c.name\)/\(g.description\)/; + # cycle through each id foreach my $accno (split(/ /, $form->{paymentaccounts})) { @@ -1258,37 +2485,51 @@ sub payments { push @{ $form->{PR} }, $ref; $sth->finish; - $query = qq|SELECT c.name, a.invnumber, a.ordnumber, - ac.transdate, - ac.amount * $ml AS paid, ac.source, a.invoice, a.id, - '$form->{db}' AS module - FROM $table c, acc_trans ac, $form->{db} a - WHERE c.id = a.${table}_id - AND ac.trans_id = a.id - AND ac.chart_id = $ref->{id}|; - - $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate}; - $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate}; + $query = qq|SELECT c.name, ac.transdate, sum(ac.amount) * $ml AS paid, + ac.source, ac.memo, e.name AS employee, a.till, a.curr + FROM acc_trans ac + JOIN $form->{db} a ON (ac.trans_id = a.id) + JOIN $table c ON (c.id = a.${table}_id) + LEFT JOIN employee e ON (a.employee_id = e.id) + $dpt_join + WHERE ac.chart_id = $ref->{id} + $where|; + + if ($form->{till}) { + $query .= " AND a.invoice = '1' + AND NOT a.till IS NULL"; + + if ($myconfig->{role} eq 'user') { + $query .= " AND e.login = '$form->{login}'"; + } + } $query .= qq| + GROUP BY c.name, ac.transdate, ac.source, ac.memo, + e.name, a.till, a.curr + |; + + if (! $form->{till}) { +# don't need gl for a till + + $query .= qq| UNION - SELECT g.description, g.reference, NULL AS ordnumber, - ac.transdate, - ac.amount * $ml AS paid, ac.source, '0' as invoice, g.id, - 'gl' AS module - FROM gl g, acc_trans ac - WHERE g.id = ac.trans_id - AND ac.chart_id = $ref->{id} - AND (ac.amount * $ml) > 0 + SELECT g.description, ac.transdate, sum(ac.amount) * $ml AS paid, ac.source, + ac.memo, e.name AS employee, '' AS till, '' AS curr + FROM acc_trans ac + JOIN gl g ON (g.id = ac.trans_id) + LEFT JOIN employee e ON (g.employee_id = e.id) + $dpt_join + WHERE ac.chart_id = $ref->{id} + $glwhere + AND (ac.amount * $ml) > 0 + GROUP BY g.description, ac.transdate, ac.source, ac.memo, e.name |; - $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate}; - $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate}; - + } - my $sortorder = join ', ', $form->sort_columns(qw(name invnumber ordnumber transdate source)); - - $query .= " ORDER BY $sortorder"; + $query .= qq| + ORDER BY $sortorder|; $sth = $dbh->prepare($query); $sth->execute || $form->dberror($query); diff --git a/sql-ledger/SL/User.pm b/sql-ledger/SL/User.pm index d9b463d6b..e7e0b9cbc 100644 --- a/sql-ledger/SL/User.pm +++ b/sql-ledger/SL/User.pm @@ -1,18 +1,18 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (C) 2001 +# Copyright (C) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org # Web: http://www.sql-ledger.org # -# Contributors: +# Contributors: Jim Rawlings # # 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 @@ -34,7 +34,6 @@ sub new { my $self = {}; if ($login ne "") { - # check if the file is locked &error("", "$memfile locked!") if (-f "${memfile}.LCK"); open(MEMBER, "$memfile") or &error("", "$memfile : $!"); @@ -46,7 +45,7 @@ sub new { next if /^(#|\s)/; # remove comments - s/\s#.*//g; + s/^\s*#.*//g; # remove any trailing whitespace s/^\s*(.*?)\s*$/$1/; @@ -96,17 +95,18 @@ sub country_codes { sub login { my ($self, $form, $userspath) = @_; - + my $rc = -3; + if ($self->{login}) { - + if ($self->{password}) { - $form->{password} = crypt $form->{password}, substr($self->{login}, 0, 2); - if ($self->{password} ne $form->{password}) { + my $password = crypt $form->{password}, substr($self->{login}, 0, 2); + if ($self->{password} ne $password) { return -1; } } - unless (-e "$userspath/$self->{login}.conf") { + unless (-f "$userspath/$self->{login}.conf") { $self->create_config("$userspath/$self->{login}.conf"); } @@ -114,7 +114,7 @@ sub login { $myconfig{dbpasswd} = unpack 'u', $myconfig{dbpasswd}; # check if database is down - my $dbh = DBI->connect($myconfig{dbconnect}, $myconfig{dbuser}, $myconfig{dbpasswd}) or $self->error(DBI::errstr); + my $dbh = DBI->connect($myconfig{dbconnect}, $myconfig{dbuser}, $myconfig{dbpasswd}) or $self->error($DBI::errstr); # we got a connection, check the version my $query = qq|SELECT version FROM defaults|; @@ -126,28 +126,46 @@ sub login { # add login to employee table if it does not exist # no error check for employee table, ignore if it does not exist - $query = qq|SELECT id FROM employee WHERE login = '$self->{login}'|; + my $login = $self->{login}; + $login =~ s/@.*//; + $query = qq|SELECT id FROM employee WHERE login = '$login'|; $sth = $dbh->prepare($query); $sth->execute; - my ($login) = $sth->fetchrow_array; + my ($id) = $sth->fetchrow_array; $sth->finish; - if (!$login) { - $query = qq|INSERT INTO employee (login, name, workphone) - VALUES ('$self->{login}', '$myconfig{name}', '$myconfig{tel}')|; + if (! $id) { + my ($employeenumber) = $form->update_defaults(\%myconfig, "employeenumber", $dbh); + + $query = qq|INSERT INTO employee (login, employeenumber, name, workphone, + role) + VALUES ('$login', '$employeenumber', '$myconfig{name}', + '$myconfig{tel}', '$myconfig{role}')|; $dbh->do($query); } $dbh->disconnect; + $rc = 0; + + if ($form->{dbversion} ne $dbversion) { - return -2; + $rc = -4; + $dbupdate = (calc_version($dbversion) < calc_version($form->{dbversion})); } - } else { - return -3; + if ($dbupdate) { + $rc = -5; + + # if DB2 bale out + if ($myconfig{dbdriver} eq 'DB2') { + $rc = -2; + } + } } + $rc; + } @@ -173,11 +191,12 @@ sub dbconnect_vars { 'dd.mm.yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD.MM.YY\'', } ); - + + $form->{dboptions} = $dboptions{$form->{dbdriver}}{$form->{dateformat}}; - if ($form->{dbdriver} eq 'Pg') { - $form->{dbconnect} = "dbi:Pg:dbname=$db"; + if ($form->{dbdriver} =~ /Pg/) { + $form->{dbconnect} = "dbi:$form->{dbdriver}:dbname=$db"; } if ($form->{dbdriver} eq 'Oracle') { @@ -198,7 +217,8 @@ sub dbdrivers { my @drivers = DBI->available_drivers(); - return (grep { /(Pg|Oracle)$/ } @drivers); +# return (grep { /(Pg|Oracle|DB2)/ } @drivers); + return (grep { /Pg$/ } @drivers); } @@ -265,6 +285,28 @@ sub dbsources { } } + +# JJR + if ($form->{dbdriver} eq 'DB2') { + if ($form->{only_acc_db}) { + $query = qq|SELECT tabschema FROM syscat.tables WHERE tabname = 'DEFAULTS'|; + } else { + $query = qq|SELECT DISTINCT schemaname FROM syscat.schemata WHERE definer != 'SYSIBM' AND schemaname != 'NULLID'|; + } + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my ($db) = $sth->fetchrow_array) { + push @dbsources, $db; + } + } +# End JJR + +# the above is not used but leave it in for future reference +# DS, Oct. 28, 2003 + + $sth->finish; $dbh->disconnect; @@ -306,21 +348,36 @@ sub dbcreate { $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror; # create the tables - my $filename = qq|sql/$form->{dbdriver}-tables.sql|; - $self->processquery($form, $dbh, $filename); + my $dbdriver = ($form->{dbdriver} =~ /Pg/) ? 'Pg' : $form->{dbdriver}; + + my $filename = qq|sql/${dbdriver}-tables.sql|; + $self->process_query($form, $dbh, $filename); + + # create functions + $filename = qq|sql/${dbdriver}-functions.sql|; + $self->process_query($form, $dbh, $filename); # load gifi ($filename) = split /_/, $form->{chart}; $filename =~ s/_//; - $self->processquery($form, $dbh, "sql/${filename}-gifi.sql"); - + $self->process_query($form, $dbh, "sql/${filename}-gifi.sql"); + # load chart of accounts $filename = qq|sql/$form->{chart}-chart.sql|; - $self->processquery($form, $dbh, $filename); + $self->process_query($form, $dbh, $filename); # create indices - $filename = qq|sql/$form->{dbdriver}-indices.sql|; - $self->processquery($form, $dbh, $filename); + $filename = qq|sql/${dbdriver}-indices.sql|; + $self->process_query($form, $dbh, $filename); + + # create custom tables and functions + my $item; + foreach $item (qw(tables functions)) { + $filename = "sql/${dbdriver}-custom_${item}.sql"; + if (-f "$filename") { + $self->process_query($form, $dbh, $filename); + } + } $dbh->disconnect; @@ -328,26 +385,59 @@ sub dbcreate { -sub processquery { +sub process_query { my ($self, $form, $dbh, $filename) = @_; return unless (-f $filename); open(FH, "$filename") or $form->error("$filename : $!\n"); my $query = ""; + my $loop = 0; + my $sth; + while () { - $query .= $_; + if ($loop && /^--\s*end\s*(procedure|function|trigger)/i) { + $loop = 0; + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + $sth->finish; + + $query = ""; + next; + } + + if ($loop || /^create *(or replace)? *(procedure|function|trigger)/i) { + $loop = 1; + next if /^(--.*|\s+)$/; + + $query .= $_; + next; + } + + # don't add comments or empty lines + next if /^(--.*|\s+)$/; + + # anything else, add to query + $query .= $_; + if (/;\s*$/) { # strip ;... Oracle doesn't like it $query =~ s/;\s*$//; - $dbh->do($query) || $form->dberror($query); + $query =~ s/\\'/''/g; + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + $sth->finish; + $query = ""; } + } close FH; - + } @@ -377,7 +467,7 @@ sub dbsources_unused { my @dbexcl = (); my @dbsources = (); - $form->error('File locked!') if (-f "${memfile}.LCK"); + $form->error("$memfile locked!") if (-f "${memfile}.LCK"); # open members file open(FH, "$memfile") or $form->error("$memfile : $!"); @@ -418,7 +508,7 @@ sub dbneedsupdate { my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror; - if ($form->{dbdriver} eq 'Pg') { + if ($form->{dbdriver} =~ /Pg/) { $query = qq|SELECT d.datname FROM pg_database d, pg_user u WHERE d.datdba = u.usesysid @@ -483,6 +573,37 @@ sub dbneedsupdate { } $sth->finish; } + + +# JJR + if ($form->{dbdriver} eq 'DB2') { + $query = qq|SELECT tabschema FROM syscat.tables WHERE tabname = 'DEFAULTS'|; + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my ($db) = $sth->fetchrow_array) { + + &dbconnect_vars($form, $db); + + my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror; + + $query = qq|SELECT version FROM defaults|; + my $sth = $dbh->prepare($query); + $sth->execute; + + if (my ($version) = $sth->fetchrow_array) { + $dbsources{$db} = $version; + } + $sth->finish; + $dbh->disconnect; + } + $sth->finish; + } +# End JJR + +# code for DB2 is not used, keep for future reference +# DS, Oct. 28, 2003 $dbh->disconnect; @@ -498,15 +619,16 @@ sub dbupdate { my @upgradescripts = (); my $query; + my $rc = -2; if ($form->{dbupdate}) { # read update scripts into memory - opendir SQLDIR, "sql/." or $form-error($!); - @upgradescripts = sort grep /$form->{dbdriver}-upgrade-.*?\.sql/, readdir SQLDIR; + opendir SQLDIR, "sql/." or $form->error($!); + @upgradescripts = sort script_version grep /$form->{dbdriver}-upgrade-.*?\.sql$/, readdir SQLDIR; closedir SQLDIR; } - + foreach my $db (split / /, $form->{dbupdate}) { next unless $form->{$db}; @@ -514,7 +636,7 @@ sub dbupdate { # strip db from dataset $db =~ s/^db//; &dbconnect_vars($form, $db); - + my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror; # check version @@ -528,37 +650,87 @@ sub dbupdate { next unless $version; + $version = calc_version($version); + my $dbversion = calc_version($form->{dbversion}); + foreach my $upgradescript (@upgradescripts) { my $a = $upgradescript; $a =~ s/(^$form->{dbdriver}-upgrade-|\.sql$)//g; my ($mindb, $maxdb) = split /-/, $a; + $mindb = calc_version($mindb); + $maxdb = calc_version($maxdb); - next if ($version ge $maxdb); + next if ($version >= $maxdb); - # if there is no upgrade script exit - last if ($version lt $mindb); + # exit if there is no upgrade script or version == mindb + last if ($version < $mindb || $version >= $dbversion); # apply upgrade - $self->processquery($form, $dbh, "sql/$upgradescript"); + $self->process_query($form, $dbh, "sql/$upgradescript"); $version = $maxdb; } + $rc = 0; $dbh->disconnect; } + + $rc; + } +sub calc_version { + + my @v = split /\./, $_[0]; + my $version = 0; + my $i; + + for ($i = 0; $i <= $#v; $i++) { + $version *= 1000; + $version += $v[$i]; + } + + return $version; + +} + + +sub script_version { + my ($my_a, $my_b) = ($a, $b); + + my ($a_from, $a_to, $b_from, $b_to); + my ($res_a, $res_b, $i); + + $my_a =~ s/.*-upgrade-//; + $my_a =~ s/.sql$//; + $my_b =~ s/.*-upgrade-//; + $my_b =~ s/.sql$//; + ($a_from, $a_to) = split(/-/, $my_a); + ($b_from, $b_to) = split(/-/, $my_b); + + $res_a = calc_version($a_from); + $res_b = calc_version($b_from); + + if ($res_a == $res_b) { + $res_a = calc_version($a_to); + $res_b = calc_version($b_to); + } + + return $res_a <=> $res_b; + +} + sub create_config { my ($self, $filename) = @_; @config = &config_vars; - + open(CONF, ">$filename") or $self->error("$filename : $!"); # create the config file @@ -568,6 +740,7 @@ sub create_config { |; foreach $key (sort @config) { + $self->{$key} =~ s/\\/\\\\/g; $self->{$key} =~ s/'/\\'/g; print CONF qq| $key => '$self->{$key}',\n|; } @@ -583,17 +756,17 @@ sub create_config { sub save_member { my ($self, $memberfile, $userspath) = @_; - my $newmember = 1; - # format dbconnect and dboptions string - map { $self->{$_} = lc $self->{$_} } qw(dbname host); &dbconnect_vars($self, $self->{dbname}); - $self->error('File locked!') if (-f "${memberfile}.LCK"); + $self->error("$memberfile locked!") if (-f "${memberfile}.LCK"); open(FH, ">${memberfile}.LCK") or $self->error("${memberfile}.LCK : $!"); close(FH); - open(CONF, "+<$memberfile") or $self->error("$memberfile : $!"); + if (! open(CONF, "+<$memberfile")) { + unlink "${memberfile}.LCK"; + $self->error("$memberfile : $!"); + } @config = ; @@ -601,10 +774,7 @@ sub save_member { truncate(CONF, 0); while ($line = shift @config) { - if ($line =~ /^\[$self->{login}\]/) { - $newmember = 0; - last; - } + last if ($line =~ /^\[$self->{login}\]/); print CONF $line; } @@ -622,7 +792,7 @@ sub save_member { print CONF qq|[$self->{login}]\n|; - if ((($self->{dbpasswd} ne $self->{old_dbpasswd}) || $newmember) && $self->{root}) { + if ($self->{root}) { $self->{dbpasswd} = pack 'u', $self->{dbpasswd}; chop $self->{dbpasswd}; } @@ -636,10 +806,9 @@ sub save_member { } else { @config = &config_vars; } - + # replace \r\n with \n - $self->{address} =~ s/\r\n/\\n/g if $self->{address}; - $self->{signature} =~ s/\r\n/\\n/g if $self->{signature}; + map { $self->{$_} =~ s/\r\n/\\n/g } qw(address signature); foreach $key (sort @config) { print CONF qq|$key=$self->{$key}\n|; @@ -650,18 +819,84 @@ sub save_member { unlink "${memberfile}.LCK"; # create conf file - $self->create_config("$userspath/$self->{login}.conf") unless $self->{'root login'}; - + if (! $self->{'root login'}) { + $self->create_config("$userspath/$self->{login}.conf"); + + $self->{dbpasswd} =~ s/\\'/'/g; + $self->{dbpasswd} =~ s/\\\\/\\/g; + $self->{dbpasswd} = unpack 'u', $self->{dbpasswd}; + + # check if login is in database + my $dbh = DBI->connect($self->{dbconnect}, $self->{dbuser}, $self->{dbpasswd}, {AutoCommit => 0}) or $self->error($DBI::errstr); + + # add login to employee table if it does not exist + # no error check for employee table, ignore if it does not exist + my $login = $self->{login}; + $login =~ s/@.*//; + my $query = qq|SELECT id FROM employee WHERE login = '$login'|; + my $sth = $dbh->prepare($query); + $sth->execute; + + my ($id) = $sth->fetchrow_array; + $sth->finish; + + if ($id) { + $query = qq|UPDATE employee SET + role = '$self->{role}', + email = '$self->{email}', + name = '$self->{name}' + WHERE login = '$login'|; + + } else { + my ($employeenumber) = Form::update_defaults("", \%$self, "employeenumber", $dbh); + $query = qq|INSERT INTO employee (login, employeenumber, name, workphone, + role, email) + VALUES ('$login', '$employeenumber', '$self->{name}', + '$self->{tel}', '$self->{role}', '$self->{email}')|; + } + + $dbh->do($query); + $dbh->commit; + $dbh->disconnect; + + } + } +sub delete_login { + my ($self, $form) = @_; + + my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, {AutoCommit} => 0) or $form->dberror; + + my $login = $form->{login}; + $login =~ s/@.*//; + my $query = qq|SELECT id FROM employee + WHERE login = '$login'|; + my $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + my ($id) = $sth->fetchrow_array; + $sth->finish; + + my $query = qq|UPDATE employee + login = NULL + WHERE login = '$login'|; + $dbh->do($query); + + $dbh->commit; + $dbh->disconnect; + +} + + sub config_vars { - my @conf = qw(acs address admin businessnumber charset company countrycode + my @conf = qw(acs address businessnumber charset company countrycode currency dateformat dbconnect dbdriver dbhost dbport dboptions dbname dbuser dbpasswd email fax name numberformat password - printer sid shippingpoint signature stylesheet tel templates - vclimit); + printer role sid signature stylesheet tel templates vclimit + menuwidth timeout); @conf; @@ -674,8 +909,6 @@ sub error { if ($ENV{HTTP_USER_AGENT}) { print qq|Content-Type: text/html - -

Error!

diff --git a/sql-ledger/VERSION b/sql-ledger/VERSION index 815e68dd2..79a614418 100644 --- a/sql-ledger/VERSION +++ b/sql-ledger/VERSION @@ -1 +1 @@ -2.0.8 +2.4.4 diff --git a/sql-ledger/am.pl b/sql-ledger/am.pl index f69a15a65..535d835a3 100755 --- a/sql-ledger/am.pl +++ b/sql-ledger/am.pl @@ -30,12 +30,13 @@ # ####################################################################### -# setup defaults, these are overidden by sql-ledger.conf -# DO NOT CHANGE +# setup defaults, DO NOT CHANGE $userspath = "users"; +$spool = "spool"; $templates = "templates"; $memberfile = "users/members"; $sendmail = "| /usr/sbin/sendmail -t"; +%printer = ( Printer => 'lpr' ); ########## end ########################################### @@ -48,7 +49,6 @@ eval { require "sql-ledger.conf"; }; $form = new Form; - # name of this script $0 =~ tr/\\/\//; $pos = rindex $0, '/'; @@ -60,7 +60,8 @@ $form->{script} = $script; $script =~ s/\.pl//; # pull in DBI -use DBI; +use DBI qw(:sql_types); + # check for user config file, could be missing or ??? eval { require("$userspath/$form->{login}.conf"); }; @@ -74,53 +75,84 @@ if ($@) { } -$myconfig{dbpasswd} = unpack 'u', $myconfig{dbpasswd}; -map { $form->{$_} = $myconfig{$_} } qw(stylesheet charset) unless (($form->{action} eq "save") && ($form->{type} eq 'preferences')); +# send warnings and errors to browser +$SIG{__WARN__} = sub { $form->info($_[0]) }; +$SIG{__DIE__} = sub { $form->error($_[0]) }; +$myconfig{dbpasswd} = unpack 'u', $myconfig{dbpasswd}; +map { $form->{$_} = $myconfig{$_} } qw(stylesheet charset timeout) unless ($form->{type} eq 'preferences'); # locale messages $locale = new Locale "$myconfig{countrycode}", "$script"; - -# check password -$form->error($locale->text('Incorrect Password!')) if ($form->{password} ne $myconfig{password}); - - $form->{path} =~ s/\.\.\///g; if ($form->{path} !~ /^bin\//) { $form->error($locale->text('Invalid path!')."\n"); } # did sysadmin lock us out -if (-e "$userspath/nologin") { +if (-f "$userspath/nologin") { $form->error($locale->text('System currently down for maintenance!')); } - # pull in the main code require "$form->{path}/$form->{script}"; # customized scripts if (-f "$form->{path}/custom_$form->{script}") { eval { require "$form->{path}/custom_$form->{script}"; }; - $form->error($@) if ($@); } # customized scripts for login if (-f "$form->{path}/$form->{login}_$form->{script}") { eval { require "$form->{path}/$form->{login}_$form->{script}"; }; - $form->error($@) if ($@); } + if ($form->{action}) { # window title bar, user info $form->{titlebar} = "SQL-Ledger ".$locale->text('Version'). " $form->{version} - $myconfig{name} - $myconfig{dbname}"; - &{ $locale->findsub($form->{action}) }; + &check_password; + + if (substr($form->{action}, 0, 1) =~ /( |\.)/) { + &{ $form->{nextsub} }; + } else { + &{ $locale->findsub($form->{action}) }; + } } else { $form->error($locale->text('action= not defined!')); } - +1; # end + +sub check_password { + + if ($myconfig{password}) { + + require "$form->{path}/pw.pl"; + + if ($form->{password}) { + if ((crypt $form->{password}, substr($form->{login}, 0, 2)) ne $myconfig{password}) { + &getpassword; + exit; + } + } else { + if ($ENV{HTTP_USER_AGENT}) { + $ENV{HTTP_COOKIE} =~ s/;\s*/;/g; + %cookie = split /[=;]/, $ENV{HTTP_COOKIE}; + + if ($form->{action} ne 'display') { + if ((! $cookie{"SQL-Ledger-$form->{login}"}) || $cookie{"SQL-Ledger-$form->{login}"} ne $form->{sessionid}) { + &getpassword(1); + exit; + } + } + } + } + } +} + + diff --git a/sql-ledger/bin/js/menu.pl b/sql-ledger/bin/js/menu.pl new file mode 100644 index 000000000..718d22dfd --- /dev/null +++ b/sql-ledger/bin/js/menu.pl @@ -0,0 +1,188 @@ +###################################################################### +# SQL-Ledger Accounting +# Copyright (c) 2004 +# +# Author: Dieter Simader +# Email: dsimader@sql-ledger.org +# Web: http://www.sql-ledger.org +# +# +# 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. +####################################################################### + +$menufile = "menu.ini"; +use SL::Menu; + + +1; +# end of main + + +sub display { + + $menuwidth = ($myconfig{menuwidth}) ? $myconfig{menuwidth} : ($ENV{HTTP_USER_AGENT} =~ /links/i) ? "240" : "155"; + + $form->header(1); + + print qq| + + + + + + + + + + +|; + +} + + +sub acc_menu { + + my $menu = new Menu "$menufile"; + $menu = new Menu "custom_$menufile" if (-f "custom_$menufile"); + $menu = new Menu "$form->{login}_$menufile" if (-f "$form->{login}_$menufile"); + + $form->{title} = $locale->text('Accounting Menu'); + + $form->header; + + print qq| + + + +|; + + §ion_menu($menu); + + print qq| + + +|; + +} + + +sub section_menu { + my ($menu, $level) = @_; + + print qq| +
+ |; +} + + +sub menubar { + + 1; + +} + + diff --git a/sql-ledger/bin/lynx/menu.pl b/sql-ledger/bin/lynx/menu.pl index 559971685..16abe975e 100644 --- a/sql-ledger/bin/lynx/menu.pl +++ b/sql-ledger/bin/lynx/menu.pl @@ -1,12 +1,12 @@ ###################################################################### # SQL-Ledger Accounting -# Copyright (c) 2001 +# Copyright (c) 2000 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org # Web: http://www.sql-ledger.org # -# Contributors: Christopher Browne +# Contributors: Christopher Browne # # 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 @@ -24,10 +24,6 @@ # # menu for text based browsers (lynx) # -# CHANGE LOG: -# DS. 2000-07-04 Created -# DS. 2001-08-07 access control -# CBB 2002-02-09 Refactored HTML out to subroutines ####################################################################### $menufile = "menu.ini"; @@ -42,12 +38,14 @@ use SL::Menu; sub display { $menu = new Menu "$menufile"; + $menu = new Menu "custom_$menufile" if (-f "custom_$menufile"); + $menu = new Menu "$form->{login}_$menufile" if (-f "$form->{login}_$menufile"); @menuorder = $menu->access_control(\%myconfig); $form->{title} = "SQL-Ledger $form->{version}"; - $form->header; + $form->header(1); $offset = int (21 - $#menuorder)/2; @@ -66,17 +64,15 @@ sub display { '; - # display the company logo -# $argv = "login=$form->{login}&password=$form->{password}&path=$form->{path}&action=company_logo&noheader=1"; -# exec "./login.pl", $argv; - } sub section_menu { $menu = new Menu "$menufile", $form->{level}; - + $menu = new Menu "custom_$menufile", $form->{level} if (-f "custom_$menufile"); + $menu = new Menu "$form->{login}_$menufile", $form->{level} if (-f "$form->{login}_$menufile"); + # build tiered menus @menuorder = $menu->access_control(\%myconfig, $form->{level}); @@ -126,3 +122,30 @@ sub acc_menu { } + +sub menubar { + $menu = new Menu "$menufile", ""; + + # build menubar + @menuorder = $menu->access_control(\%myconfig, ""); + + @neworder = (); + map { push @neworder, $_ unless ($_ =~ /--/) } @menuorder; + @menuorder = @neworder; + + print "

"; + $form->{script} = "menu.pl"; + + print "| "; + foreach $item (@menuorder) { + $label = $item; + + # remove target + $menu->{$item}{target} = ""; + + print $menu->menuitem(\%myconfig, \%$form, $item, "").$locale->text($label)." | "; + } + +} + + diff --git a/sql-ledger/bin/mozilla/admin.pl b/sql-ledger/bin/mozilla/admin.pl index 39247b541..8a4daba78 100644 --- a/sql-ledger/bin/mozilla/admin.pl +++ b/sql-ledger/bin/mozilla/admin.pl @@ -39,6 +39,11 @@ $locale = new Locale $language, "admin"; eval { require DBI; }; $form->error($locale->text('DBI not installed!')) if ($@); +$form->{stylesheet} = "sql-ledger.css"; +$form->{favicon} = "favicon.ico"; +$form->{timeout} = 600; + +require "$form->{path}/pw.pl"; # customization if (-f "$form->{path}/custom_$form->{script}") { @@ -47,22 +52,11 @@ if (-f "$form->{path}/custom_$form->{script}") { } -if (-f "css/sql-ledger.css") { - $form->{stylesheet} = "sql-ledger.css"; -} - - if ($form->{action}) { $subroutine = $locale->findsub($form->{action}); - - if ($subroutine eq 'login') { - if ($form->{rpw}) { - $form->{rpw} = crypt $form->{rpw}, "ro"; - } - } - - &check_password; + + &check_password unless $form->{action} eq 'logout'; &$subroutine; @@ -80,7 +74,7 @@ if ($form->{action}) { password= |; - close(FH); + close FH; } &adminlogin; @@ -94,32 +88,39 @@ password= sub adminlogin { $form->{title} = qq|SQL-Ledger $form->{version} |.$locale->text('Administration'); - - $form->header; - print qq| - + $form->{login} = "root login"; + $form->header(1); + + print qq| + +

|.$locale->text('Version').qq| $form->{version}

|.$locale->text('Administration').qq|

-
+ - + -{path}> +{sessionid}>
|.$locale->text('Password').qq|
-
SQL-Ledger |.$locale->text('website').qq| @@ -133,8 +134,6 @@ sub adminlogin { } - - sub login { &list_users; @@ -142,6 +141,13 @@ sub login { } +sub logout { + + $form->{callback} = "$form->{script}?path=$form->{path}&endsession=1"; + $form->redirect($locale->text('You are logged out')); + +} + sub add_user { @@ -154,7 +160,9 @@ sub add_user { if (-f "css/sql-ledger.css") { $myconfig->{stylesheet} = "sql-ledger.css"; } - $myconfig->{vclimit} = 200; + $myconfig->{vclimit} = 1000; + $myconfig->{menuwidth} = 155; + $myconfig->{timeout} = 3600; &form_header; &form_footer; @@ -183,10 +191,10 @@ sub form_footer { print qq| - - + + {path}> -{rpw}> +{sessionid}> $delete @@ -202,10 +210,17 @@ $delete sub list_users { - $form->error("$memberfile : ".$locale->text('locked!')) if (-f "${memberfile}.LCK"); - open(FH, "$memberfile") or $form->error("$memberfile : $!"); - + + $nologin = qq| +|; + + if (-e "$userspath/nologin") { + $nologin = qq| +|; + } + + while () { chop; @@ -223,6 +238,7 @@ sub list_users { close(FH); # type=submit $locale->text('Pg Database Administration') +# type=submit $locale->text('PgPP Database Administration') # type=submit $locale->text('Oracle Database Administration') foreach $item (User->dbdrivers) { @@ -242,6 +258,7 @@ sub list_users { $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Administration'); + $form->{login} = "root login"; $form->header; print qq| @@ -267,7 +284,7 @@ sub list_users { |; foreach $key (sort keys %member) { - $href = "$script?action=edit&login=$key&path=$form->{path}&root=$form->{root}&rpw=$form->{rpw}"; + $href = "$script?action=edit&login=$key&path=$form->{path}&sessionid=$form->{sessionid}"; $href =~ s/ /%20/g; $member{$key}{templates} =~ s/^$templates\///; @@ -303,13 +320,15 @@ print qq| {path}> -{rpw}> - +{sessionid}>
$dbdrivers +$nologin + + @@ -317,35 +336,6 @@ $dbdrivers
|.$locale->text('To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.').qq| -

- -

- - - - - - - - -
SQL-Ledger |.$locale->text('Accounting')." ".$locale->text('Login').qq|
- - - - - - - - - - - -{path}> -
|.$locale->text('Name').qq| 
|.$locale->text('Password').qq|
-
- -
- |; @@ -354,7 +344,6 @@ $dbdrivers - sub form_header { # if there is a login, get user @@ -376,17 +365,18 @@ sub form_header { $dateformat .= ($item eq $myconfig->{dateformat}) ? "
|; } @@ -712,6 +744,8 @@ sub save { # no spaces allowed in login name ($form->{login}) = split / /, $form->{login}; + + $form->isblank("login", $locale->text('Login name missing!')); # check for duplicates if (!$form->{edit}) { @@ -722,11 +756,6 @@ sub save { } } - # does stylesheet exist - if ($form->{userstylesheet}) { - $form->error($locale->text('Stylesheet').": css/$form->{userstylesheet} ".$locale->text('does not exist')) unless (-f "css/$form->{userstylesheet}"); - } - # no spaces allowed in directories ($form->{newtemplates}) = split / /, $form->{newtemplates}; @@ -736,7 +765,6 @@ sub save { $form->{templates} = ($form->{usetemplates}) ? $form->{usetemplates} : $form->{login}; } - # is there a basedir if (! -d "$templates") { $form->error($locale->text('Directory').": $templates ".$locale->text('does not exist')); @@ -760,38 +788,33 @@ sub save { } delete $form->{$item}; } - + # check which database was filled in + + $form->{dbhost} = $form->{"$form->{dbdriver}_dbhost"}; + $form->{dbport} = $form->{"$form->{dbdriver}_dbport"}; + $form->{dbpasswd} = $form->{"$form->{dbdriver}_dbpasswd"}; + $form->{dbuser} = $form->{"$form->{dbdriver}_dbuser"}; + $form->{dbname} = $form->{"$form->{dbdriver}_dbname"}; + if ($form->{dbdriver} eq 'Oracle') { $form->{sid} = $form->{Oracle_sid}, ; - $form->{dbhost} = $form->{Oracle_dbhost}, ; - $form->{dbport} = $form->{Oracle_dbport}; - $form->{dbpasswd} = $form->{Oracle_dbpasswd}; - $form->{dbuser} = $form->{Oracle_dbuser}; - $form->{dbname} = $form->{Oracle_dbuser}; $form->isblank("dbhost", $locale->text('Hostname missing!')); $form->isblank("dbport", $locale->text('Port missing!')); $form->isblank("dbuser", $locale->text('Dataset missing!')); } - if ($form->{dbdriver} eq 'Pg') { - $form->{dbhost} = $form->{Pg_dbhost}; - $form->{dbport} = $form->{Pg_dbport}; - $form->{dbpasswd} = $form->{Pg_dbpasswd}; - $form->{dbuser} = $form->{Pg_dbuser}; - $form->{dbname} = $form->{Pg_dbname}; - + if ($form->{dbdriver} =~ /Pg/) { $form->isblank("dbname", $locale->text('Dataset missing!')); $form->isblank("dbuser", $locale->text('Database User missing!')); } - # set admin - $form->{admin} = "" unless $form->{admin}; - foreach $item (keys %{$form}) { $myconfig->{$item} = $form->{$item}; } + $myconfig->{password} = $form->{new_password} if $form->{new_password} ne $form->{old_password}; + delete $myconfig->{stylesheet}; if ($form->{userstylesheet}) { $myconfig->{stylesheet} = $form->{userstylesheet}; @@ -808,8 +831,8 @@ sub save { umask(007); # copy templates to the directory - opendir TEMPLATEDIR, "$templates/." or $form-error("$templates : $!"); - @templates = grep /$form->{mastertemplates}.*?\.(html|tex)$/, readdir TEMPLATEDIR; + opendir TEMPLATEDIR, "$templates/." or $form->error("$templates : $!"); + @templates = grep /$form->{mastertemplates}.*?\.(html|tex|txt)$/, readdir TEMPLATEDIR; closedir TEMPLATEDIR; foreach $file (@templates) { @@ -838,11 +861,14 @@ sub delete { $form->{templates} = ($form->{templates}) ? "$templates/$form->{templates}" : "$templates/$form->{login}"; - $form->error("$memberfile : ".$locale->text('locked!')) if (-f ${memberfile}.LCK); + $form->error("$memberfile ".$locale->text('locked!')) if (-f ${memberfile}.LCK); open(FH, ">${memberfile}.LCK") or $form->error("${memberfile}.LCK : $!"); close(FH); - open(CONF, "+<$memberfile") or $form->error("$memberfile : $!"); + if (! open(CONF, "+<$memberfile")) { + unlink "${memberfile}.LCK"; + $form->error("$memberfile : $!"); + } @config = ; @@ -851,6 +877,8 @@ sub delete { while ($line = shift @config) { + chop $line; + if ($line =~ /^\[/) { last if ($line =~ /\[$form->{login}\]/); $login = &login_name($line); @@ -860,25 +888,31 @@ sub delete { $user{$login} = &get_value($line); } - print CONF $line; + print CONF "$line\n"; } # remove everything up to next login or EOF # and save template variable while ($line = shift @config) { - if ($line =~ /^templates=/) { - $templatedir = &get_value($line); - } + + chop $line; + + ($key, $value) = split /=/, $line, 2; + $myconfig{$key} = $value; + last if ($line =~ /^\[/); } # this one is either the next login or EOF - print CONF $line; + print CONF "$line\n"; $login = &login_name($line); while ($line = shift @config) { + + chop $line; + if ($line =~ /^\[/) { $login = &login_name($line); } @@ -887,7 +921,7 @@ sub delete { $user{$login} = &get_value($line); } - print CONF $line; + print CONF "$line\n"; } close(CONF); @@ -895,9 +929,11 @@ sub delete { # scan %user for $templatedir foreach $login (keys %user) { - last if ($found = ($templatedir eq $user{$login})); + last if ($found = ($myconfig{templates} eq $user{$login})); } + map { $form->{$_} = $myconfig{$_} } keys %myconfig; + # if found keep directory otherwise delete if (!$found) { # delete it if there is a template directory @@ -905,13 +941,16 @@ sub delete { if (-d "$dir") { unlink <$dir/*.html>; unlink <$dir/*.tex>; + unlink <$dir/*.txt>; rmdir "$dir"; } } # delete config file for user unlink "$userspath/$form->{login}.conf"; - + + User::delete_login("", \%$form); + $form->redirect($locale->text('User deleted!')); } @@ -930,10 +969,10 @@ sub login_name { sub get_value { my $line = shift; - my ($null, $value) = split(/=/, $line, 2); + my ($null, $value) = split /=/, $line, 2; # remove comments - $value =~ s/\s#.*//g; + $value =~ s/^\s*#.*//g; # remove any trailing whitespace $value =~ s/^\s*(.*?)\s*$/$1/; @@ -946,22 +985,42 @@ sub get_value { sub change_admin_password { $form->{title} = qq|SQL-Ledger |.$locale->text('Accounting')." ".$locale->text('Administration')." / ".$locale->text('Change Admin Password'); - + + $form->{login} = "root login"; $form->header; print qq| - -

|.$locale->text('Change Admin Password').qq|

-
{script}> -|.$locale->text('Password').qq| + + + + + + + + + - +
|.$locale->text('Change Password').qq|
+ + + + + + + + + +
|.$locale->text('Password').qq|
|.$locale->text('Confirm').qq|
+
+ +
+
{path}> -{rpw}> +{sessionid}>

@@ -977,12 +1036,14 @@ sub change_admin_password { sub change_password { - $root->{password} = $form->{password}; + $form->error($locale->text('Passwords do not match!')) if $form->{new_password} ne $form->{confirm_password}; + + $root->{password} = $form->{new_password}; $root->{'root login'} = 1; $root->save_member($memberfile); - $form->{callback} = "$form->{script}?action=list_users&path=$form->{path}&root=$form->{root}&rpw=$root->{password}"; + $form->{callback} = "$form->{script}?action=list_users&path=$form->{path}&sessionid=$form->{sessionid}"; $form->redirect($locale->text('Password changed!')); @@ -991,11 +1052,26 @@ sub change_password { sub check_password { - $root = new User "$memberfile", $form->{root}; + $root = new User "$memberfile", "root login"; if ($root->{password}) { - if ($root->{password} ne $form->{rpw}) { - $form->error($locale->text('Incorrect Password!')); + + if ($form->{password}) { + $form->{callback} .= "&password=$form->{password}" if $form->{callback}; + $form->{sessionid} = time; + if ($root->{password} ne crypt $form->{password}, 'ro') { + &getpassword; + exit; + } + } else { + if ($ENV{HTTP_USER_AGENT}) { + $ENV{HTTP_COOKIE} =~ s/;\s*/;/g; + %cookie = split /[=;]/, $ENV{HTTP_COOKIE}; + if ((! $cookie{"SQL-Ledger-root login"}) || $cookie{"SQL-Ledger-root login"} ne $form->{sessionid}) { + &getpassword(1); + exit; + } + } } } @@ -1010,6 +1086,14 @@ sub pg_database_administration { } +sub pgpp_database_administration { + + $form->{dbdriver} = 'PgPP'; + &dbselect_source; + +} + + sub oracle_database_administration { $form->{dbdriver} = 'Oracle'; @@ -1035,6 +1119,8 @@ sub dbdriver_defaults { } ); + $driverdefaults{PgPP} = $driverdefaults{Pg}; + map { $form->{$_} = $driverdefaults{$form->{dbdriver}}{$_} } keys %{ $driverdefaults{Pg} }; } @@ -1045,73 +1131,61 @@ sub dbselect_source { &dbdriver_defaults; $msg{Pg} = $locale->text('Leave host and port field empty unless you want to make a remote connection.'); + $msg{PgPP} = $msg{Pg}; $msg{Oracle} = $locale->text('You must enter a host and port for local and remote connections!'); $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." / ".$locale->text('Database Administration'); - + $form->{login} = "root login"; $form->header; print qq| -

$form->{title}

{script}> - + +
- - - - - - - -{dbdriver}> - - -
|.$locale->text('Database').qq|
- - - - - - - - - - - - - - - - - - - - + - - - - -
|.$locale->text('Host').qq|{dbhost}>|.$locale->text('Port').qq|{dbport}>
|.$locale->text('User').qq|{dbuser}>|.$locale->text('Password').qq|
+ + + + + {dbdriver}> + + + +
|.$locale->text('Database').qq|
+ + + + + + + + + + + + + + + + + + + +
|.$locale->text('Host').qq|{dbhost}>|.$locale->text('Port').qq|{dbport}>
|.$locale->text('User').qq|{dbuser}>|.$locale->text('Password').qq|
$form->{connectstring}{dbdefault}>
+
-
$form->{connectstring}{dbdefault}>
- -
- - - + {path}> -{rpw}> +{sessionid}> -

@@ -1120,7 +1194,8 @@ sub dbselect_source { -

|.$locale->text('This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!') @@ -1149,6 +1224,7 @@ sub update_dataset { $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Database Administration')." / ".$locale->text('Update Dataset'); + $form->{login} = "root login"; $form->header; print qq| @@ -1161,8 +1237,8 @@ sub update_dataset { foreach $key (sort keys %needsupdate) { - if ($needsupdate{$key} lt $form->{dbversion}) { - $upd .= qq|
$key\n|; + if ($needsupdate{$key} ne $form->{dbversion}) { + $upd .= qq| $key\n|; $form->{dbupdate} .= "db$key "; } } @@ -1173,7 +1249,7 @@ sub update_dataset { if ($form->{dbupdate}) { print qq| - +
{script}> {dbdriver}> @@ -1191,19 +1267,23 @@ sub update_dataset { $upd - - + + + @@ -1237,41 +1317,53 @@ sub dbupdate { sub create_dataset { - foreach $item (sort User->dbsources(\%$form)) { - $dbsources .= "[$item] "; - } + @dbsources = sort User->dbsources(\%$form); - opendir SQLDIR, "sql/." or $form-error($!); + opendir SQLDIR, "sql/." or $form->error($!); foreach $item (sort grep /-chart\.sql/, readdir SQLDIR) { next if ($item eq 'Default-chart.sql'); $item =~ s/-chart\.sql//; - push @charts, qq|  $item|; + push @charts, qq|$item|; } closedir SQLDIR; # add Default at beginning - @charts = (qq| Default|, @charts); + unshift @charts, qq|Default|; - $selectencoding = qq|
+
- + - {path}> -{rpw}> +{sessionid}> +
+ +
+
@@ -1291,8 +1383,13 @@ sub create_dataset { - + @@ -1301,7 +1398,7 @@ sub create_dataset { - + @@ -1311,14 +1408,36 @@ sub create_dataset { - - + + + + + +
 
|.$locale->text('Existing Datasets').qq|$dbsources +|; + map { print "[ $_ ] " } @dbsources; + + print qq| +
|.$locale->text('Multibyte Encoding').qq|
|.$locale->text('Create Chart of Accounts').qq|@charts|.$locale->text('Create Chart of Accounts').qq| + +|; + while (@charts) { + print qq| + +|; + + map { print "\n" } (0 .. 2); + + print qq| + +|; + + splice @charts, 0, 3; + } + + print qq| +
$charts[$_]
+
+
+
- -


-
{dbdriver}> {dbuser}> {dbhost}> @@ -1326,22 +1445,19 @@ sub create_dataset { {dbpasswd}> {dbdefault}> - + - {path}> -{rpw}> +{sessionid}> +
- - - |; @@ -1357,6 +1473,7 @@ sub dbcreate { $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Database Administration')." / ".$locale->text('Create Dataset'); + $form->{login} = "root login"; $form->header; print qq| @@ -1372,9 +1489,8 @@ sub dbcreate { .qq| - - +{sessionid}> @@ -1393,7 +1509,7 @@ sub delete_dataset { if (@dbsources = User->dbsources_unused(\%$form, $memberfile)) { foreach $item (sort @dbsources) { - $dbsources .= qq| $item\n
|; + $dbsources .= qq| $item |; } } else { $form->error($locale->text('Nothing to delete!')); @@ -1401,18 +1517,17 @@ sub delete_dataset { $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Database Administration')." / ".$locale->text('Delete Dataset'); + $form->{login} = "root login"; $form->header; print qq| - -

$form->{title}

{script}> - +
@@ -1424,9 +1539,7 @@ sub delete_dataset { @@ -1449,11 +1564,6 @@ sub delete_dataset { -

|.$locale->text('Select a Dataset to delete and press "Continue"') - -.qq| - - |; @@ -1471,6 +1581,7 @@ sub dbdelete { $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Database Administration')." / ".$locale->text('Delete Dataset'); + $form->{login} = "root login"; $form->header; print qq| @@ -1486,9 +1597,8 @@ $form->{db} |.$locale->text('successfully deleted!') .qq| - - +{sessionid}> @@ -1502,3 +1612,27 @@ $form->{db} |.$locale->text('successfully deleted!') } + +sub unlock_system { + + unlink "$userspath/nologin"; + + $form->{callback} = "$form->{script}?action=list_users&path=$form->{path}&sessionid=$form->{sessionid}"; + + $form->redirect($locale->text('Lockfile removed!')); + +} + + +sub lock_system { + + open(FH, ">$userspath/nologin") or $form->error($locale->text('Cannot create Lock!')); + close(FH); + + $form->{callback} = "$form->{script}?action=list_users&path=$form->{path}&sessionid=$form->{sessionid}"; + + $form->redirect($locale->text('Lockfile created!')); + +} + + diff --git a/sql-ledger/bin/mozilla/am.pl b/sql-ledger/bin/mozilla/am.pl index 7e36cfdc9..834290343 100644 --- a/sql-ledger/bin/mozilla/am.pl +++ b/sql-ledger/bin/mozilla/am.pl @@ -1,6 +1,6 @@ #===================================================================== # SQL-Ledger Accounting -# Copyright (c) 1998-2002 +# Copyright (c) 2001 # # Author: Dieter Simader # Email: dsimader@sql-ledger.org @@ -30,6 +30,8 @@ use SL::AM; use SL::CA; use SL::Form; use SL::User; +use SL::RP; +use SL::GL; 1; @@ -37,42 +39,54 @@ use SL::User; -sub add { +sub add { &{ "add_$form->{type}" } }; +sub edit { &{ "edit_$form->{type}" } }; +sub save { &{ "save_$form->{type}" } }; +sub delete { &{ "delete_$form->{type}" } }; + + +sub save_as_new { + + delete $form->{id}; + + &save; + +} + +sub add_account { + $form->{title} = "Add"; $form->{charttype} = "A"; - $form->{callback} = "$form->{script}?action=list&path=$form->{path}&login=$form->{login}&password=$form->{password}" unless $form->{callback}; + $form->{callback} = "$form->{script}?action=list_account&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}" unless $form->{callback}; - &form_header; + &account_header; &form_footer; } -sub edit { +sub edit_account { + $form->{title} = "Edit"; - - # if it is a template - if ($form->{file}) { - $form->{type} = "template"; - &edit_template; - exit; - } - + + $form->{accno} =~ s/\\'/'/g; + $form->{accno} =~ s/\\\\/\\/g; + AM->get_account(\%myconfig, \%$form); foreach my $item (split(/:/, $form->{link})) { $form->{$item} = "checked"; } - &form_header; + &account_header; &form_footer; } -sub form_header { +sub account_header { $form->{title} = $locale->text("$form->{title} Account"); @@ -80,7 +94,7 @@ sub form_header { $checked{"$form->{category}_"} = "checked"; $checked{CT_tax} = ($form->{CT_tax}) ? "" : "checked"; - $form->{description} =~ s/"/"/g; + map { $form->{$_} = $form->quote($form->{$_}) } qw(accno description); # this is for our parser only! # type=submit $locale->text('Add Account') @@ -102,8 +116,6 @@ sub form_header { {fxgain_accno_id}> {fxloss_accno_id}> -{amount}> -

|.$locale->text('The following Datasets are not in use and can be deleted').qq|
- -
-
+

{dbdriver}> {dbuser}> {dbhost}> @@ -1434,14 +1547,16 @@ sub delete_dataset { {dbpasswd}> {dbdefault}> - + - - +{sessionid}> +


+ +
@@ -114,7 +126,7 @@ sub form_header {
$form->{title}
- + @@ -126,11 +138,13 @@ sub form_header {
|.$locale->text('Account Number').qq|{accno}>
|.$locale->text('Description').qq|
+ + +
 |.$locale->text('Asset').qq|\n
+  |.$locale->text('Contra').qq|\n
 |.$locale->text('Liability').qq|\n
 |.$locale->text('Equity').qq|\n
 |.$locale->text('Income').qq|\n
 |.$locale->text('Expense') .qq|
   |.$locale->text('Heading').qq|
 |.$locale->text('Account') @@ -169,31 +183,32 @@ if ($form->{charttype} eq "A") {
|.$locale->text('Payables').qq| |.$locale->text('Parts Inventory').qq| |.$locale->text('Service Items').qq||.$locale->text('Labor/Overhead').qq|
{AR_amount}> |.$locale->text('Income').qq|\n
{AR_paid}> |.$locale->text('Payment').qq|\n
- {AR_tax}> |.$locale->text('Tax') - .qq| + {AR_tax}> |.$locale->text('Tax') .qq|
{AP_amount}> |.$locale->text('Expense/Asset').qq|\n
{AP_paid}> |.$locale->text('Payment').qq|\n
- {AP_tax}> |.$locale->text('Tax') - .qq| + {AP_tax}> |.$locale->text('Tax') .qq|
- {IC_sale}> |.$locale->text('Sales').qq|\n
+ {IC_sale}> |.$locale->text('Income').qq|\n
{IC_cogs}> |.$locale->text('COGS').qq|\n
- {IC_taxpart}> |.$locale->text('Tax') - .qq| + {IC_taxpart}> |.$locale->text('Tax') .qq|
{IC_income}> |.$locale->text('Income').qq|\n
{IC_expense}> |.$locale->text('Expense').qq|\n
- {IC_taxservice}> |.$locale->text('Tax') - .qq| + {IC_taxservice}> |.$locale->text('Tax') .qq| +
+
+ {IC_cogs}> |.$locale->text('COGS').qq|\n
@@ -241,16 +256,27 @@ sub form_footer { {path}> {login}> -{password}> +{sessionid}>
|; if ($form->{id}) { + print qq| + +|; + } + + if ($form->{id} && $form->{orphaned}) { print qq||; } + if ($form->{menubar}) { + require "$form->{path}/menu.pl"; + &menubar; + } + print qq| @@ -260,37 +286,57 @@ sub form_footer { } - -sub save { &{ "save_$form->{type}" } }; sub save_account { $form->isblank("accno", $locale->text('Account Number missing!')); $form->isblank("category", $locale->text('Account Type missing!')); + # check for conflicting accounts + if ($form->{AR} || $form->{AP} || $form->{IC}) { + map { $a .= $form->{$_} } qw(AR AP IC); + $form->error($locale->text('Cannot set account for more than one of AR, AP or IC')) if length $a > 2; + + map { $form->error("$form->{AR}$form->{AP}$form->{IC} ". $locale->text('account cannot be set to any other type of account')) if $form->{$_} } qw(AR_amount AR_tax AR_paid AP_amount AP_tax AP_paid IC_sale IC_cogs IC_taxpart IC_income IC_expense IC_taxservice); + } + + foreach $item ("AR", "AP") { + $i = 0; + map { $i++ if $form->{$_} } ("${item}_amount", "${item}_paid", "${item}_tax"); + $form->error($locale->text('Cannot set multiple options for')." $item") if $i > 1; + } + + $i = 0; + map { $i++ if $form->{$_} } qw(IC_sale IC_cogs IC_taxpart); + $form->error($locale->text('Cannot set multiple options for Parts Inventory')) if $i > 1; + + $i = 0; + map { $i++ if $form->{$_} } qw(IC_income IC_expense IC_taxservice); + $form->error($locale->text('Cannot set multiple options for Service Items')) if $i > 1; + $form->redirect($locale->text('Account saved!')) if (AM->save_account(\%myconfig, \%$form)); $form->error($locale->text('Cannot save account!')); } -sub list { +sub list_account { CA->all_accounts(\%myconfig, \%$form); $form->{title} = $locale->text('Chart of Accounts'); # construct callback - $callback = "$form->{script}?action=list&path=$form->{path}&login=$form->{login}&password=$form->{password}"; + $callback = "$form->{script}?action=list_account&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}"; @column_index = qw(accno gifi_accno description debit credit link); - $column_header{accno} = qq||.$locale->text('Account').qq||; - $column_header{gifi_accno} = qq||.$locale->text('GIFI').qq||; - $column_header{description} = qq||.$locale->text('Description').qq||; - $column_header{debit} = qq||.$locale->text('Debit').qq||; - $column_header{credit} = qq||.$locale->text('Credit').qq||; - $column_header{link} = qq||.$locale->text('Link').qq||; + $column_header{accno} = qq||.$locale->text('Account').qq||; + $column_header{gifi_accno} = qq||.$locale->text('GIFI').qq||; + $column_header{description} = qq||.$locale->text('Description').qq||; + $column_header{debit} = qq||.$locale->text('Debit').qq||; + $column_header{credit} = qq||.$locale->text('Credit').qq||; + $column_header{link} = qq||.$locale->text('Link').qq||; $form->header; @@ -299,8 +345,10 @@ sub list { print qq| - - +
$form->{title}
+ + + |; @@ -319,15 +367,10 @@ sub list { $ca->{debit} = " "; $ca->{credit} = " "; - # needed if we can delete an account - $amount = 0; - if ($ca->{amount} > 0) { - $amount = $ca->{amount}; $ca->{credit} = $form->format_amount(\%myconfig, $ca->{amount}, 2, " "); } if ($ca->{amount} < 0) { - $amount = -$ca->{amount}; $ca->{debit} = $form->format_amount(\%myconfig, -$ca->{amount}, 2, " "); } @@ -336,8 +379,8 @@ sub list { if ($ca->{charttype} eq "H") { print qq||; - $column_data{accno} = qq||; - $column_data{gifi_accno} = qq||; + $column_data{accno} = qq||; + $column_data{gifi_accno} = qq||; $column_data{description} = qq||; $column_data{debit} = qq||; $column_data{credit} = qq| |; @@ -347,8 +390,8 @@ sub list { $i++; $i %= 2; print qq| |; - $column_data{accno} = qq||; - $column_data{gifi_accno} = qq||; + $column_data{accno} = qq||; + $column_data{gifi_accno} = qq||; $column_data{description} = qq||; $column_data{debit} = qq||; $column_data{credit} = qq||; @@ -372,16 +415,10 @@ sub list { } -sub delete { &{ "delete_$form->{type}" } }; - sub delete_account { $form->{title} = $locale->text('Delete Account'); - if ($form->{amount} != 0) { - $form->error($locale->text('Transactions exist; cannot delete account!')); - } - foreach $id (qw(inventory_accno_id income_accno_id expense_accno_id fxgain_accno_id fxloss_accno_id)) { if ($form->{id} == $form->{$id}) { $form->error($locale->text('Cannot delete default account!')); @@ -396,16 +433,15 @@ sub delete_account { sub list_gifi { - @{ $form->{fields} } = (accno, description); + @{ $form->{fields} } = qw(accno description); $form->{table} = "gifi"; - $form->{sortorder} = "accno"; AM->gifi_accounts(\%myconfig, \%$form); $form->{title} = $locale->text('GIFI'); # construct callback - $callback = "$form->{script}?action=list_gifi&path=$form->{path}&login=$form->{login}&password=$form->{password}"; + $callback = "$form->{script}?action=list_gifi&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}"; @column_index = qw(accno description); @@ -419,8 +455,10 @@ sub list_gifi { print qq| -
$form->{title}
{script}?action=edit&id=$ca->{id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ca->{accno}{script}?action=edit_gifi&accno=$ca->{gifi_accno}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ca->{gifi_accno} {script}?action=edit_account&id=$ca->{id}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}&callback=$callback>$ca->{accno}{script}?action=edit_gifi&accno=$ca->{gifi_accno}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}&callback=$callback>$ca->{gifi_accno} $ca->{description}   
{script}?action=edit&id=$ca->{id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback&amount=$amount>$ca->{accno}{script}?action=edit_gifi&accno=$ca->{gifi_accno}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback&amount=$amount>$ca->{gifi_accno} {script}?action=edit_account&id=$ca->{id}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}&callback=$callback>$ca->{accno}{script}?action=edit_gifi&accno=$ca->{gifi_accno}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}&callback=$callback>$ca->{gifi_accno} $ca->{description} $ca->{debit}$ca->{credit}
- +
$form->{title}
+ + + |; @@ -441,7 +479,7 @@ sub list_gifi { print qq| |; - $column_data{accno} = qq||; + $column_data{accno} = qq||; $column_data{description} = qq||; map { print "$column_data{$_}\n" } @column_index; @@ -466,7 +504,7 @@ sub add_gifi { $form->{title} = "Add"; # construct callback - $form->{callback} = "$form->{script}?action=list_gifi&path=$form->{path}&login=$form->{login}&password=$form->{password}"; + $form->{callback} = "$form->{script}?action=list_gifi&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}"; $form->{coa} = 1; @@ -479,8 +517,10 @@ sub add_gifi { sub edit_gifi { $form->{title} = "Edit"; - + AM->get_gifi(\%myconfig, \%$form); + + $form->error($locale->text('Account does not exist!')) unless $form->{accno}; &gifi_header; &gifi_footer; @@ -495,7 +535,7 @@ sub gifi_header { # $locale->text('Add GIFI') # $locale->text('Edit GIFI') - $form->{description} =~ s/"/"/g; + map { $form->{$_} = $form->quote($form->{$_}) } qw(accno description); $form->header; @@ -504,7 +544,7 @@ sub gifi_header { {script}> -{accno}> +
$form->{title}
{script}?action=edit_gifi&coa=1&accno=$ca->{accno}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ca->{accno}{script}?action=edit_gifi&coa=1&accno=$ca->{accno}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}&callback=$callback>$ca->{accno}$ca->{description} 
@@ -517,7 +557,7 @@ sub gifi_header {
- + @@ -543,23 +583,27 @@ sub gifi_footer { {path}> {login}> -{password}> +{sessionid}> -
-|; +
|; if ($form->{coa}) { print qq| |; - if ($form->{accno}) { + if ($form->{accno} && $form->{orphaned}) { print qq||; } } + if ($form->{menubar}) { + require "$form->{path}/menu.pl"; + &menubar; + } + print qq| - + @@ -585,10 +629,11 @@ sub copy_to_coa { delete $form->{id}; $form->{gifi_accno} = $form->{accno}; + $form->{title} = "Add"; $form->{charttype} = "A"; - &form_header; + &account_header; &form_footer; } @@ -602,317 +647,1222 @@ sub delete_gifi { } -sub display_stylesheet { - - $form->{file} = "css/$myconfig{stylesheet}"; - &display_form; +sub add_department { + + $form->{title} = "Add"; + $form->{role} = "P"; + $form->{callback} = "$form->{script}?action=add_department&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}" unless $form->{callback}; + + &department_header; + &form_footer; + } -sub display_form { +sub edit_department { - $form->{file} =~ s/^(.:)*?\/|\.\.\///g; - $form->{file} =~ s/^\/*//g; - $form->{file} =~ s/$userspath//; + $form->{title} = "Edit"; - $form->error("$!: $form->{file}") unless -f $form->{file}; + AM->get_department(\%myconfig, \%$form); - AM->load_template(\%$form); + &department_header; + &form_footer; - $form->{title} = $form->{file}; +} + + +sub list_department { + + AM->departments(\%myconfig, \%$form); + + $href = "$form->{script}?action=list_department&direction=$form->{direction}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}"; + + $form->sort_order(); + + $form->{callback} = "$form->{script}?action=list_department&direction=$form->{direction}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}"; + + $callback = $form->escape($form->{callback}); + + $form->{title} = $locale->text('Departments'); + + @column_index = qw(description cost profit); + + $column_header{description} = qq||; + $column_header{cost} = qq||; + $column_header{profit} = qq||; - # if it is anything but html - if ($form->{file} !~ /\.html$/) { - $form->{body} = "
\n$form->{body}\n
"; - } - $form->header; print qq| -$form->{body} +
|.$locale->text('GIFI').qq|{accno}>
|.$locale->text('Description').qq| |.$locale->text('Description').qq||.$locale->text('Cost Center').qq||.$locale->text('Profit Center').qq|
+ + + + + + + + + + +
$form->{title}
+ + +|; + + map { print "$column_header{$_}\n" } @column_index; + + print qq| + +|; + + foreach $ref (@{ $form->{ALL} }) { + + $i++; $i %= 2; + + print qq| + +|; + + $costcenter = ($ref->{role} eq "C") ? "*" : " "; + $profitcenter = ($ref->{role} eq "P") ? "*" : " "; + + $column_data{description} = qq||; + $column_data{cost} = qq||; + $column_data{profit} = qq||; + + map { print "$column_data{$_}\n" } @column_index; + + print qq| + +|; + } + + print qq| +
{script}?action=edit_department&id=$ref->{id}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}&callback=$callback>$ref->{description}$costcenter$profitcenter
+

+
{script}> -{file}> + + + {path}> {login}> -{password}> +{sessionid}> - -
+|; + if ($form->{menubar}) { + require "$form->{path}/menu.pl"; + &menubar; + } - - + print qq| + + + + |; - + } -sub edit_template { +sub department_header { - AM->load_template(\%$form); + $form->{title} = $locale->text("$form->{title} Department"); - $form->{title} = $locale->text('Edit Template'); - # convert   to &nbsp; - $form->{body} =~ s/ /&nbsp;/gi; - +# $locale->text('Add Department') +# $locale->text('Edit Department') - $form->header; + $form->{description} = $form->quote($form->{description}); + + if (($rows = $form->numtextrows($form->{description}, 60)) > 1) { + $description = qq||; + } else { + $description = qq||; + } + + $costcenter = "checked" if $form->{role} eq "C"; + $profitcenter = "checked" if $form->{role} eq "P"; + $form->header; + print qq|
{script}> -{file}> - +{id}> + -{path}> -{login}> -{password}> + + + + + + + + + + + + + + + +
$form->{title}
|.$locale->text('Description').qq|$description
|.$locale->text('Cost Center').qq| + |.$locale->text('Profit Center').qq| +

+|; - +} - -
- +sub save_department { -
+ $form->isblank("description", $locale->text('Description missing!')); + AM->save_department(\%myconfig, \%$form); + $form->redirect($locale->text('Department saved!')); +} - - -|; + +sub delete_department { + + AM->delete_department(\%myconfig, \%$form); + $form->redirect($locale->text('Department deleted!')); } -sub save_template { +sub add_business { - AM->save_template(\%$form); - $form->redirect($locale->text('Template saved!')); + $form->{title} = "Add"; + $form->{callback} = "$form->{script}?action=add_business&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}" unless $form->{callback}; + + &business_header; + &form_footer; + } -sub config { +sub edit_business { - # get defaults for account numbers and last numbers - AM->defaultaccounts(\%myconfig, \%$form); + $form->{title} = "Edit"; - foreach $item (qw(mm-dd-yy mm/dd/yy dd-mm-yy dd/mm/yy dd.mm.yy yyyy-mm-dd)) { - $dateformat .= ($item eq $myconfig{dateformat}) ? "