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 Receivable module backend routines
27 #======================================================================
32 sub post_transaction {
33 my ($self, $myconfig, $form) = @_;
43 # split and store id numbers in link accounts
44 map { ($form->{AR_amounts}{"amount_$_"}) = split(/--/, $form->{"AR_amount_$_"}) } (1 .. $form->{rowcount});
45 ($form->{AR_amounts}{receivables}) = split(/--/, $form->{AR});
47 ($null, $form->{department_id}) = split(/--/, $form->{department});
48 $form->{department_id} *= 1;
50 if ($form->{currency} eq $form->{defaultcurrency}) {
51 $form->{exchangerate} = 1;
53 $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'buy');
55 $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate});
58 for $i (1 .. $form->{rowcount}) {
59 $form->{"amount_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"amount_$i"}) * $form->{exchangerate}, 2);
61 $form->{netamount} += $form->{"amount_$i"};
66 # taxincluded doesn't make sense if there is no amount
67 $form->{taxincluded} = 0 if ($form->{netamount} == 0);
69 foreach my $item (split / /, $form->{taxaccounts}) {
70 $form->{AR_amounts}{"tax_$item"} = $item;
72 $form->{"tax_$item"} = $form->round_amount($form->parse_amount($myconfig, $form->{"tax_$item"}) * $form->{exchangerate}, 2);
73 $form->{tax} += $form->{"tax_$item"};
76 # adjust paidaccounts if there is no date in the last row
77 $form->{paidaccounts}-- unless ($form->{"datepaid_$form->{paidaccounts}"});
81 for $i (1 .. $form->{paidaccounts}) {
82 $form->{"paid_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"paid_$i"}), 2);
84 $form->{paid} += $form->{"paid_$i"};
85 $form->{datepaid} = $form->{"datepaid_$i"};
90 if ($form->{taxincluded} *= 1) {
91 for $i (1 .. $form->{rowcount}) {
92 $tax = ($form->{netamount}) ? $form->{tax} * $form->{"amount_$i"} / $form->{netamount} : 0;
93 $amount = $form->{"amount_$i"} - $tax;
94 $form->{"amount_$i"} = $form->round_amount($amount, 2);
95 $diff += $amount - $form->{"amount_$i"};
98 $form->{netamount} -= $form->{tax};
99 # deduct difference from amount_1
100 $form->{amount_1} += $form->round_amount($diff, 2);
103 $form->{amount} = $form->{netamount} + $form->{tax};
104 $form->{paid} = $form->round_amount($form->{paid} * $form->{exchangerate}, 2);
106 # connect to database
107 my $dbh = $form->dbconnect_noauto($myconfig);
112 ($null, $form->{employee_id}) = split /--/, $form->{employee};
113 unless ($form->{employee_id}) {
114 ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh);
117 # if we have an id delete old records
120 # delete detail records
121 $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|;
122 $dbh->do($query) || $form->dberror($query);
126 $uid .= $form->{login};
128 $query = qq|INSERT INTO ar (invnumber)
130 $dbh->do($query) || $form->dberror($query);
132 $query = qq|SELECT id FROM ar
133 WHERE invnumber = '$uid'|;
134 ($form->{id}) = $dbh->selectrow_array($query);
138 # record last payment date in ar table
139 $form->{datepaid} = $form->{transdate} unless $form->{datepaid};
140 my $datepaid = ($form->{paid} != 0) ? qq|'$form->{datepaid}'| : 'NULL';
142 $query = qq|UPDATE ar set
143 invnumber = |.$dbh->quote($form->{invnumber}).qq|,
144 ordnumber = |.$dbh->quote($form->{ordnumber}).qq|,
145 transdate = '$form->{transdate}',
146 customer_id = $form->{customer_id},
147 taxincluded = '$form->{taxincluded}',
148 amount = $form->{amount},
149 duedate = '$form->{duedate}',
150 paid = $form->{paid},
151 datepaid = $datepaid,
152 netamount = $form->{netamount},
153 curr = '$form->{currency}',
154 notes = |.$dbh->quote($form->{notes}).qq|,
155 department_id = $form->{department_id},
156 employee_id = $form->{employee_id}
157 WHERE id = $form->{id}|;
158 $dbh->do($query) || $form->dberror($query);
161 # amount for AR account
162 $form->{receivables} = $form->{amount} * -1;
165 # update exchangerate
166 if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
167 $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, $form->{exchangerate}, 0);
170 # add individual transactions for AR, amount and taxes
171 foreach my $item (keys %{ $form->{AR_amounts} }) {
173 if ($form->{$item} != 0) {
175 $project_id = 'NULL';
176 if ($item =~ /amount_/) {
177 if ($form->{"projectnumber_$'"}) {
178 ($null, $project_id) = split /--/, $form->{"projectnumber_$'"};
182 # insert detail records in acc_trans
183 $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
185 VALUES ($form->{id}, (SELECT id FROM chart
186 WHERE accno = '$form->{AR_amounts}{$item}'),
187 $form->{$item}, '$form->{transdate}', $project_id)|;
188 $dbh->do($query) || $form->dberror($query);
192 if ($form->{amount} == 0) {
193 $form->{receivables} = $form->{paid};
194 $form->{receivables} -= $form->{paid_1} if $form->{amount_1} != 0;
197 # add paid transactions
198 for my $i (1 .. $form->{paidaccounts}) {
199 if ($form->{"paid_$i"} != 0) {
201 ($form->{AR_amounts}{"paid_$i"}) = split(/--/, $form->{"AR_paid_$i"});
202 $form->{"datepaid_$i"} = $form->{transdate} unless ($form->{"datepaid_$i"});
205 if ($form->{currency} eq $form->{defaultcurrency}) {
206 $form->{"exchangerate_$i"} = 1;
208 $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy');
210 $form->{"exchangerate_$i"} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
214 # if there is no amount
215 if ($form->{amount} == 0 && $form->{netamount} == 0) {
216 $form->{exchangerate} = $form->{"exchangerate_$i"};
220 $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate}, 2);
222 if ($form->{receivables} != 0) {
224 $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
227 (SELECT id FROM chart
228 WHERE accno = '$form->{AR_amounts}{receivables}'),
229 $amount, '$form->{"datepaid_$i"}')|;
230 $dbh->do($query) || $form->dberror($query);
232 $form->{receivables} = $amount;
234 if ($form->{"paid_$i"} != 0) {
236 $amount = $form->{"paid_$i"} * -1;
237 $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
238 transdate, source, memo)
240 (SELECT id FROM chart
241 WHERE accno = '$form->{AR_amounts}{"paid_$i"}'),
242 $amount, '$form->{"datepaid_$i"}', |
243 .$dbh->quote($form->{"source_$i"}).qq|, |
244 .$dbh->quote($form->{"memo_$i"}).qq|)|;
245 $dbh->do($query) || $form->dberror($query);
248 # exchangerate difference for payment
249 $amount = $form->round_amount($form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) * -1, 2);
252 $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
253 transdate, fx_transaction, cleared)
255 (SELECT id FROM chart
256 WHERE accno = '$form->{AR_amounts}{"paid_$i"}'),
257 $amount, '$form->{"datepaid_$i"}', '1', '0')|;
258 $dbh->do($query) || $form->dberror($query);
261 # exchangerate gain/loss
262 $amount = $form->round_amount($form->{"paid_$i"} * ($form->{exchangerate} - $form->{"exchangerate_$i"}) * -1, 2);
265 $accno = ($amount > 0) ? $form->{fxgain_accno} : $form->{fxloss_accno};
266 $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
267 transdate, fx_transaction, cleared)
268 VALUES ($form->{id}, (SELECT id FROM chart
269 WHERE accno = '$accno'),
270 $amount, '$form->{"datepaid_$i"}', '1', '0')|;
271 $dbh->do($query) || $form->dberror($query);
275 # update exchangerate record
276 if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
277 $form->update_exchangerate($dbh, $form->{currency}, $form->{"datepaid_$i"}, $form->{"exchangerate_$i"}, 0);
282 # save printed and queued
283 $form->save_status($dbh);
285 my %audittrail = ( tablename => 'ar',
286 reference => $form->{invnumber},
287 formname => 'transaction',
291 $form->audittrail($dbh, "", \%audittrail);
293 my $rc = $dbh->commit;
302 sub delete_transaction {
303 my ($self, $myconfig, $form) = @_;
305 # connect to database, turn AutoCommit off
306 my $dbh = $form->dbconnect_noauto($myconfig);
308 my %audittrail = ( tablename => 'ar',
309 reference => $form->{invnumber},
310 formname => 'transaction',
314 $form->audittrail($dbh, "", \%audittrail);
316 my $query = qq|DELETE FROM ar WHERE id = $form->{id}|;
317 $dbh->do($query) || $form->dberror($query);
319 $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|;
320 $dbh->do($query) || $form->dberror($query);
323 $query = qq|SELECT spoolfile FROM status
324 WHERE trans_id = $form->{id}
325 AND spoolfile IS NOT NULL|;
326 my $sth = $dbh->prepare($query);
327 $sth->execute || $form->dberror($query);
332 while (($spoolfile) = $sth->fetchrow_array) {
333 push @spoolfiles, $spoolfile;
337 $query = qq|DELETE FROM status WHERE trans_id = $form->{id}|;
338 $dbh->do($query) || $form->dberror($query);
341 my $rc = $dbh->commit;
345 foreach $spoolfile (@spoolfiles) {
346 unlink "$spool/$spoolfile" if $spoolfile;
356 sub ar_transactions {
357 my ($self, $myconfig, $form) = @_;
359 # connect to database
360 my $dbh = $form->dbconnect($myconfig);
365 ($form->{transdatefrom}, $form->{transdateto}) = $form->from_to($form->{year}, $form->{month}, $form->{interval}) if $form->{year} && $form->{month};
367 if ($form->{outstanding}) {
368 $paid = qq|SELECT SUM(ac.amount) * -1
370 JOIN chart c ON (c.id = ac.chart_id)
371 WHERE ac.trans_id = a.id
372 AND (c.link LIKE '%AR_paid%' OR c.link = '')|;
374 AND ac.transdate <= '$form->{transdateto}'| if $form->{transdateto};
377 my $query = qq|SELECT a.id, a.invnumber, a.ordnumber, a.transdate,
378 a.duedate, a.netamount, a.amount, ($paid) AS paid,
379 a.invoice, a.datepaid, a.terms, a.notes,
380 a.shipvia, a.shippingpoint, e.name AS employee, c.name,
381 a.customer_id, a.till, m.name AS manager, a.curr,
382 ex.buy AS exchangerate
384 JOIN customer c ON (a.customer_id = c.id)
385 LEFT JOIN employee e ON (a.employee_id = e.id)
386 LEFT JOIN employee m ON (e.managerid = m.id)
387 LEFT JOIN exchangerate ex ON (ex.curr = a.curr
388 AND ex.transdate = a.transdate)
391 my %ordinal = ( 'id' => 1,
398 'shippingpoint' => 14,
406 my @a = (transdate, invnumber, name);
407 push @a, "employee" if $form->{l_employee};
408 push @a, "manager" if $form->{l_manager};
409 my $sortorder = $form->sort_order(\@a, \%ordinal);
412 if ($form->{customer_id}) {
413 $where .= " AND a.customer_id = $form->{customer_id}";
415 if ($form->{customer}) {
416 $var = $form->like(lc $form->{customer});
417 $where .= " AND lower(c.name) LIKE '$var'";
420 if ($form->{department}) {
421 my ($null, $department_id) = split /--/, $form->{department};
422 $where .= " AND a.department_id = $department_id";
424 if ($form->{invnumber}) {
425 $var = $form->like(lc $form->{invnumber});
426 $where .= " AND lower(a.invnumber) LIKE '$var'";
427 $form->{open} = $form->{closed} = 0;
429 if ($form->{ordnumber}) {
430 $var = $form->like(lc $form->{ordnumber});
431 $where .= " AND lower(a.ordnumber) LIKE '$var'";
432 $form->{open} = $form->{closed} = 0;
434 if ($form->{shipvia}) {
435 $var = $form->like(lc $form->{shipvia});
436 $where .= " AND lower(a.shipvia) LIKE '$var'";
438 if ($form->{notes}) {
439 $var = $form->like(lc $form->{notes});
440 $where .= " AND lower(a.notes) LIKE '$var'";
443 $where .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom};
444 $where .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto};
445 if ($form->{open} || $form->{closed}) {
446 unless ($form->{open} && $form->{closed}) {
447 $where .= " AND a.amount != a.paid" if ($form->{open});
448 $where .= " AND a.amount = a.paid" if ($form->{closed});
453 $where .= " AND a.invoice = '1'
454 AND NOT a.till IS NULL";
455 if ($myconfig->{role} eq 'user') {
456 $where .= " AND e.login = '$form->{login}'";
461 my ($accno) = split /--/, $form->{AR};
463 AND a.id IN (SELECT ac.trans_id
465 JOIN chart c ON (c.id = ac.chart_id)
466 WHERE a.id = ac.trans_id
467 AND c.accno = '$accno')
471 $query .= "WHERE $where
472 ORDER by $sortorder";
474 my $sth = $dbh->prepare($query);
475 $sth->execute || $form->dberror($query);
477 while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
478 $ref->{exchangerate} = 1 unless $ref->{exchangerate};
479 if ($form->{outstanding}) {
480 next if $form->round_amount($ref->{amount}, 2) == $form->round_amount($ref->{paid}, 2);
482 push @{ $form->{transactions} }, $ref;