This commit was generated by cvs2svn to compensate for changes in r3880,
[freeside.git] / sql-ledger / sql-ledger / SL / IR.pm
1 #=====================================================================
2 # SQL-Ledger Accounting
3 # Copyright (C) 2000
4 #
5 #  Author: Dieter Simader
6 #   Email: dsimader@sql-ledger.org
7 #     Web: http://www.sql-ledger.org
8 #
9 #  Contributors: Jim Rawlings <jim@your-dba.com>
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 # Inventory received module
26 #
27 #======================================================================
28
29 package IR;
30
31
32 sub post_invoice {
33   my ($self, $myconfig, $form) = @_;
34   
35   # connect to database, turn off autocommit
36   my $dbh = $form->dbconnect_noauto($myconfig);
37
38   my $query;
39   my $sth;
40   my $null;
41   my $project_id;
42   my $exchangerate = 0;
43   my $allocated;
44   my $taxrate;
45   my $taxamount;
46   my $taxdiff;
47   my $item;
48
49   if ($form->{id}) {
50
51     &reverse_invoice($dbh, $form);
52
53   } else {
54     my $uid = time;
55     $uid .= $form->{login};
56
57     $query = qq|INSERT INTO ap (invnumber, employee_id)
58                 VALUES ('$uid', (SELECT id FROM employee
59                                  WHERE login = '$form->{login}'))|;
60     $dbh->do($query) || $form->dberror($query);
61     
62     $query = qq|SELECT id FROM ap
63                 WHERE invnumber = '$uid'|;
64     $sth = $dbh->prepare($query);
65     $sth->execute || $form->dberror($query);
66
67     ($form->{id}) = $sth->fetchrow_array;
68     $sth->finish;
69
70   }
71
72   my ($amount, $linetotal, $lastinventoryaccno, $lastexpenseaccno);
73   my ($netamount, $invoicediff, $expensediff) = (0, 0, 0);
74
75   if ($form->{currency} eq $form->{defaultcurrency}) {
76     $form->{exchangerate} = 1;
77   } else {
78     $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'sell');
79   }
80   
81   $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate});
82
83   
84   for my $i (1 .. $form->{rowcount}) {
85     $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
86     
87     if ($form->{"qty_$i"} != 0) {
88
89       # project
90       $project_id = 'NULL';
91       if ($form->{"projectnumber_$i"}) {
92         ($null, $project_id) = split /--/, $form->{"projectnumber_$i"};
93       }
94  
95       # undo discount formatting
96       $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
97       
98       @taxaccounts = split / /, $form->{"taxaccounts_$i"};
99       $taxdiff = 0;
100       $allocated = 0;
101       $taxrate = 0;
102       
103       # keep entered selling price
104       my $fxsellprice = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
105           
106       my ($dec) = ($fxsellprice =~ /\.(\d+)/);
107       $dec = length $dec;
108       my $decimalplaces = ($dec > 2) ? $dec : 2;
109       
110       # deduct discount
111       my $discount = $form->round_amount($fxsellprice * $form->{"discount_$i"}, $decimalplaces);
112       $form->{"sellprice_$i"} = $fxsellprice - $discount;
113       
114       map { $taxrate += $form->{"${_}_rate"} } @taxaccounts;
115
116       if ($form->{"inventory_accno_$i"}) {
117
118         $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2);
119         
120         if ($form->{taxincluded}) {
121           $taxamount = $linetotal * ($taxrate / (1 + $taxrate));
122           $form->{"sellprice_$i"} = $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
123         } else {
124           $taxamount = $linetotal * $taxrate;
125         }
126
127         $netamount += $linetotal;
128
129         if (@taxaccounts && $form->round_amount($taxamount, 2) == 0) {
130           if ($form->{taxincluded}) {
131             foreach $item (@taxaccounts) {
132               $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2);
133               $taxdiff += $taxamount;
134               $form->{amount}{$form->{id}}{$item} -= $taxamount;
135             }
136             $form->{amount}{$form->{id}}{$taxaccounts[0]} += $taxdiff;
137           } else {
138             map { $form->{amount}{$form->{id}}{$_} -= $linetotal * $form->{"${_}_rate"} } @taxaccounts;
139           }
140         } else {
141             map { $form->{amount}{$form->{id}}{$_} -= $taxamount * $form->{"${_}_rate"} / $taxrate } @taxaccounts;
142         }
143         
144
145         # add purchase to inventory, this one is without the tax!
146         $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate};
147         $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2) * $form->{exchangerate};
148         $linetotal = $form->round_amount($linetotal, 2);
149
150         # this is the difference for the inventory
151         $invoicediff += ($amount - $linetotal);
152         
153         $form->{amount}{$form->{id}}{$form->{"inventory_accno_$i"}} -= $linetotal;
154
155         # adjust and round sellprice
156         $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate}, $decimalplaces);
157
158         
159         # update parts table
160         $form->update_balance($dbh,
161                               "parts",
162                               "onhand",
163                               qq|id = $form->{"id_$i"}|,
164                               $form->{"qty_$i"}) unless $form->{shipped};
165
166
167         # check if we sold the item already and
168         # make an entry for the expense and inventory
169         $query = qq|SELECT i.id, i.qty, i.allocated, i.trans_id,
170                     p.inventory_accno_id, p.expense_accno_id, a.transdate
171                     FROM invoice i, ar a, parts p
172                     WHERE i.parts_id = p.id
173                     AND i.parts_id = $form->{"id_$i"}
174                     AND (i.qty + i.allocated) > 0
175                     AND i.trans_id = a.id
176                     ORDER BY transdate|;
177         $sth = $dbh->prepare($query);
178         $sth->execute || $form->dberror($query);
179
180
181         my $totalqty = $form->{"qty_$i"};
182         
183         while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
184           
185           my $qty = $ref->{qty} + $ref->{allocated};
186           
187           if (($qty - $totalqty) > 0) {
188             $qty = $totalqty;
189           }
190
191
192           $linetotal = $form->round_amount($form->{"sellprice_$i"} * $qty, 2);
193
194           if ($ref->{allocated} < 0) {
195             # we have an entry for it already, adjust amount
196             $form->update_balance($dbh,
197                                   "acc_trans",
198                                   "amount",
199                                   qq|trans_id = $ref->{trans_id} AND chart_id = $ref->{inventory_accno_id} AND transdate = '$ref->{transdate}'|,
200                                   $linetotal);
201
202             $form->update_balance($dbh,
203                                   "acc_trans",
204                                   "amount",
205                                   qq|trans_id = $ref->{trans_id} AND chart_id = $ref->{expense_accno_id} AND transdate = '$ref->{transdate}'|,
206                                   $linetotal * -1);
207
208           } else {
209             # add entry for inventory, this one is for the sold item
210             if ($linetotal != 0) {
211               $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, 
212                           transdate)
213                           VALUES ($ref->{trans_id}, $ref->{inventory_accno_id},
214                           $linetotal, '$ref->{transdate}')|;
215               $dbh->do($query) || $form->dberror($query);
216
217               # add expense
218               $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, 
219                           transdate)
220                           VALUES ($ref->{trans_id}, $ref->{expense_accno_id},
221                           |. ($linetotal * -1) .qq|, '$ref->{transdate}')|;
222               $dbh->do($query) || $form->dberror($query);
223             }
224           }
225         
226           # update allocated for sold item
227           $form->update_balance($dbh,
228                                 "invoice",
229                                 "allocated",
230                                 qq|id = $ref->{id}|,
231                                 $qty * -1);
232         
233           $allocated += $qty;
234
235           last if (($totalqty -= $qty) <= 0);
236         }
237
238         $sth->finish;
239
240         $lastinventoryaccno = $form->{"inventory_accno_$i"};
241         
242       } else {
243         
244         $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2);
245         
246         if ($form->{taxincluded}) {
247           $taxamount = $linetotal * ($taxrate / (1 + $taxrate));
248           
249           $form->{"sellprice_$i"} = $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
250         } else {
251           $taxamount = $linetotal * $taxrate;
252         }
253         
254         $netamount += $linetotal;
255         
256         if (@taxaccounts && $form->round_amount($taxamount, 2) == 0) {
257           if ($form->{taxincluded}) {
258             foreach $item (@taxaccounts) {
259               $taxamount = $form->round_amount($linetotal * $form->{"${item}_rate"} / (1 + abs($form->{"${item}_rate"})), 2);
260               $totaltax += $taxamount;
261               $taxdiff += $taxamount;
262               $form->{amount}{$form->{id}}{$item} -= $taxamount;
263             }
264             $form->{amount}{$form->{id}}{$taxaccounts[0]} += $taxdiff;
265           } else {
266             map { $form->{amount}{$form->{id}}{$_} -= $linetotal * $form->{"${_}_rate"} } @taxaccounts;
267           }
268         } else {
269             map { $form->{amount}{$form->{id}}{$_} -= $taxamount * $form->{"${_}_rate"} / $taxrate } @taxaccounts;
270         }
271         
272
273         $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate};
274         $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2) * $form->{exchangerate};
275         $linetotal = $form->round_amount($linetotal, 2);
276
277         # this is the difference for expense
278         $expensediff += ($amount - $linetotal);
279         
280         # add amount to expense
281         $form->{amount}{$form->{id}}{$form->{"expense_accno_$i"}} -= $linetotal;
282
283         $lastexpenseaccno = $form->{"expense_accno_$i"};
284
285         # adjust and round sellprice
286         $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate}, $decimalplaces);
287         
288       }
289
290      
291       # save detail record in invoice table
292       $query = qq|INSERT INTO invoice (trans_id, parts_id, description, qty,
293                   sellprice, fxsellprice, discount, allocated,
294                   unit, deliverydate, project_id, serialnumber)
295                   VALUES ($form->{id}, $form->{"id_$i"}, |
296                   .$dbh->quote($form->{"description_$i"}).qq|, |
297                   .($form->{"qty_$i"} * -1) .qq|,
298                   $form->{"sellprice_$i"}, $fxsellprice,
299                   $form->{"discount_$i"}, $allocated, |
300                   .$dbh->quote($form->{"unit_$i"}).qq|, |
301                   .$form->dbquote($form->{"deliverydate_$i"}, SQL_DATE).qq|,
302                   $project_id, |
303                   .$dbh->quote($form->{"serialnumber_$i"}).qq|)|;
304       $dbh->do($query) || $form->dberror($query);
305
306     }
307   }
308
309
310   $form->{datepaid} = $form->{transdate};
311
312   # all amounts are in natural state, netamount includes the taxes
313   # if tax is included, netamount is rounded to 2 decimal places,
314   
315   # total payments
316   for my $i (1 .. $form->{paidaccounts}) {
317     $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
318     $form->{paid} += $form->{"paid_$i"};
319     $form->{datepaid} = $form->{"datepaid_$i"} if ($form->{"datepaid_$i"}); 
320   }
321
322   my ($tax, $paiddiff) = (0, 0);
323
324   $netamount = $form->round_amount($netamount, 2);
325   
326   # figure out rounding errors for amount paid and total amount
327   if ($form->{taxincluded}) {
328
329     $amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
330     $paiddiff = $amount - $netamount * $form->{exchangerate};
331     $netamount = $amount;
332
333     foreach $item (split / /, $form->{taxaccounts}) {
334       $amount = $form->{amount}{$form->{id}}{$item} * $form->{exchangerate};
335       $form->{amount}{$form->{id}}{$item} = $form->round_amount($amount, 2);
336       $amount = $form->{amount}{$form->{id}}{$item} * -1;
337       $tax += $amount;
338       $netamount -= $amount;
339     }
340
341     $invoicediff += $paiddiff;
342     $expensediff += $paiddiff;
343
344     ######## this only applies to tax included
345     if ($lastinventoryaccno) {
346       $form->{amount}{$form->{id}}{$lastinventoryaccno} -= $invoicediff;
347     }
348     if ($lastexpenseaccno) {
349       $form->{amount}{$form->{id}}{$lastexpenseaccno} -= $expensediff;
350     }
351
352   } else {
353     $amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
354     $paiddiff = $amount - $netamount * $form->{exchangerate};
355     $netamount = $amount;
356     foreach my $item (split / /, $form->{taxaccounts}) {
357       $form->{amount}{$form->{id}}{$item} = $form->round_amount($form->{amount}{$form->{id}}{$item}, 2);
358       $amount = $form->round_amount($form->{amount}{$form->{id}}{$item} * $form->{exchangerate} * -1, 2);
359       $paiddiff += $amount - $form->{amount}{$form->{id}}{$item} * $form->{exchangerate} * -1;
360       $form->{amount}{$form->{id}}{$item} = $form->round_amount($amount * -1, 2);
361       $amount = $form->{amount}{$form->{id}}{$item} * -1;
362       $tax += $amount;
363     }
364   }
365
366
367   $form->{amount}{$form->{id}}{$form->{AP}} = $netamount + $tax;
368
369   if ($form->{paid} != 0) {
370     $form->{paid} = $form->round_amount($form->{paid} * $form->{exchangerate} + $paiddiff, 2);
371   }
372
373
374   # update exchangerate
375   if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
376     $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, 0, $form->{exchangerate});
377   }
378   
379   # record acc_trans transactions
380   foreach my $trans_id (keys %{$form->{amount}}) {
381     foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
382       if (($form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2)) != 0) {
383         $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, 
384                     transdate)
385                     VALUES ($trans_id, (SELECT id FROM chart
386                                          WHERE accno = '$accno'),
387                     $form->{amount}{$trans_id}{$accno},
388                     '$form->{transdate}')|;
389         $dbh->do($query) || $form->dberror($query);
390       }
391     }
392   }
393
394   # deduct payment differences from paiddiff
395   for my $i (1 .. $form->{paidaccounts}) {
396     if ($form->{"paid_$i"} != 0) {
397       $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate}, 2);
398       $paiddiff -= $amount - $form->{"paid_$i"} * $form->{exchangerate};
399     }
400   }
401
402   # force AP entry if 0
403   $form->{amount}{$form->{id}}{$form->{AP}} = $form->{paid} if ($form->{amount}{$form->{id}}{$form->{AP}} == 0);
404   
405   # record payments and offsetting AP
406   for my $i (1 .. $form->{paidaccounts}) {
407
408     if ($form->{"paid_$i"} != 0) {
409       my ($accno) = split /--/, $form->{"AP_paid_$i"};
410       $form->{"datepaid_$i"} = $form->{transdate} unless ($form->{"datepaid_$i"});
411       $form->{datepaid} = $form->{"datepaid_$i"};
412       
413       $amount = ($form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $paiddiff, 2)) * -1;
414       
415       # record AP
416       
417       if ($form->{amount}{$form->{id}}{$form->{AP}} != 0) {
418         $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
419                     transdate)
420                     VALUES ($form->{id}, (SELECT id FROM chart
421                                         WHERE accno = '$form->{AP}'),
422                     $amount, '$form->{"datepaid_$i"}')|;
423         $dbh->do($query) || $form->dberror($query);
424       }
425
426       # record payment
427       
428       $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
429                   source, memo)
430                   VALUES ($form->{id}, (SELECT id FROM chart
431                                       WHERE accno = '$accno'),
432                   $form->{"paid_$i"}, '$form->{"datepaid_$i"}', |
433                   .$dbh->quote($form->{"source_$i"}).qq|, |
434                   .$dbh->quote($form->{"memo_$i"}).qq|)|;
435       $dbh->do($query) || $form->dberror($query);
436
437
438       $exchangerate = 0;
439
440       if ($form->{currency} eq $form->{defaultcurrency}) {
441         $form->{"exchangerate_$i"} = 1;
442       } else {
443         $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'sell');
444
445         $form->{"exchangerate_$i"} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
446       }
447       
448
449       # exchangerate difference
450       $form->{fx}{$accno}{$form->{"datepaid_$i"}} += $form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $paiddiff;
451       
452
453       # gain/loss
454       $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate},2) - $form->round_amount($form->{"paid_$i"} * $form->{"exchangerate_$i"},2);
455       if ($amount > 0) {
456         $form->{fx}{$form->{fxgain_accno}}{$form->{"datepaid_$i"}} += $amount;
457       } else {
458         $form->{fx}{$form->{fxloss_accno}}{$form->{"datepaid_$i"}} += $amount;
459       }
460       
461       $paiddiff = 0;
462
463       # update exchange rate
464       if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
465         $form->update_exchangerate($dbh, $form->{currency}, $form->{"datepaid_$i"}, 0, $form->{"exchangerate_$i"});
466       }
467     }
468   }
469
470   # record exchange rate differences and gains/losses
471   foreach my $accno (keys %{$form->{fx}}) {
472     foreach my $transdate (keys %{ $form->{fx}{$accno} }) {
473       if (($form->{fx}{$accno}{$transdate} = $form->round_amount($form->{fx}{$accno}{$transdate}, 2)) != 0) {
474
475         $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
476                     transdate, cleared, fx_transaction)
477                     VALUES ($form->{id}, (SELECT id FROM chart
478                                         WHERE accno = '$accno'),
479                     $form->{fx}{$accno}{$transdate}, '$transdate', '0', '1')|;
480         $dbh->do($query) || $form->dberror($query);
481       }
482     }
483   }
484
485
486   $amount = $netamount + $tax;
487
488   # set values which could be empty
489   $form->{taxincluded} *= 1;
490   
491   ($null, $form->{department_id}) = split(/--/, $form->{department});
492   $form->{department_id} *= 1;
493
494   # save AP record
495   $query = qq|UPDATE ap set
496               invnumber = |.$dbh->quote($form->{invnumber}).qq|,
497               ordnumber = |.$dbh->quote($form->{ordnumber}).qq|,
498               quonumber = |.$dbh->quote($form->{quonumber}).qq|,
499               transdate = '$form->{transdate}',
500               vendor_id = $form->{vendor_id},
501               amount = $amount,
502               netamount = $netamount,
503               paid = $form->{paid},
504               datepaid = |.$form->dbquote($form->{datepaid}, SQL_DATE).qq|,
505               duedate = |.$form->dbquote($form->{duedate}, SQL_DATE).qq|,
506               invoice = '1',
507               taxincluded = '$form->{taxincluded}',
508               notes = |.$dbh->quote($form->{notes}).qq|,
509               intnotes = |.$dbh->quote($form->{intnotes}).qq|,
510               curr = '$form->{currency}',
511               department_id = $form->{department_id},
512               language_code = '$form->{language_code}'
513               WHERE id = $form->{id}|;
514   $dbh->do($query) || $form->dberror($query);
515
516   # add shipto
517   $form->{name} = $form->{vendor};
518   $form->{name} =~ s/--$form->{vendor_id}//;
519   $form->add_shipto($dbh, $form->{id});
520   
521   my %audittrail = ( tablename  => 'ap',
522                      reference  => $form->{invnumber},
523                      formname   => $form->{type},
524                      action     => 'posted',
525                      id         => $form->{id} );
526  
527   $form->audittrail($dbh, "", \%audittrail);
528  
529   my $rc = $dbh->commit;
530   $dbh->disconnect;
531   $rc;
532   
533 }
534
535
536
537 sub reverse_invoice {
538   my ($dbh, $form) = @_;
539   
540   # reverse inventory items
541   my $query = qq|SELECT i.parts_id, p.inventory_accno_id, p.expense_accno_id,
542                  i.qty, i.allocated, i.sellprice
543                  FROM invoice i, parts p
544                  WHERE i.parts_id = p.id
545                  AND i.trans_id = $form->{id}|;
546   my $sth = $dbh->prepare($query);
547   $sth->execute || $form->dberror($query);
548
549   my $netamount = 0;
550   
551   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
552     $netamount += $form->round_amount($ref->{sellprice} * $ref->{qty} * -1, 2);
553
554     if ($ref->{inventory_accno_id}) {
555       # update onhand
556       $form->update_balance($dbh,
557                             "parts",
558                             "onhand",
559                             qq|id = $ref->{parts_id}|,
560                             $ref->{qty});
561  
562       # if $ref->{allocated} > 0 than we sold that many items
563       if ($ref->{allocated} > 0) {
564
565         # get references for sold items
566         $query = qq|SELECT i.id, i.trans_id, i.allocated, a.transdate
567                     FROM invoice i, ar a
568                     WHERE i.parts_id = $ref->{parts_id}
569                     AND i.allocated < 0
570                     AND i.trans_id = a.id
571                     ORDER BY transdate DESC|;
572         my $sth = $dbh->prepare($query);
573         $sth->execute || $form->dberror($query);
574
575         while (my $pthref = $sth->fetchrow_hashref(NAME_lc)) {
576           my $qty = $ref->{allocated};
577           
578           if (($ref->{allocated} + $pthref->{allocated}) > 0) {
579             $qty = $pthref->{allocated} * -1;
580           }
581
582           my $amount = $form->round_amount($ref->{sellprice} * $qty, 2);
583
584           #adjust allocated
585           $form->update_balance($dbh,
586                                 "invoice",
587                                 "allocated",
588                                 qq|id = $pthref->{id}|,
589                                 $qty);
590           
591           $form->update_balance($dbh,
592                                 "acc_trans",
593                                 "amount",
594                                 qq|trans_id = $pthref->{trans_id} AND chart_id = $ref->{expense_accno_id} AND transdate = '$pthref->{transdate}'|,
595                                 $amount);
596                       
597           $form->update_balance($dbh,
598                                 "acc_trans",
599                                 "amount",
600                                 qq|trans_id = $pthref->{trans_id} AND chart_id = $ref->{inventory_accno_id} AND transdate = '$pthref->{transdate}'|,
601                                 $amount * -1);
602
603           $query = qq|DELETE FROM acc_trans
604                       WHERE trans_id = $pthref->{trans_id}
605                       AND amount = 0|;
606           $dbh->do($query) || $form->dberror($query);
607           
608           last if (($ref->{allocated} -= $qty) <= 0);
609         }
610         $sth->finish;
611       }
612     }
613   }
614   $sth->finish;
615   
616   # delete acc_trans
617   $query = qq|DELETE FROM acc_trans
618               WHERE trans_id = $form->{id}|;
619   $dbh->do($query) || $form->dberror($query);
620
621   # delete invoice entries
622   $query = qq|DELETE FROM invoice
623               WHERE trans_id = $form->{id}|;
624   $dbh->do($query) || $form->dberror($query);
625
626   $query = qq|DELETE FROM shipto
627               WHERE trans_id = $form->{id}|;
628   $dbh->do($query) || $form->dberror($query);
629   
630
631
632
633
634 sub delete_invoice {
635   my ($self, $myconfig, $form) = @_;
636
637   # connect to database
638   my $dbh = $form->dbconnect_noauto($myconfig);
639   
640   my %audittrail = ( tablename  => 'ap',
641                      reference  => $form->{invnumber},
642                      formname   => $form->{type},
643                      action     => 'deleted',
644                      id         => $form->{id} );
645  
646   $form->audittrail($dbh, "", \%audittrail);
647
648   &reverse_invoice($dbh, $form);
649   
650   # delete AP record
651   my $query = qq|DELETE FROM ap
652                  WHERE id = $form->{id}|;
653   $dbh->do($query) || $form->dberror($query);
654
655   my $rc = $dbh->commit;
656   $dbh->disconnect;
657
658   $rc;
659   
660 }
661
662
663
664 sub retrieve_invoice {
665   my ($self, $myconfig, $form) = @_;
666   
667   # connect to database
668   my $dbh = $form->dbconnect_noauto($myconfig);
669
670   my $query;
671
672   if ($form->{id}) {
673     # get default accounts and last invoice number
674     $query = qq|SELECT (SELECT c.accno FROM chart c
675                         WHERE d.inventory_accno_id = c.id) AS inventory_accno,
676                        (SELECT c.accno FROM chart c
677                         WHERE d.income_accno_id = c.id) AS income_accno,
678                        (SELECT c.accno FROM chart c
679                         WHERE d.expense_accno_id = c.id) AS expense_accno,
680                        (SELECT c.accno FROM chart c
681                         WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
682                        (SELECT c.accno FROM chart c
683                         WHERE d.fxloss_accno_id = c.id) AS fxloss_accno,
684                 d.curr AS currencies
685                 FROM defaults d|;
686   } else {
687     $query = qq|SELECT (SELECT c.accno FROM chart c
688                         WHERE d.inventory_accno_id = c.id) AS inventory_accno,
689                        (SELECT c.accno FROM chart c
690                         WHERE d.income_accno_id = c.id) AS income_accno,
691                        (SELECT c.accno FROM chart c
692                         WHERE d.expense_accno_id = c.id) AS expense_accno,
693                        (SELECT c.accno FROM chart c
694                         WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
695                        (SELECT c.accno FROM chart c
696                         WHERE d.fxloss_accno_id = c.id) AS fxloss_accno,
697                 d.curr AS currencies,
698                 current_date AS transdate
699                 FROM defaults d|;
700   }
701   my $sth = $dbh->prepare($query);
702   $sth->execute || $form->dberror($query);
703
704   my $ref = $sth->fetchrow_hashref(NAME_lc);
705   map { $form->{$_} = $ref->{$_} } keys %$ref;
706   $sth->finish;
707
708
709   if ($form->{id}) {
710     
711     # retrieve invoice
712     $query = qq|SELECT a.invnumber, a.transdate, a.duedate,
713                 a.ordnumber, a.quonumber, a.paid, a.taxincluded, a.notes,
714                 a.intnotes, a.curr AS currency, a.vendor_id, a.language_code
715                 FROM ap a
716                 WHERE id = $form->{id}|;
717     $sth = $dbh->prepare($query);
718     $sth->execute || $form->dberror($query);
719
720     $ref = $sth->fetchrow_hashref(NAME_lc);
721     map { $form->{$_} = $ref->{$_} } keys %$ref;
722     $sth->finish;
723
724     # get shipto
725     $query = qq|SELECT * FROM shipto
726                 WHERE trans_id = $form->{id}|;
727     $sth = $dbh->prepare($query);
728     $sth->execute || $form->dberror($query);
729
730     $ref = $sth->fetchrow_hashref(NAME_lc);
731     map { $form->{$_} = $ref->{$_} } keys %$ref;
732     $sth->finish;
733     
734     # retrieve individual items
735     $query = qq|SELECT c1.accno AS inventory_accno,
736                        c2.accno AS income_accno,
737                        c3.accno AS expense_accno,
738                 p.partnumber, i.description, i.qty, i.fxsellprice, i.sellprice,
739                 i.parts_id AS id, i.unit, p.bin, i.deliverydate,
740                 pr.projectnumber,
741                 i.project_id, i.serialnumber, i.discount,
742                 pg.partsgroup, p.partsgroup_id, p.partnumber AS sku,
743                 t.description AS partsgrouptranslation
744                 FROM invoice i
745                 JOIN parts p ON (i.parts_id = p.id)
746                 LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id)
747                 LEFT JOIN chart c2 ON (p.income_accno_id = c2.id)
748                 LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id)
749                 LEFT JOIN project pr ON (i.project_id = pr.id)
750                 LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
751                 LEFT JOIN translation t ON (t.trans_id = p.partsgroup_id AND t.language_code = '$form->{language_code}')
752                 WHERE i.trans_id = $form->{id}
753                 ORDER BY i.id|;
754     $sth = $dbh->prepare($query);
755     $sth->execute || $form->dberror($query);
756
757     # exchangerate defaults
758     &exchangerate_defaults($dbh, $form);
759
760     # price matrix and vendor partnumber
761     $query = qq|SELECT partnumber
762                 FROM partsvendor
763                 WHERE parts_id = ?
764                 AND vendor_id = $form->{vendor_id}|;
765     my $pmh = $dbh->prepare($query) || $form->dberror($query);
766
767     # tax rates for part
768     $query = qq|SELECT c.accno
769                 FROM chart c
770                 JOIN partstax pt ON (pt.chart_id = c.id)
771                 WHERE pt.parts_id = ?|;
772     my $tth = $dbh->prepare($query);
773
774     my $ptref;
775     my $taxrate;
776
777     while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
778
779       ($decimalplaces) = ($ref->{fxsellprice} =~ /\.(\d+)/);
780       $decimalplaces = length $decimalplaces;
781       $decimalplaces = 2 unless $decimalplaces;
782
783       $tth->execute($ref->{id});
784       $ref->{taxaccounts} = "";
785       $taxrate = 0;
786       
787       while ($ptref = $tth->fetchrow_hashref(NAME_lc)) {
788         $ref->{taxaccounts} .= "$ptref->{accno} ";
789         $taxrate += $form->{"$ptref->{accno}_rate"};
790       }
791       
792       $tth->finish;
793       chop $ref->{taxaccounts};
794
795       # price matrix
796       $ref->{sellprice} = $form->round_amount($ref->{fxsellprice} * $form->{$form->{currency}}, 2);
797       &price_matrix($pmh, $ref, $decimalplaces, $form);
798
799       $ref->{sellprice} = $ref->{fxsellprice};
800       $ref->{qty} *= -1;
801
802       $ref->{partsgroup} = $ref->{partsgrouptranslation} if $ref->{partsgrouptranslation};
803       
804       push @{ $form->{invoice_details} }, $ref;
805       
806     }
807     
808     $sth->finish;
809     
810   }
811   
812   
813   my $rc = $dbh->commit;
814   $dbh->disconnect;
815   
816   $rc;
817   
818 }
819
820
821
822 sub get_vendor {
823   my ($self, $myconfig, $form) = @_;
824   
825   # connect to database
826   my $dbh = $form->dbconnect($myconfig);
827   
828   my $dateformat = $myconfig->{dateformat};
829   if ($myconfig->{dateformat} !~ /^y/) {
830     my @a = split /\W/, $form->{transdate};
831     $dateformat .= "yy" if (length $a[2] > 2);
832   }
833
834   if ($form->{transdate} !~ /\W/) {
835     $dateformat = 'yyyymmdd';
836   }
837
838   my $duedate;
839   
840   if ($myconfig->{dbdriver} eq 'DB2') {
841     $duedate = ($form->{transdate}) ? "date('$form->{transdate}') + v.terms DAYS" : "current_date + v.terms DAYS";
842   } else {
843     $duedate = ($form->{transdate}) ? "to_date('$form->{transdate}', '$dateformat') + v.terms" : "current_date + v.terms";
844   }
845
846   $form->{vendor_id} *= 1;
847   # get vendor
848   my $query = qq|SELECT v.name AS vendor, v.creditlimit, v.terms,
849                  v.email, v.cc, v.bcc, v.taxincluded,
850                  v.address1, v.address2, v.city, v.state,
851                  v.zipcode, v.country, v.curr AS currency, v.language_code,
852                  $duedate AS duedate, v.notes AS intnotes,
853                  e.name AS employee, e.id AS employee_id
854                  FROM vendor v
855                  LEFT JOIN employee e ON (e.id = v.employee_id)
856                  WHERE v.id = $form->{vendor_id}|;
857   my $sth = $dbh->prepare($query);
858   $sth->execute || $form->dberror($query);
859
860   $ref = $sth->fetchrow_hashref(NAME_lc);
861   
862   if ($form->{id}) {
863     map { delete $ref->{$_} } qw(currency taxincluded employee employee_id intnotes);
864   }
865   
866   map { $form->{$_} = $ref->{$_} } keys %$ref;
867   $sth->finish;
868
869   # if no currency use defaultcurrency
870   $form->{currency} = ($form->{currency}) ? $form->{currency} : $form->{defaultcurrency};
871   
872   $form->{exchangerate} = 0 if $form->{currency} eq $form->{defaultcurrency};
873   if ($form->{transdate} && ($form->{currency} ne $form->{defaultcurrency})) {
874     $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{transdate}, "sell"); 
875   }
876   $form->{forex} = $form->{exchangerate};
877
878   # if no employee, default to login
879   ($form->{employee}, $form->{employee_id}) = $form->get_employee($dbh) unless $form->{employee_id};
880   
881   $form->{creditremaining} = $form->{creditlimit};
882   $query = qq|SELECT SUM(amount - paid)
883               FROM ap
884               WHERE vendor_id = $form->{vendor_id}|;
885   $sth = $dbh->prepare($query);
886   $sth->execute || $form->dberror($query);
887
888   ($form->{creditremaining}) -= $sth->fetchrow_array;
889
890   $sth->finish;
891   
892   $query = qq|SELECT o.amount,
893                 (SELECT e.sell FROM exchangerate e
894                  WHERE e.curr = o.curr
895                  AND e.transdate = o.transdate)
896               FROM oe o
897               WHERE o.vendor_id = $form->{vendor_id}
898               AND o.quotation = '0'
899               AND o.closed = '0'|;
900   $sth = $dbh->prepare($query);
901   $sth->execute || $form->dberror($query);
902
903   while (my ($amount, $exch) = $sth->fetchrow_array) {
904     $exch = 1 unless $exch;
905     $form->{creditremaining} -= $amount * $exch;
906   }
907   $sth->finish;
908     
909                 
910   # get shipto if we do not convert an order or invoice
911   if (!$form->{shipto}) {
912     map { delete $form->{$_} } qw(shiptoname shiptoaddress1 shiptoaddress2 shiptocity shiptostate shiptozipcode shiptocountry shiptocontact shiptophone shiptofax shiptoemail);
913
914     $query = qq|SELECT * FROM shipto
915                 WHERE trans_id = $form->{vendor_id}|;
916     $sth = $dbh->prepare($query);
917     $sth->execute || $form->dberror($query);
918
919     $ref = $sth->fetchrow_hashref(NAME_lc);
920     map { $form->{$_} = $ref->{$_} } keys %$ref;
921     $sth->finish;
922   }
923   
924   # get taxes for vendor
925   $query = qq|SELECT c.accno
926               FROM chart c
927               JOIN vendortax v ON (v.chart_id = c.id)
928               WHERE v.vendor_id = $form->{vendor_id}|;
929   $sth = $dbh->prepare($query);
930   $sth->execute || $form->dberror($query);
931
932   my $vendortax = ();
933   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
934     $vendortax{$ref->{accno}} = 1;
935   }
936   $sth->finish;
937
938
939   # get tax rates and description
940   $query = qq|SELECT c.accno, c.description, c.link, t.rate, t.taxnumber
941               FROM chart c
942               JOIN tax t ON (c.id = t.chart_id)
943               WHERE c.link LIKE '%CT_tax%'
944               ORDER BY accno|;
945   $sth = $dbh->prepare($query);
946   $sth->execute || $form->dberror($query);
947
948   $form->{taxaccounts} = "";
949   $form->{taxpart} = "";
950   $form->{taxservice} = "";
951   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
952     if ($vendortax{$ref->{accno}}) {
953       $form->{"$ref->{accno}_rate"} = $ref->{rate};
954       $form->{"$ref->{accno}_description"} = $ref->{description};
955       $form->{"$ref->{accno}_taxnumber"} = $ref->{taxnumber};
956       $form->{taxaccounts} .= "$ref->{accno} ";
957     }
958     
959     foreach my $item (split /:/, $ref->{link}) {
960       if ($item =~ /IC_taxpart/) {
961         $form->{taxpart} .= "$ref->{accno} ";
962       }
963       
964       if ($item =~ /IC_taxservice/) {
965         $form->{taxservice} .= "$ref->{accno} ";
966       }
967     }
968   }
969   $sth->finish;
970   chop $form->{taxaccounts};
971   chop $form->{taxpart};
972   chop $form->{taxservice};
973
974
975   if (!$form->{id} && $form->{type} !~ /_(order|quotation)/) {
976     # setup last accounts used
977     $query = qq|SELECT c.accno, c.description, c.link, c.category,
978                 ac.project_id, p.projectnumber, a.department_id,
979                 d.description AS department
980                 FROM chart c
981                 JOIN acc_trans ac ON (ac.chart_id = c.id)
982                 JOIN ap a ON (a.id = ac.trans_id)
983                 LEFT JOIN project p ON (ac.project_id = p.id)
984                 LEFT JOIN department d ON (a.department_id = d.id)
985                 WHERE a.vendor_id = $form->{vendor_id}
986                 AND a.id IN (SELECT max(id) FROM ap
987                              WHERE vendor_id = $form->{vendor_id})|;
988     $sth = $dbh->prepare($query);
989     $sth->execute || $form->dberror($query);
990     
991     my $i = 0;
992     while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
993       $form->{department} = $ref->{department};
994       $form->{department_id} = $ref->{department_id};
995
996       if ($ref->{link} =~ /_amount/) {
997         $i++;
998         $form->{"AP_amount_$i"} = "$ref->{accno}--$ref->{description}";
999         $form->{"projectnumber_$i"} = "$ref->{projectnumber}--$ref->{project_id}";
1000       }
1001       if ($ref->{category} eq 'L') {
1002         $form->{AP} = $form->{AP_1} = "$ref->{accno}--$ref->{description}";
1003       }
1004     }
1005     $sth->finish;
1006     $form->{rowcount} = $i if ($i && !$form->{type});
1007   }
1008
1009   $dbh->disconnect;
1010   
1011 }
1012
1013
1014 sub retrieve_item {
1015   my ($self, $myconfig, $form) = @_;
1016
1017   my $i = $form->{rowcount};
1018   my $null;
1019   my $var;
1020   
1021   # don't include assemblies or obsolete parts
1022   my $where = "WHERE p.assembly = '0' AND p.obsolete = '0'";
1023   
1024   if ($form->{"partnumber_$i"}) {
1025     $var = $form->like(lc $form->{"partnumber_$i"});
1026     $where .= " AND lower(p.partnumber) LIKE '$var'";
1027   }
1028   
1029   if ($form->{"description_$i"}) {
1030     $var = $form->like(lc $form->{"description_$i"});
1031     if ($form->{language_code}) {
1032       $where .= " AND lower(t1.description) LIKE '$var'";
1033     } else {
1034       $where .= " AND lower(p.description) LIKE '$var'";
1035     }
1036   }
1037
1038   if ($form->{"partsgroup_$i"}) {
1039     ($null, $var) = split /--/, $form->{"partsgroup_$i"};
1040     $where .= qq| AND p.partsgroup_id = $var|;
1041   }
1042   
1043   if ($form->{"description_$i"}) {
1044     $where .= " ORDER BY 3";
1045   } else {
1046     $where .= " ORDER BY 2";
1047   }
1048
1049   # connect to database
1050   my $dbh = $form->dbconnect($myconfig);
1051
1052   my $query = qq|SELECT p.id, p.partnumber, p.description,
1053                  c1.accno AS inventory_accno,
1054                  c2.accno AS income_accno,
1055                  c3.accno AS expense_accno,
1056                  pg.partsgroup, p.partsgroup_id,
1057                  p.lastcost AS sellprice, p.unit, p.bin, p.onhand,
1058                  p.partnumber AS sku, p.weight,
1059                  t1.description AS translation,
1060                  t2.description AS grouptranslation
1061                  FROM parts p
1062                  LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id)
1063                  LEFT JOIN chart c2 ON (p.income_accno_id = c2.id)
1064                  LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id)
1065                  LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
1066                  LEFT JOIN translation t1 ON (t1.trans_id = p.id AND t1.language_code = '$form->{language_code}')
1067                  LEFT JOIN translation t2 ON (t2.trans_id = p.partsgroup_id AND t2.language_code = '$form->{language_code}')
1068                  $where|;
1069   my $sth = $dbh->prepare($query);
1070   $sth->execute || $form->dberror($query);
1071   
1072   # foreign currency
1073   &exchangerate_defaults($dbh, $form);
1074
1075   # taxes
1076   $query = qq|SELECT c.accno
1077               FROM chart c
1078               JOIN partstax pt ON (pt.chart_id = c.id)
1079               WHERE pt.parts_id = ?|;
1080   my $tth = $dbh->prepare($query) || $form->dberror($query);
1081
1082   # price matrix
1083   $query = qq|SELECT p.*
1084               FROM partsvendor p
1085               WHERE p.parts_id = ?
1086               AND vendor_id = $form->{vendor_id}|;
1087   my $pmh = $dbh->prepare($query) || $form->dberror($query);
1088
1089   my $ref;
1090   my $ptref;
1091   my $decimalplaces;
1092   
1093   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1094
1095     ($decimalplaces) = ($ref->{sellprice} =~ /\.(\d+)/);
1096     $decimalplaces = length $decimalplaces;
1097     $decimalplaces = 2 unless $decimalplaces;
1098     
1099     # get taxes for part
1100     $tth->execute($ref->{id});
1101
1102     $ref->{taxaccounts} = "";
1103     while ($ptref = $tth->fetchrow_hashref(NAME_lc)) {
1104       $ref->{taxaccounts} .= "$ptref->{accno} ";
1105     }
1106     $tth->finish;
1107     chop $ref->{taxaccounts};
1108
1109     # get vendor price and partnumber
1110     &price_matrix($pmh, $ref, $decimalplaces, $form, $myconfig);
1111
1112     $ref->{description} = $ref->{translation} if $ref->{translation};
1113     $ref->{partsgroup} = $ref->{grouptranslation} if $ref->{grouptranslation};
1114     
1115     push @{ $form->{item_list} }, $ref;
1116     
1117   }
1118   
1119   $sth->finish;
1120   $dbh->disconnect;
1121   
1122 }
1123
1124
1125 sub exchangerate_defaults {
1126   my ($dbh, $form) = @_;
1127
1128   my $var;
1129   
1130   # get default currencies
1131   my $query = qq|SELECT substr(curr,1,3), curr FROM defaults|;
1132   my $eth = $dbh->prepare($query) || $form->dberror($query);
1133   $eth->execute;
1134   ($form->{defaultcurrency}, $form->{currencies}) = $eth->fetchrow_array;
1135   $eth->finish;
1136
1137   $query = qq|SELECT sell
1138               FROM exchangerate
1139               WHERE curr = ?
1140               AND transdate = ?|;
1141   my $eth1 = $dbh->prepare($query) || $form->dberror($query);
1142
1143   $query = qq~SELECT max(transdate || ' ' || sell || ' ' || curr)
1144               FROM exchangerate
1145               WHERE curr = ?~;
1146   my $eth2 = $dbh->prepare($query) || $form->dberror($query);
1147
1148   # get exchange rates for transdate or max
1149   foreach $var (split /:/, substr($form->{currencies},4)) {
1150     $eth1->execute($var, $form->{transdate});
1151     ($form->{$var}) = $eth1->fetchrow_array;
1152     if (! $form->{$var} ) {
1153       $eth2->execute($var);
1154
1155       ($form->{$var}) = $eth2->fetchrow_array;
1156       ($null, $form->{$var}) = split / /, $form->{$var};
1157       $form->{$var} = 1 unless $form->{$var};
1158       $eth2->finish;
1159     }
1160     $eth1->finish;
1161   }
1162
1163   $form->{$form->{defaultcurrency}} = 1;
1164   
1165 }
1166
1167
1168 sub price_matrix {
1169   my ($pmh, $ref, $decimalplaces, $form, $myconfig) = @_;
1170   
1171   $pmh->execute($ref->{id});
1172   my $mref = $pmh->fetchrow_hashref(NAME_lc);
1173   
1174   if ($mref->{partnumber}) {
1175     $ref->{partnumber} = $mref->{partnumber};
1176   }
1177
1178   if ($mref->{lastcost}) {
1179     # do a conversion
1180     $ref->{sellprice} = $form->round_amount($mref->{lastcost} * $form->{$mref->{curr}}, $decimalplaces);
1181   }
1182   $pmh->finish;
1183
1184   $ref->{sellprice} *= 1;
1185   
1186   # add 0:price to matrix
1187   $ref->{pricematrix} = "0:$ref->{sellprice}";
1188   
1189 }
1190
1191
1192 sub vendor_details {
1193   my ($self, $myconfig, $form) = @_;
1194       
1195   # connect to database
1196   my $dbh = $form->dbconnect($myconfig);
1197
1198   # get rest for the vendor
1199   my $query = qq|SELECT vendornumber, name, address1, address2, city, state,
1200                  zipcode, country,
1201                  contact, phone as vendorphone, fax as vendorfax, vendornumber,
1202                  taxnumber, sic_code AS sic, iban, bic
1203                  FROM vendor
1204                  WHERE id = $form->{vendor_id}|;
1205   my $sth = $dbh->prepare($query);
1206   $sth->execute || $form->dberror($query);
1207
1208   $ref = $sth->fetchrow_hashref(NAME_lc);
1209   map { $form->{$_} = $ref->{$_} } keys %$ref;
1210
1211   $sth->finish;
1212   $dbh->disconnect;
1213
1214 }
1215
1216
1217 sub item_links {
1218   my ($self, $myconfig, $form) = @_;
1219
1220   # connect to database
1221   my $dbh = $form->dbconnect($myconfig);
1222
1223   my $query = qq|SELECT accno, description, link
1224                  FROM chart
1225                  WHERE link LIKE '%IC%'
1226                  ORDER BY accno|;
1227   my $sth = $dbh->prepare($query);
1228   $sth->execute || $form->dberror($query);
1229
1230   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1231     foreach my $key (split(/:/, $ref->{link})) {
1232       if ($key =~ /IC/) {
1233         push @{ $form->{IC_links}{$key} }, { accno => $ref->{accno},
1234                                        description => $ref->{description} };
1235       }
1236     }
1237   }
1238
1239   $sth->finish;
1240 }
1241
1242 1;
1243