1 #=====================================================================
2 # SQL-Ledger Accounting
5 # Author: Dieter Simader
6 # Email: dsimader@sql-ledger.org
7 # Web: http://www.sql-ledger.org
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #======================================================================
25 # Accounts Payables database backend routines
27 #======================================================================
33 sub post_transaction {
34 my ($self, $myconfig, $form) = @_;
37 my $dbh = $form->dbconnect_noauto($myconfig);
44 # split and store id numbers in link accounts
45 map { ($form->{AP_amounts}{"amount_$_"}) = split(/--/, $form->{"AP_amount_$_"}) } (1 .. $form->{rowcount});
46 ($form->{AP_amounts}{payables}) = split(/--/, $form->{AP});
48 ($null, $form->{department_id}) = split(/--/, $form->{department});
49 $form->{department_id} *= 1;
51 if ($form->{currency} eq $form->{defaultcurrency}) {
52 $form->{exchangerate} = 1;
54 $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'sell');
56 $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate});
59 # reverse and parse amounts
60 for my $i (1 .. $form->{rowcount}) {
61 $form->{"amount_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"amount_$i"}) * $form->{exchangerate} * -1, 2);
62 $form->{netamount} += ($form->{"amount_$i"} * -1);
66 # taxincluded doesn't make sense if there is no amount
67 $form->{taxincluded} = 0 if ($form->{netamount} == 0);
69 for my $item (split / /, $form->{taxaccounts}) {
70 $form->{AP_amounts}{"tax_$item"} = $item;
72 $form->{"tax_$item"} = $form->round_amount($form->parse_amount($myconfig, $form->{"tax_$item"}) * $form->{exchangerate}, 2) * -1;
73 $form->{tax} += ($form->{"tax_$item"} * -1);
77 # adjust paidaccounts if there is no date in the last row
78 $form->{paidaccounts}-- unless ($form->{"datepaid_$form->{paidaccounts}"});
82 for my $i (1 .. $form->{paidaccounts}) {
83 $form->{"paid_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"paid_$i"}), 2);
85 $form->{paid} += $form->{"paid_$i"};
86 $form->{datepaid} = $form->{"datepaid_$i"};
91 if ($form->{taxincluded} *= 1) {
92 for $i (1 .. $form->{rowcount}) {
93 $tax = ($form->{netamount}) ? $form->{tax} * $form->{"amount_$i"} / $form->{netamount} : 0;
94 $amount = $form->{"amount_$i"} - $tax;
95 $form->{"amount_$i"} = $form->round_amount($amount, 2);
96 $diff += $amount - $form->{"amount_$i"};
99 $form->{netamount} -= $form->{tax};
100 # deduct difference from amount_1
101 $form->{amount_1} += $form->round_amount($diff, 2);
104 $form->{amount} = $form->{netamount} + $form->{tax};
105 $form->{paid} = $form->round_amount($form->{paid} * $form->{exchangerate}, 2);
110 # if we have an id delete old records
113 # delete detail records
114 $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|;
115 $dbh->do($query) || $form->dberror($query);
119 $uid .= $form->{login};
121 $query = qq|INSERT INTO ap (invnumber, employee_id)
122 VALUES ('$uid', (SELECT id FROM employee
123 WHERE login = '$form->{login}') )|;
124 $dbh->do($query) || $form->dberror($query);
126 $query = qq|SELECT id FROM ap
127 WHERE invnumber = '$uid'|;
128 ($form->{id}) = $dbh->selectrow_array($query);
131 $form->{datepaid} = $form->{transdate} unless ($form->{datepaid});
132 my $datepaid = ($form->{paid} != 0) ? qq|'$form->{datepaid}'| : 'NULL';
134 $query = qq|UPDATE ap SET
135 invnumber = |.$dbh->quote($form->{invnumber}).qq|,
136 transdate = '$form->{transdate}',
137 ordnumber = |.$dbh->quote($form->{ordnumber}).qq|,
138 vendor_id = $form->{vendor_id},
139 taxincluded = '$form->{taxincluded}',
140 amount = $form->{amount},
141 duedate = |.$form->dbquote($form->{duedate}, SQL_DATE).qq|,
142 paid = $form->{paid},
143 datepaid = $datepaid,
144 netamount = $form->{netamount},
145 curr = |.$dbh->quote($form->{currency}).qq|,
146 notes = |.$dbh->quote($form->{notes}).qq|,
147 department_id = $form->{department_id}
148 WHERE id = $form->{id}
150 $dbh->do($query) || $form->dberror($query);
152 # amount for AP account
153 $form->{payables} = $form->{amount};
156 # update exchangerate
157 if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
158 $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, 0, $form->{exchangerate});
161 # add individual transactions
162 foreach my $item (keys %{ $form->{AP_amounts} }) {
164 if ($form->{$item} != 0) {
166 $project_id = 'NULL';
167 if ($item =~ /amount_/) {
168 if ($form->{"projectnumber_$'"}) {
169 ($null, $project_id) = split /--/, $form->{"projectnumber_$'"}
173 # insert detail records in acc_trans
174 $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
176 VALUES ($form->{id}, (SELECT id FROM chart
177 WHERE accno = '$form->{AP_amounts}{$item}'),
178 $form->{$item}, '$form->{transdate}', $project_id)|;
179 $dbh->do($query) || $form->dberror($query);
183 # if there is no amount but a payment record a payable
184 if ($form->{amount} == 0) {
185 $form->{payables} = $form->{paid};
186 $form->{payables} -= $form->{paid_1} if $form->{amount_1} != 0;
189 # add paid transactions
190 for my $i (1 .. $form->{paidaccounts}) {
191 if ($form->{"paid_$i"} != 0) {
194 ($form->{AP_amounts}{"paid_$i"}) = split(/--/, $form->{"AP_paid_$i"});
195 $form->{"datepaid_$i"} = $form->{transdate} unless ($form->{"datepaid_$i"});
198 if ($form->{currency} eq $form->{defaultcurrency}) {
199 $form->{"exchangerate_$i"} = 1;
201 $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'sell');
203 $form->{"exchangerate_$i"} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
207 # if there is no amount
208 if ($form->{amount} == 0 && $form->{netamount} == 0) {
209 $form->{exchangerate} = $form->{"exchangerate_$i"};
212 $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} * -1, 2);
213 if ($form->{payables} != 0) {
214 $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
217 (SELECT id FROM chart
218 WHERE accno = '$form->{AP_amounts}{payables}'),
219 $amount, '$form->{"datepaid_$i"}')|;
220 $dbh->do($query) || $form->dberror($query);
222 $form->{payables} = $amount;
225 $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
226 transdate, source, memo)
228 (SELECT id FROM chart
229 WHERE accno = '$form->{AP_amounts}{"paid_$i"}'),
230 $form->{"paid_$i"}, '$form->{"datepaid_$i"}', |
231 .$dbh->quote($form->{"source_$i"}).qq|, |
232 .$dbh->quote($form->{"memo_$i"}).qq|)|;
233 $dbh->do($query) || $form->dberror($query);
235 # add exchange rate difference
236 $amount = $form->round_amount($form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1), 2);
238 $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
239 transdate, fx_transaction, cleared)
241 (SELECT id FROM chart
242 WHERE accno = '$form->{AP_amounts}{"paid_$i"}'),
243 $amount, '$form->{"datepaid_$i"}', '1', '0')|;
245 $dbh->do($query) || $form->dberror($query);
248 # exchangerate gain/loss
249 $amount = $form->round_amount($form->{"paid_$i"} * ($form->{exchangerate} - $form->{"exchangerate_$i"}), 2);
252 $accno = ($amount > 0) ? $form->{fxgain_accno} : $form->{fxloss_accno};
253 $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
254 transdate, fx_transaction, cleared)
255 VALUES ($form->{id}, (SELECT id FROM chart
256 WHERE accno = '$accno'),
257 $amount, '$form->{"datepaid_$i"}', '1', '0')|;
258 $dbh->do($query) || $form->dberror($query);
261 # update exchange rate record
262 if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
263 $form->update_exchangerate($dbh, $form->{currency}, $form->{"datepaid_$i"}, 0, $form->{"exchangerate_$i"});
268 # save printed and queued
269 $form->save_status($dbh);
271 my %audittrail = ( tablename => 'ap',
272 reference => $form->{invnumber},
273 formname => 'transaction',
276 $form->audittrail($dbh, "", \%audittrail);
278 my $rc = $dbh->commit;
288 sub delete_transaction {
289 my ($self, $myconfig, $form, $spool) = @_;
291 # connect to database
292 my $dbh = $form->dbconnect_noauto($myconfig);
294 my %audittrail = ( tablename => 'ap',
295 reference => $form->{invnumber},
296 formname => 'transaction',
299 $form->audittrail($dbh, "", \%audittrail);
301 my $query = qq|DELETE FROM ap WHERE id = $form->{id}|;
302 $dbh->do($query) || $form->dberror($query);
304 $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|;
305 $dbh->do($query) || $form->dberror($query);
308 $query = qq|SELECT spoolfile FROM status
309 WHERE trans_id = $form->{id}
310 AND spoolfile IS NOT NULL|;
311 my $sth = $dbh->prepare($query);
312 $sth->execute || $form->dberror($query);
317 while (($spoolfile) = $sth->fetchrow_array) {
318 push @spoolfiles, $spoolfile;
322 $query = qq|DELETE FROM status WHERE trans_id = $form->{id}|;
323 $dbh->do($query) || $form->dberror($query);
325 # commit and redirect
326 my $rc = $dbh->commit;
330 foreach $spoolfile (@spoolfiles) {
331 unlink "$spool/$spoolfile" if $spoolfile;
342 sub ap_transactions {
343 my ($self, $myconfig, $form) = @_;
345 # connect to database
346 my $dbh = $form->dbconnect($myconfig);
351 if ($form->{outstanding}) {
352 $paid = qq|SELECT SUM(ac.amount)
354 JOIN chart c ON (c.id = ac.chart_id)
355 WHERE ac.trans_id = a.id
356 AND (c.link LIKE '%AP_paid%' OR c.link = '')|;
358 AND ac.transdate <= '$form->{transdateto}'| if $form->{transdateto};
361 my $query = qq|SELECT a.id, a.invnumber, a.transdate, a.duedate,
362 a.amount, ($paid) AS paid, a.ordnumber, v.name,
363 a.invoice, a.netamount, a.datepaid, a.notes,
364 a.vendor_id, e.name AS employee, m.name AS manager,
365 a.curr, ex.sell AS exchangerate
367 JOIN vendor v ON (a.vendor_id = v.id)
368 LEFT JOIN employee e ON (a.employee_id = e.id)
369 LEFT JOIN employee m ON (e.managerid = m.id)
370 LEFT JOIN exchangerate ex ON (ex.curr = a.curr
371 AND ex.transdate = a.transdate)
374 my %ordinal = ( 'id' => 1,
386 my @a = (transdate, invnumber, name);
387 push @a, "employee" if $form->{l_employee};
388 push @a, "manager" if $form->{l_manager};
389 my $sortorder = $form->sort_order(\@a, \%ordinal);
393 if ($form->{vendor_id}) {
394 $where .= " AND a.vendor_id = $form->{vendor_id}";
396 if ($form->{vendor}) {
397 $var = $form->like(lc $form->{vendor});
398 $where .= " AND lower(v.name) LIKE '$var'";
401 if ($form->{department}) {
402 my ($null, $department_id) = split /--/, $form->{department};
403 $where .= " AND a.department_id = $department_id";
405 if ($form->{invnumber}) {
406 $var = $form->like(lc $form->{invnumber});
407 $where .= " AND lower(a.invnumber) LIKE '$var'";
408 $form->{open} = $form->{closed} = 0;
410 if ($form->{ordnumber}) {
411 $var = $form->like(lc $form->{ordnumber});
412 $where .= " AND lower(a.ordnumber) LIKE '$var'";
413 $form->{open} = $form->{closed} = 0;
415 if ($form->{notes}) {
416 $var = $form->like(lc $form->{notes});
417 $where .= " AND lower(a.notes) LIKE '$var'";
420 ($form->{transdatefrom}, $form->{transdateto}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month};
422 $where .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom};
423 $where .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto};
424 if ($form->{open} || $form->{closed}) {
425 unless ($form->{open} && $form->{closed}) {
426 $where .= " AND a.amount != a.paid" if ($form->{open});
427 $where .= " AND a.amount = a.paid" if ($form->{closed});
433 my ($accno) = split /--/, $form->{AP};
435 AND a.id IN (SELECT ac.trans_id
437 JOIN chart c ON (c.id = ac.chart_id)
438 WHERE a.id = ac.trans_id
439 AND c.accno = '$accno')
443 $query .= "WHERE $where
444 ORDER by $sortorder";
446 my $sth = $dbh->prepare($query);
447 $sth->execute || $form->dberror($query);
449 while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
450 $ref->{exchangerate} = 1 unless $ref->{exchangerate};
451 if ($form->{outstanding}) {
452 next if $form->round_amount($ref->{amount}, 2) == $form->round_amount($ref->{paid}, 2);
454 push @{ $form->{transactions} }, $ref;