import sql-ledger 2.4.4
[freeside.git] / sql-ledger / sql-ledger / SL / CP.pm
1 #=====================================================================
2 # SQL-Ledger Accounting
3 # Copyright (C) 2003
4 #
5 #  Author: Dieter Simader
6 #   Email: dsimader@sql-ledger.org
7 #     Web: http://www.sql-ledger.org
8 #
9 #  Contributors:
10 #
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.
15 #
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 #======================================================================
24 #
25 # Check and receipt printing payment module backend routines
26 # Number to text conversion routines are in
27 # locale/{countrycode}/Num2text
28 #
29 #======================================================================
30
31 package CP;
32
33
34 sub new {
35   my ($type, $countrycode) = @_;
36
37   $self = {};
38
39   if ($countrycode) {
40     if (-f "locale/$countrycode/Num2text") {
41       require "locale/$countrycode/Num2text";
42     } else {
43       use SL::Num2text;
44     }
45   } else {
46     use SL::Num2text;
47   }
48
49   bless $self, $type;
50
51 }
52
53
54 sub paymentaccounts {
55   my ($self, $myconfig, $form) = @_;
56
57   # connect to database
58   my $dbh = $form->dbconnect($myconfig);
59   
60   my $query = qq|SELECT accno, description, link
61                  FROM chart
62                  WHERE link LIKE '%$form->{ARAP}%'
63                  ORDER BY accno|;
64   my $sth = $dbh->prepare($query);
65   $sth->execute || $form->dberror($query);
66
67   $form->{PR}{$form->{ARAP}} = ();
68   $form->{PR}{"$form->{ARAP}_paid"} = ();
69   
70   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
71     foreach my $item (split /:/, $ref->{link}) {
72       if ($item eq $form->{ARAP}) {
73         push @{ $form->{PR}{$form->{ARAP}} }, $ref;
74       }
75       if ($item eq "$form->{ARAP}_paid") {
76         push @{ $form->{PR}{"$form->{ARAP}_paid"} }, $ref;
77       }
78     }
79   }
80   $sth->finish;
81   
82   # get currencies and closedto
83   $query = qq|SELECT curr, closedto, current_date
84               FROM defaults|;
85   ($form->{currencies}, $form->{closedto}, $form->{datepaid}) = $dbh->selectrow_array($query);
86
87   $dbh->disconnect;
88
89 }
90
91
92 sub get_openvc {
93   my ($self, $myconfig, $form) = @_;
94
95   my $dbh = $form->dbconnect($myconfig);
96
97   my $arap = ($form->{vc} eq 'customer') ? 'ar' : 'ap';
98   my $query = qq|SELECT count(*)
99                  FROM $form->{vc} ct, $arap a
100                  WHERE a.$form->{vc}_id = ct.id
101                  AND a.amount != a.paid|;
102   my ($count) = $dbh->selectrow_array($query);
103
104   my $sth;
105   my $ref;
106
107   # build selection list
108   if ($count < $myconfig->{vclimit}) {
109     $query = qq|SELECT DISTINCT ct.id, ct.name
110                 FROM $form->{vc} ct, $arap a
111                 WHERE a.$form->{vc}_id = ct.id
112                 AND a.amount != a.paid
113                 ORDER BY name|;
114     $sth = $dbh->prepare($query);
115     $sth->execute || $form->dberror($query);
116
117     while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
118       push @{ $form->{"all_$form->{vc}"} }, $ref;
119     }
120
121     $sth->finish;
122
123   }
124
125   if ($form->{ARAP} eq 'AR') {
126     $query = qq|SELECT id, description
127                 FROM department
128                 WHERE role = 'P'
129                 ORDER BY 2|;
130   } else {
131     $query = qq|SELECT id, description
132                 FROM department
133                 ORDER BY 2|;
134   }
135   $sth = $dbh->prepare($query);
136   $sth->execute || $form->dberror($query);
137
138   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
139     push @{ $form->{all_departments} }, $ref;
140   }
141   $sth->finish;
142
143   # get language codes
144   $query = qq|SELECT *
145               FROM language
146               ORDER BY 2|;
147   $sth = $dbh->prepare($query);
148   $sth->execute || $self->dberror($query);
149
150   $form->{all_languages} = ();
151   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
152     push @{ $form->{all_languages} }, $ref;
153   }
154   $sth->finish;
155
156   # get currency for first name
157   if ($form->{"all_$form->{vc}"}) {
158     $query = qq|SELECT curr FROM $form->{vc}
159                 WHERE id = $form->{"all_$form->{vc}"}->[0]->{id}|;
160     ($form->{currency}) = $dbh->selectrow_array($query);
161   }
162
163   $dbh->disconnect;
164
165 }
166
167
168 sub get_openinvoices {
169   my ($self, $myconfig, $form) = @_;
170   
171   my $null;
172   my $department_id;
173  
174   # connect to database
175   my $dbh = $form->dbconnect($myconfig);
176  
177   my $where = qq|WHERE $form->{vc}_id = $form->{"$form->{vc}_id"}
178                  AND curr = '$form->{currency}'
179                  AND amount != paid|;
180   
181   my ($buysell);
182   if ($form->{vc} eq 'customer') {
183     $buysell = "buy";
184   } else {
185     $buysell = "sell";
186   }
187   
188   ($null, $department_id) = split /--/, $form->{department};
189   if ($department_id) {
190     $where .= qq|
191                  AND department_id = $department_id|;
192   }
193
194   my $query = qq|SELECT id, invnumber, transdate, amount, paid, curr
195                  FROM $form->{arap}
196                  $where
197                  ORDER BY transdate, invnumber|;
198   my $sth = $dbh->prepare($query);
199   $sth->execute || $form->dberror($query);
200
201   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
202     # if this is a foreign currency transaction get exchangerate
203     $ref->{exchangerate} = $form->get_exchangerate($dbh, $ref->{curr}, $ref->{transdate}, $buysell) if ($form->{currency} ne $form->{defaultcurrency});
204     push @{ $form->{PR} }, $ref;
205   }
206   
207   $sth->finish;
208   $dbh->disconnect;
209
210 }
211
212
213
214 sub process_payment {
215   my ($self, $myconfig, $form) = @_;
216
217   # connect to database, turn AutoCommit off
218   my $dbh = $form->dbconnect_noauto($myconfig);
219
220   my $sth;
221   
222   my ($paymentaccno) = split /--/, $form->{account};
223   
224   # if currency ne defaultcurrency update exchangerate
225   if ($form->{currency} ne $form->{defaultcurrency}) {
226     $form->{exchangerate} = $form->parse_amount($myconfig, $form->{exchangerate});
227
228     if ($form->{vc} eq 'customer') {
229       $form->update_exchangerate($dbh, $form->{currency}, $form->{datepaid}, $form->{exchangerate}, 0);
230     } else {
231       $form->update_exchangerate($dbh, $form->{currency}, $form->{datepaid}, 0, $form->{exchangerate});
232     }
233   } else {
234     $form->{exchangerate} = 1;
235   }
236
237   my $query = qq|SELECT fxgain_accno_id, fxloss_accno_id
238                  FROM defaults|;
239   my ($fxgain_accno_id, $fxloss_accno_id) = $dbh->selectrow_array($query);
240
241   my ($buysell);
242   
243   if ($form->{vc} eq 'customer') {
244     $buysell = "buy";
245   } else {
246     $buysell = "sell";
247   }
248
249   my $ml;
250   my $where;
251   
252   if ($form->{ARAP} eq 'AR') {
253     $ml = 1;
254     $where = qq|
255                 (c.link = 'AR'
256                 OR c.link LIKE 'AR:%')
257                 |;
258   } else {
259     $ml = -1;
260     $where = qq|
261                 (c.link = 'AP'
262                 OR c.link LIKE '%:AP'
263                 OR c.link LIKE '%:AP:%')
264                 |;
265   }
266   
267   my $paymentamount = $form->parse_amount($myconfig, $form->{amount});
268   
269   my $null;
270   ($null, $form->{department_id}) = split /--/, $form->{department};
271   $form->{department_id} *= 1;
272
273
274   # query to retrieve paid amount
275   $query = qq|SELECT paid FROM $form->{arap}
276               WHERE id = ?
277               FOR UPDATE|;
278   my $pth = $dbh->prepare($query) || $form->dberror($query);
279
280   my %audittrail;
281  
282   # go through line by line
283   for my $i (1 .. $form->{rowcount}) {
284
285     $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
286     $form->{"due_$i"} = $form->parse_amount($myconfig, $form->{"due_$i"});
287     
288     if ($form->{"checked_$i"} && $form->{"paid_$i"}) {
289
290       $paymentamount -= $form->{"paid_$i"};
291       
292       # get exchangerate for original 
293       $query = qq|SELECT $buysell
294                   FROM exchangerate e
295                   JOIN $form->{arap} a ON (a.transdate = e.transdate)
296                   WHERE e.curr = '$form->{currency}'
297                   AND a.id = $form->{"id_$i"}|;
298       my ($exchangerate) = $dbh->selectrow_array($query);
299
300       $exchangerate = 1 unless $exchangerate;
301
302       $query = qq|SELECT c.id
303                   FROM chart c
304                   JOIN acc_trans a ON (a.chart_id = c.id)
305                   WHERE $where
306                   AND a.trans_id = $form->{"id_$i"}|;
307       my ($id) = $dbh->selectrow_array($query);
308      
309       $amount = $form->round_amount($form->{"paid_$i"} * $exchangerate, 2);
310       
311       # add AR/AP
312       $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate,
313                   amount)
314                   VALUES ($form->{"id_$i"}, $id, '$form->{datepaid}',
315                   $amount * $ml)|;
316       $dbh->do($query) || $form->dberror($query);
317       
318       # add payment
319       $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate,
320                   amount, source, memo)
321                   VALUES ($form->{"id_$i"},
322                          (SELECT id FROM chart
323                           WHERE accno = '$paymentaccno'),
324                   '$form->{datepaid}', $form->{"paid_$i"} * $ml * -1, |
325                   .$dbh->quote($form->{source}).qq|, |
326                   .$dbh->quote($form->{memo}).qq|)|;
327       $dbh->do($query) || $form->dberror($query);
328
329       # add exchangerate difference if currency ne defaultcurrency
330       $amount = $form->round_amount($form->{"paid_$i"} * ($form->{exchangerate} - 1), 2);
331
332       if ($amount != 0) {
333         # exchangerate difference
334         $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate,
335                     amount, cleared, fx_transaction)
336                     VALUES ($form->{"id_$i"},
337                            (SELECT id FROM chart
338                             WHERE accno = '$paymentaccno'),
339                   '$form->{datepaid}', $amount * $ml * -1, '0', '1')|;
340         $dbh->do($query) || $form->dberror($query);
341
342         # gain/loss
343         $amount = $form->round_amount($form->{"paid_$i"} * ($exchangerate - $form->{exchangerate}) * $ml * -1, 2);
344         if ($amount != 0) {
345           my $accno_id = ($amount > 0) ? $fxgain_accno_id : $fxloss_accno_id;
346           $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate,
347                       amount, cleared, fx_transaction)
348                       VALUES ($form->{"id_$i"}, $accno_id,
349                       '$form->{datepaid}', $amount, '0', '1')|;
350           $dbh->do($query) || $form->dberror($query);
351         }
352       }
353
354       $form->{"paid_$i"} = $form->round_amount($form->{"paid_$i"} * $exchangerate, 2);
355
356       $pth->execute($form->{"id_$i"}) || $form->dberror;
357       ($amount) = $pth->fetchrow_array;
358       $pth->finish;
359
360       $amount += $form->{"paid_$i"};
361                   
362       # update AR/AP transaction
363       $query = qq|UPDATE $form->{arap} set
364                   paid = $amount,
365                   datepaid = '$form->{datepaid}'
366                   WHERE id = $form->{"id_$i"}|;
367       $dbh->do($query) || $form->dberror($query);
368       
369       %audittrail = ( tablename  => $form->{arap},
370                       reference  => $form->{source},
371                       formname   => $form->{formname},
372                       action     => 'posted',
373                       id         => $form->{"id_$i"} );
374  
375       $form->audittrail($dbh, "", \%audittrail);
376       
377     }
378   }
379
380
381   # record a AR/AP with a payment
382   if ($form->round_amount($paymentamount, 2) != 0) {
383     $form->{invnumber} = "";
384     OP::overpayment("", $myconfig, $form, $dbh, $paymentamount, $ml, 1);
385   }
386
387   my $rc = $dbh->commit;
388   $dbh->disconnect;
389
390   $rc;
391
392 }
393
394
395 1;
396