Uebernahme der kompletten Version, so wie sie Philip als "Demo-Version" gezeigt hat...
[kivitendo-erp.git] / SL / CP.pm
1 #=====================================================================
2 # LX-Office ERP
3 # Copyright (C) 2004
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
6 #
7 #=====================================================================
8 # SQL-Ledger Accounting
9 # Copyright (C) 2002
10 #
11 #  Author: Dieter Simader
12 #   Email: dsimader@sql-ledger.org
13 #     Web: http://www.sql-ledger.org
14 #
15 #  Contributors:
16 #
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation; either version 2 of the License, or
20 # (at your option) any later version.
21 #
22 # This program is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 # GNU General Public License for more details.
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #======================================================================
30 #
31 # Check and receipt printing payment module backend routines
32 # Number to text conversion routines are in
33 # locale/{countrycode}/Num2text
34 #
35 #======================================================================
36
37 package CP;
38
39 sub new {
40   $main::lxdebug->enter_sub();
41
42   my ($type, $countrycode) = @_;
43
44   $self = {};
45
46   if ($countrycode) {
47     if (-f "locale/$countrycode/Num2text") {
48       require "locale/$countrycode/Num2text";
49     } else {
50       use SL::Num2text;
51     }
52   } else {
53     use SL::Num2text;
54   }
55
56   $main::lxdebug->leave_sub();
57
58   bless $self, $type;
59 }
60
61 sub paymentaccounts {
62   $main::lxdebug->enter_sub();
63
64   my ($self, $myconfig, $form) = @_;
65
66   # connect to database
67   my $dbh = $form->dbconnect($myconfig);
68
69   my $query = qq|SELECT c.accno, c.description, c.link
70                  FROM chart c
71                  WHERE c.link LIKE '%$form->{ARAP}%'
72                  ORDER BY c.accno|;
73   my $sth = $dbh->prepare($query);
74   $sth->execute || $form->dberror($query);
75
76   $form->{PR}{ $form->{ARAP} } = ();
77   $form->{PR}{"$form->{ARAP}_paid"} = ();
78
79   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
80     foreach my $item (split /:/, $ref->{link}) {
81       if ($item eq $form->{ARAP}) {
82         push @{ $form->{PR}{ $form->{ARAP} } }, $ref;
83       }
84       if ($item eq "$form->{ARAP}_paid") {
85         push @{ $form->{PR}{"$form->{ARAP}_paid"} }, $ref;
86       }
87     }
88   }
89   $sth->finish;
90
91   # get currencies and closedto
92   $query = qq|SELECT curr, closedto
93               FROM defaults|;
94   $sth = $dbh->prepare($query);
95   $sth->execute || $form->dberror($query);
96
97   ($form->{currencies}, $form->{closedto}) = $sth->fetchrow_array;
98   $sth->finish;
99
100   $dbh->disconnect;
101
102   $main::lxdebug->leave_sub();
103 }
104
105 sub get_openvc {
106   $main::lxdebug->enter_sub();
107
108   my ($self, $myconfig, $form) = @_;
109
110   my $dbh = $form->dbconnect($myconfig);
111
112   my $arap  = ($form->{vc} eq 'customer') ? 'ar' : 'ap';
113   my $query = qq|SELECT count(*)
114                  FROM $form->{vc} ct, $arap a
115                  WHERE a.$form->{vc}_id = ct.id
116                  AND a.amount != a.paid|;
117   my $sth = $dbh->prepare($query);
118   $sth->execute || $form->dberror($query);
119   my ($count) = $sth->fetchrow_array;
120   $sth->finish;
121
122   my $ref;
123
124   # build selection list
125   if ($count < $myconfig->{vclimit}) {
126     $query = qq|SELECT DISTINCT ct.id, ct.name
127                 FROM $form->{vc} ct, $arap a
128                 WHERE a.$form->{vc}_id = ct.id
129                 AND a.amount != a.paid
130                 ORDER BY ct.name|;
131     $sth = $dbh->prepare($query);
132     $sth->execute || $form->dberror($query);
133
134     while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
135       push @{ $form->{"all_$form->{vc}"} }, $ref;
136     }
137
138     $sth->finish;
139
140   }
141
142   if ($form->{ARAP} eq 'AR') {
143     $query = qq|SELECT d.id, d.description
144                 FROM department d
145                 WHERE d.role = 'P'
146                 ORDER BY 2|;
147   } else {
148     $query = qq|SELECT d.id, d.description
149                 FROM department d
150                 ORDER BY 2|;
151   }
152   $sth = $dbh->prepare($query);
153   $sth->execute || $form->dberror($query);
154
155   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
156     push @{ $form->{all_departments} }, $ref;
157   }
158   $sth->finish;
159
160   $dbh->disconnect;
161
162   $main::lxdebug->leave_sub();
163 }
164
165 sub get_openinvoices {
166   $main::lxdebug->enter_sub();
167
168   my ($self, $myconfig, $form) = @_;
169
170   # connect to database
171   my $dbh = $form->dbconnect($myconfig);
172
173   my $where = qq|WHERE a.$form->{vc}_id = $form->{"$form->{vc}_id"}
174                  AND a.curr = '$form->{currency}'
175                  AND NOT a.amount = paid|;
176
177   my ($buysell);
178   if ($form->{vc} eq 'customer') {
179     $buysell = "buy";
180   } else {
181     $buysell = "sell";
182   }
183
184   my $query =
185     qq|SELECT a.id, a.invnumber, a.transdate, a.amount, a.paid, a.curr
186                  FROM $form->{arap} a
187                  $where
188                  ORDER BY a.id|;
189   my $sth = $dbh->prepare($query);
190   $sth->execute || $form->dberror($query);
191
192   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
193
194     # if this is a foreign currency transaction get exchangerate
195     $ref->{exchangerate} =
196       $form->get_exchangerate($dbh, $ref->{curr}, $ref->{transdate}, $buysell)
197       if ($form->{currency} ne $form->{defaultcurrency});
198     push @{ $form->{PR} }, $ref;
199   }
200
201   $sth->finish;
202   $dbh->disconnect;
203
204   $main::lxdebug->leave_sub();
205 }
206
207 sub process_payment {
208   $main::lxdebug->enter_sub();
209
210   my ($self, $myconfig, $form) = @_;
211
212   # connect to database, turn AutoCommit off
213   my $dbh = $form->dbconnect_noauto($myconfig);
214
215   my ($paymentaccno) = split /--/, $form->{account};
216
217   # if currency ne defaultcurrency update exchangerate
218   if ($form->{currency} ne $form->{defaultcurrency}) {
219     $form->{exchangerate} =
220       $form->parse_amount($myconfig, $form->{exchangerate});
221
222     if ($form->{vc} eq 'customer') {
223       $form->update_exchangerate($dbh, $form->{currency}, $form->{datepaid},
224                                  $form->{exchangerate}, 0);
225     } else {
226       $form->update_exchangerate($dbh, $form->{currency}, $form->{datepaid}, 0,
227                                  $form->{exchangerate});
228     }
229   } else {
230     $form->{exchangerate} = 1;
231   }
232
233   my $query = qq|SELECT fxgain_accno_id, fxloss_accno_id
234                  FROM defaults|;
235   my $sth = $dbh->prepare($query);
236   $sth->execute || $form->dberror($query);
237
238   my ($fxgain_accno_id, $fxloss_accno_id) = $sth->fetchrow_array;
239   $sth->finish;
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   $paymentamount = $form->{amount};
268
269   #  $paymentamount = $form->{amount};
270   my $null;
271   ($null, $form->{department_id}) = split /--/, $form->{department};
272   $form->{department_id} *= 1;
273
274   # query to retrieve paid amount
275   $query = qq|SELECT a.paid FROM ar a
276               WHERE a.id = ?
277               FOR UPDATE|;
278   my $pth = $dbh->prepare($query) || $form->dberror($query);
279
280   # go through line by line
281   for my $i (1 .. $form->{rowcount}) {
282
283     $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
284     $form->{"due_$i"}  = $form->parse_amount($myconfig, $form->{"due_$i"});
285
286     if ($form->{"checked_$i"} && $form->{"paid_$i"}) {
287       $paymentamount =
288         (($paymentamount * 1000) - ($form->{"paid_$i"} * 1000)) / 1000;
289
290       # get exchangerate for original
291       $query = qq|SELECT $buysell
292                   FROM exchangerate e
293                   JOIN $form->{arap} a ON (a.transdate = e.transdate)
294                   WHERE e.curr = '$form->{currency}'
295                   AND a.id = $form->{"id_$i"}|;
296       $sth = $dbh->prepare($query);
297       $sth->execute || $form->dberror($query);
298
299       my ($exchangerate) = $sth->fetchrow_array;
300       $sth->finish;
301
302       $exchangerate = 1 unless $exchangerate;
303
304       $query = qq|SELECT c.id
305                   FROM chart c
306                   JOIN acc_trans a ON (a.chart_id = c.id)
307                   WHERE $where
308                   AND a.trans_id = $form->{"id_$i"}|;
309       $sth = $dbh->prepare($query);
310       $sth->execute || $form->dberror($query);
311
312       my ($id) = $sth->fetchrow_array;
313       $sth->finish;
314
315       $amount = $form->round_amount($form->{"paid_$i"} * $exchangerate, 2);
316
317       # add AR/AP
318       $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate,
319                   amount)
320                   VALUES ($form->{"id_$i"}, $id, '$form->{datepaid}',
321                   $amount * $ml)|;
322       $dbh->do($query) || $form->dberror($query);
323
324       # add payment
325       $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate,
326                   amount, source, memo)
327                   VALUES ($form->{"id_$i"},
328                          (SELECT c.id FROM chart c
329                           WHERE c.accno = '$paymentaccno'),
330                   '$form->{datepaid}', $form->{"paid_$i"} * $ml * -1,
331                   '$form->{source}', '$form->{memo}')|;
332       $dbh->do($query) || $form->dberror($query);
333
334       # add exchangerate difference if currency ne defaultcurrency
335       $amount =
336         $form->round_amount($form->{"paid_$i"} * ($form->{exchangerate} - 1),
337                             2);
338       if ($amount != 0) {
339
340         # exchangerate difference
341         $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate,
342                     amount, cleared, fx_transaction)
343                     VALUES ($form->{"id_$i"},
344                            (SELECT c.id FROM chart c
345                             WHERE c.accno = '$paymentaccno'),
346                   '$form->{datepaid}', $amount * $ml * -1, '0', '1')|;
347         $dbh->do($query) || $form->dberror($query);
348
349         # gain/loss
350
351         $amount =
352           $form->round_amount(
353                   $form->{"paid_$i"} * ($exchangerate - $form->{exchangerate}),
354                   2);
355         if ($amount != 0) {
356           my $accno_id = ($amount < 0) ? $fxgain_accno_id : $fxloss_accno_id;
357           $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate,
358                       amount, cleared, fx_transaction)
359                       VALUES ($form->{"id_$i"}, $accno_id,
360                       '$form->{datepaid}', $amount * $ml * -1, '0', '1')|;
361           $dbh->do($query) || $form->dberror($query);
362         }
363       }
364
365       $form->{"paid_$i"} =
366         $form->round_amount($form->{"paid_$i"} * $exchangerate, 2);
367
368       $pth->execute($form->{"id_$i"}) || $form->dberror;
369       ($amount) = $pth->fetchrow_array;
370       $pth->finish;
371
372       $amount += $form->{"paid_$i"};
373
374       # update AR/AP transaction
375       $query = qq|UPDATE $form->{arap} set
376                   paid = $amount,
377                   datepaid = '$form->{datepaid}'
378                   WHERE id = $form->{"id_$i"}|;
379       $dbh->do($query) || $form->dberror($query);
380     }
381   }
382
383   # record a AR/AP with a payment
384   if ($form->round_amount($paymentamount, 2) > 0) {
385     $form->{invnumber} = "";
386     OP::overpayment("", $myconfig, $form, $dbh, $paymentamount, $ml, 1);
387   }
388
389   if ($form->round_amount($paymentamount, 2) < 0) {
390     $dbh->rollback;
391     $rc = 0;
392   }
393   if ($form->round_amount($paymentamount, 2) == 0) {
394     $rc = $dbh->commit;
395   }
396
397   $dbh->disconnect;
398
399   $main::lxdebug->leave_sub();
400
401   return $rc;
402 }
403
404 1;
405