Merge branch 'master' of vc.linet-services.de:public/lx-office-erp
[kivitendo-erp.git] / SL / CT.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) 2001
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 # backend code for customers and vendors
32 #
33 # CHANGE LOG:
34 #   DS. 2000-07-04  Created
35 #
36 #======================================================================
37
38 package CT;
39
40 use Data::Dumper;
41
42 use SL::Common;
43 use SL::CVar;
44 use SL::DBUtils;
45 use SL::FU;
46 use SL::Notes;
47 use SL::TransNumber;
48
49 use strict;
50
51 sub get_tuple {
52   $main::lxdebug->enter_sub();
53
54   my ( $self, $myconfig, $form ) = @_;
55
56   my $cv = $form->{db} eq "customer" ? "customer" : "vendor";
57
58   my $dbh   = $form->dbconnect($myconfig);
59   my $query =
60     qq|SELECT ct.*, b.id AS business, cp.* | .
61     qq|FROM $cv ct | .
62     qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
63     qq|LEFT JOIN contacts cp ON (ct.id = cp.cp_cv_id) | .
64     qq|WHERE (ct.id = ?) | .
65     qq|ORDER BY cp.cp_id LIMIT 1|;
66   my $sth = prepare_execute_query($form, $dbh, $query, $form->{id});
67
68   my $ref = $sth->fetchrow_hashref("NAME_lc");
69
70   map { $form->{$_} = $ref->{$_} } keys %$ref;
71
72   # remove any trailing whitespace
73   $form->{curr} =~ s/\s*$//;
74
75   $sth->finish;
76   if ( $form->{salesman_id} ) {
77     my $query =
78       qq|SELECT ct.name AS salesman | .
79       qq|FROM $cv ct | .
80       qq|WHERE ct.id = ?|;
81     ($form->{salesman}) =
82       selectrow_query($form, $dbh, $query, $form->{salesman_id});
83   }
84
85   my ($employee_id) = selectrow_query($form, $dbh, qq|SELECT id FROM employee WHERE login = ?|, $form->{login});
86   $query =
87     qq|SELECT n.*, n.itime::DATE AS created_on,
88          e.name AS created_by_name, e.login AS created_by_login
89        FROM notes n
90        LEFT JOIN employee e ON (n.created_by = e.id)
91        WHERE (n.trans_id = ?) AND (n.trans_module = 'ct')|;
92   $form->{NOTES} = selectall_hashref_query($form, $dbh, $query, conv_i($form->{id}));
93
94   $query =
95     qq|SELECT fu.follow_up_date, fu.done AS follow_up_done, e.name AS created_for_name, e.name AS created_for_login
96        FROM follow_ups fu
97        LEFT JOIN employee e ON (fu.created_for_user = e.id)
98        WHERE (fu.note_id = ?)
99          AND NOT COALESCE(fu.done, FALSE)
100          AND (   (fu.created_by = ?)
101               OR (fu.created_by IN (SELECT DISTINCT what FROM follow_up_access WHERE who = ?)))|;
102   $sth = prepare_query($form, $dbh, $query);
103
104   foreach my $note (@{ $form->{NOTES} }) {
105     do_statement($form, $sth, $query, conv_i($note->{id}), conv_i($note->{created_by}), conv_i($employee_id));
106     $ref = $sth->fetchrow_hashref();
107
108     map { $note->{$_} = $ref->{$_} } keys %{ $ref } if ($ref);
109   }
110
111   $sth->finish();
112
113   if ($form->{edit_note_id}) {
114     $query =
115       qq|SELECT n.id AS NOTE_id, n.subject AS NOTE_subject, n.body AS NOTE_body,
116            fu.id AS FU_id, fu.follow_up_date AS FU_date, fu.done AS FU_done, fu.created_for_user AS FU_created_for_user
117          FROM notes n
118          LEFT JOIN follow_ups fu ON ((n.id = fu.note_id) AND NOT COALESCE(fu.done, FALSE))
119          WHERE n.id = ?|;
120     $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{edit_note_id}));
121
122     if ($ref) {
123       foreach my $key (keys %{ $ref }) {
124         my $new_key       =  $key;
125         $new_key          =~ s/^([^_]+)/\U$1\E/;
126         $form->{$new_key} =  $ref->{$key};
127       }
128     }
129   }
130
131   # check if it is orphaned
132   my $arap      = ( $form->{db} eq 'customer' ) ? "ar" : "ap";
133   my $num_args  = 2;
134   my $makemodel = '';
135   if ($form->{db} eq 'vendor') {
136     $makemodel = qq| UNION SELECT 1 FROM makemodel mm WHERE mm.make = ?|;
137     $num_args++;
138   }
139
140   $query =
141     qq|SELECT a.id | .
142     qq|FROM $arap a | .
143     qq|JOIN $cv ct ON (a.${cv}_id = ct.id) | .
144     qq|WHERE ct.id = ? | .
145     qq|UNION | .
146     qq|SELECT a.id | .
147     qq|FROM oe a | .
148     qq|JOIN $cv ct ON (a.${cv}_id = ct.id) | .
149     qq|WHERE ct.id = ?|
150     . $makemodel;
151   my ($dummy) = selectrow_query($form, $dbh, $query, (conv_i($form->{id})) x $num_args);
152
153   $form->{status} = "orphaned" unless ($dummy);
154
155   $dbh->disconnect;
156
157   $main::lxdebug->leave_sub();
158 }
159
160 sub populate_drop_down_boxes {
161   $main::lxdebug->enter_sub();
162
163   my ($self, $myconfig, $form, $provided_dbh) = @_;
164   my $query;
165
166   my $dbh = $provided_dbh ? $provided_dbh : $form->dbconnect($myconfig);
167
168   # get business types
169   $query = qq|SELECT id, description FROM business ORDER BY id|;
170   $form->{all_business} = selectall_hashref_query($form, $dbh, $query);
171
172   # get shipto address
173   $query =
174     qq|SELECT shipto_id, shiptoname, shiptodepartment_1, shiptostreet, shiptocity
175        FROM shipto
176        WHERE (trans_id = ?) AND (module = 'CT')|;
177   $form->{SHIPTO} = selectall_hashref_query($form, $dbh, $query, $form->{id});
178
179   # get contacts
180   $query  = qq|SELECT cp_id, cp_name, cp_givenname FROM contacts WHERE cp_cv_id = ? ORDER BY cp_name|;
181   $form->{CONTACTS} = selectall_hashref_query($form, $dbh, $query, $form->{id});
182
183   # get languages
184   $query = qq|SELECT id, description FROM language ORDER BY id|;
185   $form->{languages} = selectall_hashref_query($form, $dbh, $query);
186
187   # get payment terms
188   $query = qq|SELECT id, description FROM payment_terms ORDER BY sortkey|;
189   $form->{payment_terms} = selectall_hashref_query($form, $dbh, $query);
190
191   $dbh->disconnect() unless ($provided_dbh);
192
193   $main::lxdebug->leave_sub();
194 }
195
196 sub query_titles_and_greetings {
197   $main::lxdebug->enter_sub();
198
199   my ( $self, $myconfig, $form ) = @_;
200   my ( %tmp,  $ref, $query );
201
202   my $dbh = $form->dbconnect($myconfig);
203
204   $query =
205     qq|SELECT DISTINCT(greeting) | .
206     qq|FROM customer | .
207     qq|WHERE greeting ~ '[a-zA-Z]' | .
208     qq|UNION | .
209     qq|SELECT DISTINCT(greeting) | .
210     qq|FROM vendor | .
211     qq|WHERE greeting ~ '[a-zA-Z]' | .
212     qq|ORDER BY greeting|;
213
214   map({ $tmp{$_} = 1; } selectall_array_query($form, $dbh, $query));
215   $form->{COMPANY_GREETINGS} = [ sort(keys(%tmp)) ];
216
217   $query =
218     qq|SELECT DISTINCT(cp_title) | .
219     qq|FROM contacts | .
220     qq|WHERE cp_title ~ '[a-zA-Z]'|;
221   $form->{TITLES} = [ selectall_array_query($form, $dbh, $query) ];
222
223   $query =
224     qq|SELECT DISTINCT(cp_abteilung) | .
225     qq|FROM contacts | .
226     qq|WHERE cp_abteilung ~ '[a-zA-Z]'|;
227   $form->{DEPARTMENT} = [ selectall_array_query($form, $dbh, $query) ];
228
229   $dbh->disconnect();
230   $main::lxdebug->leave_sub();
231 }
232
233 sub save_customer {
234   $main::lxdebug->enter_sub();
235
236   my ( $self, $myconfig, $form ) = @_;
237
238   # set pricegroup to default
239   $form->{klass} = 0 unless ($form->{klass});
240
241   # connect to database
242   my $dbh = $form->get_standard_dbh;
243
244   map( {
245     $form->{"cp_${_}"} = $form->{"selected_cp_${_}"}
246     if ( $form->{"selected_cp_${_}"} );
247        } qw(title greeting abteilung) );
248   $form->{"greeting"} = $form->{"selected_company_greeting"}
249   if ( $form->{"selected_company_greeting"} );
250
251   # assign value discount, terms, creditlimit
252   $form->{discount} = $form->parse_amount( $myconfig, $form->{discount} );
253   $form->{discount} /= 100;
254   $form->{creditlimit} = $form->parse_amount( $myconfig, $form->{creditlimit} );
255
256   my ( $query, $sth, $f_id );
257
258   if ( $form->{id} ) {
259     $query = qq|SELECT id FROM customer WHERE customernumber = ?|;
260     ($f_id) = selectrow_query($form, $dbh, $query, $form->{customernumber});
261
262     if (($f_id ne $form->{id}) && ($f_id ne "")) {
263       $main::lxdebug->leave_sub();
264       return 3;
265     }
266
267   } else {
268     my $customernumber      = SL::TransNumber->new(type        => 'customer',
269                                                    dbh         => $dbh,
270                                                    number      => $form->{customernumber},
271                                                    business_id => $form->{business},
272                                                    save        => 1);
273     $form->{customernumber} = $customernumber->create_unique unless $customernumber->is_unique;
274
275     $query = qq|SELECT nextval('id')|;
276     ($form->{id}) = selectrow_query($form, $dbh, $query);
277
278     $query = qq|INSERT INTO customer (id, name) VALUES (?, '')|;
279     do_query($form, $dbh, $query, $form->{id});
280   }
281
282   $query = qq|UPDATE customer SET | .
283     qq|customernumber = ?, | .
284     qq|name = ?, | .
285     qq|greeting = ?, | .
286     qq|department_1 = ?, | .
287     qq|department_2 = ?, | .
288     qq|street = ?, | .
289     qq|zipcode = ?, | .
290     qq|city = ?, | .
291     qq|country = ?, | .
292     qq|homepage = ?, | .
293     qq|contact = ?, | .
294     qq|phone = ?, | .
295     qq|fax = ?, | .
296     qq|email = ?, | .
297     qq|cc = ?, | .
298     qq|bcc = ?, | .
299     qq|notes = ?, | .
300     qq|discount = ?, | .
301     qq|creditlimit = ?, | .
302     qq|terms = ?, | .
303     qq|business_id = ?, | .
304     qq|taxnumber = ?, | .
305     qq|language = ?, | .
306     qq|account_number = ?, | .
307     qq|bank_code = ?, | .
308     qq|bank = ?, | .
309     qq|iban = ?, | .
310     qq|bic = ?, | .
311     qq|obsolete = ?, | .
312     qq|direct_debit = ?, | .
313     qq|ustid = ?, | .
314     qq|username = ?, | .
315     qq|salesman_id = ?, | .
316     qq|language_id = ?, | .
317     qq|payment_id = ?, | .
318     qq|taxzone_id = ?, | .
319     qq|user_password = ?, | .
320     qq|c_vendor_id = ?, | .
321     qq|klass = ?, | .
322     qq|curr = ? | .
323     qq|WHERE id = ?|;
324   my @values = (
325     $form->{customernumber},
326     $form->{name},
327     $form->{greeting},
328     $form->{department_1},
329     $form->{department_2},
330     $form->{street},
331     $form->{zipcode},
332     $form->{city},
333     $form->{country},
334     $form->{homepage},
335     $form->{contact},
336     $form->{phone},
337     $form->{fax},
338     $form->{email},
339     $form->{cc},
340     $form->{bcc},
341     $form->{notes},
342     $form->{discount},
343     $form->{creditlimit},
344     conv_i($form->{terms}),
345     conv_i($form->{business}),
346     $form->{taxnumber},
347     $form->{language},
348     $form->{account_number},
349     $form->{bank_code},
350     $form->{bank},
351     $form->{iban},
352     $form->{bic},
353     $form->{obsolete} ? 't' : 'f',
354     $form->{direct_debit} ? 't' : 'f',
355     $form->{ustid},
356     $form->{username},
357     conv_i($form->{salesman_id}),
358     conv_i($form->{language_id}),
359     conv_i($form->{payment_id}),
360     conv_i($form->{taxzone_id}, 0),
361     $form->{user_password},
362     $form->{c_vendor_id},
363     conv_i($form->{klass}),
364     substr($form->{currency}, 0, 3),
365     $form->{id}
366     );
367   do_query( $form, $dbh, $query, @values );
368
369   $query = undef;
370   my @columns = qw(cp_title cp_givenname cp_name cp_email cp_phone1 cp_phone2 cp_abteilung cp_fax
371                    cp_mobile1 cp_mobile2 cp_satphone cp_satfax cp_project cp_privatphone cp_privatemail cp_birthday cp_gender
372                    cp_street cp_zipcode cp_city);
373   @values     = map { $_ eq 'cp_gender' ? ($form->{$_} eq 'f' ? 'f' : 'm') : $form->{$_} } @columns;
374
375   if ( $form->{cp_id} ) {
376     $query = qq|UPDATE contacts SET | . join(', ', map { "${_} = ?" } @columns) . qq| WHERE cp_id = ?|;
377     push @values, $form->{cp_id};
378
379   } elsif ( $form->{cp_name} || $form->{cp_givenname} ) {
380     $query = qq|INSERT INTO contacts (| . join(', ', 'cp_cv_id', @columns) . qq|) VALUES (?, | . join(', ', ('?') x scalar(@columns)) . qq|)|;
381     unshift @values, $form->{id};
382   }
383   do_query( $form, $dbh, $query, @values ) if ($query);
384
385   # add shipto
386   $form->add_shipto( $dbh, $form->{id}, "CT" );
387
388   $self->_save_note('dbh' => $dbh);
389   $self->_delete_selected_notes('dbh' => $dbh);
390
391   CVar->save_custom_variables('dbh'       => $dbh,
392                               'module'    => 'CT',
393                               'trans_id'  => $form->{id},
394                               'variables' => $form,
395                               'always_valid' => 1);
396   if ($form->{cp_id}) {
397     CVar->save_custom_variables('dbh'       => $dbh,
398                                 'module'    => 'Contacts',
399                                 'trans_id'  => $form->{cp_id},
400                                 'variables' => $form,
401                                 'name_prefix'  => 'cp',
402                                 'always_valid' => 1);
403   }
404
405   my $rc = $dbh->commit();
406
407   $main::lxdebug->leave_sub();
408   return $rc;
409 }
410
411 sub save_vendor {
412   $main::lxdebug->enter_sub();
413
414   my ( $self, $myconfig, $form ) = @_;
415
416   $form->{taxzone_id} *= 1;
417   # connect to database
418   my $dbh = $form->get_standard_dbh;
419
420   map( {
421     $form->{"cp_${_}"} = $form->{"selected_cp_${_}"}
422     if ( $form->{"selected_cp_${_}"} );
423        } qw(title greeting abteilung) );
424   $form->{"greeting"} = $form->{"selected_company_greeting"}
425   if ( $form->{"selected_company_greeting"} );
426
427   $form->{discount} = $form->parse_amount( $myconfig, $form->{discount} );
428   $form->{discount} /= 100;
429   $form->{creditlimit} = $form->parse_amount( $myconfig, $form->{creditlimit} );
430
431   my $query;
432
433   if (!$form->{id}) {
434     $query = qq|SELECT nextval('id')|;
435     ($form->{id}) = selectrow_query($form, $dbh, $query);
436
437     $query = qq|INSERT INTO vendor (id, name) VALUES (?, '')|;
438     do_query($form, $dbh, $query, $form->{id});
439
440     my $vendornumber      = SL::TransNumber->new(type   => 'vendor',
441                                                  dbh    => $dbh,
442                                                  number => $form->{vendornumber},
443                                                  save   => 1);
444     $form->{vendornumber} = $vendornumber->create_unique unless $vendornumber->is_unique;
445   }
446
447   $query =
448     qq|UPDATE vendor SET | .
449     qq|  vendornumber = ?, | .
450     qq|  name = ?, | .
451     qq|  greeting = ?, | .
452     qq|  department_1 = ?, | .
453     qq|  department_2 = ?, | .
454     qq|  street = ?, | .
455     qq|  zipcode = ?, | .
456     qq|  city = ?, | .
457     qq|  country = ?, | .
458     qq|  homepage = ?, | .
459     qq|  contact = ?, | .
460     qq|  phone = ?, | .
461     qq|  fax = ?, | .
462     qq|  email = ?, | .
463     qq|  cc = ?, | .
464     qq|  bcc = ?, | .
465     qq|  notes = ?, | .
466     qq|  terms = ?, | .
467     qq|  discount = ?, | .
468     qq|  creditlimit = ?, | .
469     qq|  business_id = ?, | .
470     qq|  taxnumber = ?, | .
471     qq|  language = ?, | .
472     qq|  account_number = ?, | .
473     qq|  bank_code = ?, | .
474     qq|  bank = ?, | .
475     qq|  iban = ?, | .
476     qq|  bic = ?, | .
477     qq|  obsolete = ?, | .
478     qq|  direct_debit = ?, | .
479     qq|  ustid = ?, | .
480     qq|  payment_id = ?, | .
481     qq|  taxzone_id = ?, | .
482     qq|  language_id = ?, | .
483     qq|  username = ?, | .
484     qq|  user_password = ?, | .
485     qq|  v_customer_id = ?, | .
486     qq|  curr = ? | .
487     qq|WHERE id = ?|;
488   my @values = (
489     $form->{vendornumber},
490     $form->{name},
491     $form->{greeting},
492     $form->{department_1},
493     $form->{department_2},
494     $form->{street},
495     $form->{zipcode},
496     $form->{city},
497     $form->{country},
498     $form->{homepage},
499     $form->{contact},
500     $form->{phone},
501     $form->{fax},
502     $form->{email},
503     $form->{cc},
504     $form->{bcc},
505     $form->{notes},
506     conv_i($form->{terms}),
507     $form->{discount},
508     $form->{creditlimit},
509     conv_i($form->{business}),
510     $form->{taxnumber},
511     $form->{language},
512     $form->{account_number},
513     $form->{bank_code},
514     $form->{bank},
515     $form->{iban},
516     $form->{bic},
517     $form->{obsolete} ? 't' : 'f',
518     $form->{direct_debit} ? 't' : 'f',
519     $form->{ustid},
520     conv_i($form->{payment_id}),
521     conv_i($form->{taxzone_id}, 0),
522     conv_i( $form->{language_id}),
523     $form->{username},
524     $form->{user_password},
525     $form->{v_customer_id},
526     substr($form->{currency}, 0, 3),
527     $form->{id}
528     );
529   do_query($form, $dbh, $query, @values);
530
531   $query = undef;
532   if ( $form->{cp_id} ) {
533     $query = qq|UPDATE contacts SET | .
534       qq|cp_title = ?,  | .
535       qq|cp_givenname = ?, | .
536       qq|cp_name = ?, | .
537       qq|cp_email = ?, | .
538       qq|cp_phone1 = ?, | .
539       qq|cp_phone2 = ?, | .
540       qq|cp_abteilung = ?, | .
541       qq|cp_fax = ?, | .
542       qq|cp_mobile1 = ?, | .
543       qq|cp_mobile2 = ?, | .
544       qq|cp_satphone = ?, | .
545       qq|cp_satfax = ?, | .
546       qq|cp_project = ?, | .
547       qq|cp_privatphone = ?, | .
548       qq|cp_privatemail = ?, | .
549       qq|cp_birthday = ?, | .
550       qq|cp_gender = ? | .
551       qq|WHERE cp_id = ?|;
552     @values = (
553       $form->{cp_title},
554       $form->{cp_givenname},
555       $form->{cp_name},
556       $form->{cp_email},
557       $form->{cp_phone1},
558       $form->{cp_phone2},
559       $form->{cp_abteilung},
560       $form->{cp_fax},
561       $form->{cp_mobile1},
562       $form->{cp_mobile2},
563       $form->{cp_satphone},
564       $form->{cp_satfax},
565       $form->{cp_project},
566       $form->{cp_privatphone},
567       $form->{cp_privatemail},
568       $form->{cp_birthday},
569       $form->{cp_gender} eq 'f' ? 'f' : 'm',
570       $form->{cp_id}
571       );
572   } elsif ( $form->{cp_name} || $form->{cp_givenname} ) {
573     $query =
574       qq|INSERT INTO contacts ( cp_cv_id, cp_title, cp_givenname,  | .
575       qq|  cp_name, cp_email, cp_phone1, cp_phone2, cp_abteilung, cp_fax, cp_mobile1, | .
576       qq|  cp_mobile2, cp_satphone, cp_satfax, cp_project, cp_privatphone, cp_privatemail, | .
577       qq|  cp_birthday, cp_gender) | .
578       qq|VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)|;
579     @values = (
580       $form->{id},
581       $form->{cp_title},
582       $form->{cp_givenname},
583       $form->{cp_name},
584       $form->{cp_email},
585       $form->{cp_phone1},
586       $form->{cp_phone2},
587       $form->{cp_abteilung},
588       $form->{cp_fax},
589       $form->{cp_mobile1},
590       $form->{cp_mobile2},
591       $form->{cp_satphone},
592       $form->{cp_satfax},
593       $form->{cp_project},
594       $form->{cp_privatphone},
595       $form->{cp_privatemail},
596       $form->{cp_birthday},
597       $form->{cp_gender}
598       );
599   }
600   do_query($form, $dbh, $query, @values) if ($query);
601
602   # add shipto
603   $form->add_shipto( $dbh, $form->{id}, "CT" );
604
605   $self->_save_note('dbh' => $dbh);
606   $self->_delete_selected_notes('dbh' => $dbh);
607
608   CVar->save_custom_variables('dbh'       => $dbh,
609                               'module'    => 'CT',
610                               'trans_id'  => $form->{id},
611                               'variables' => $form,
612                               'always_valid' => 1);
613   if ($form->{cp_id}) {
614     CVar->save_custom_variables('dbh'       => $dbh,
615                                 'module'    => 'Contacts',
616                                 'trans_id'  => $form->{cp_id},
617                                 'variables' => $form,
618                                 'name_prefix'  => 'cp',
619                                 'always_valid' => 1);
620   }
621
622   my $rc = $dbh->commit();
623
624   $main::lxdebug->leave_sub();
625   return $rc;
626 }
627
628 sub delete {
629   $main::lxdebug->enter_sub();
630
631   my ( $self, $myconfig, $form ) = @_;
632   # connect to database
633   my $dbh = $form->dbconnect($myconfig);
634
635   # delete vendor
636   my $cv = $form->{db} eq "customer" ? "customer" : "vendor";
637   my $query = qq|DELETE FROM $cv WHERE id = ?|;
638   do_query($form, $dbh, $query, $form->{id});
639
640   $dbh->disconnect;
641
642   $main::lxdebug->leave_sub();
643 }
644
645 sub search {
646   $main::lxdebug->enter_sub();
647
648   my ( $self, $myconfig, $form ) = @_;
649
650   # connect to database
651   my $dbh = $form->dbconnect($myconfig);
652
653   my $cv = $form->{db} eq "customer" ? "customer" : "vendor";
654
655   my $where = "1 = 1";
656   my @values;
657
658   my %allowed_sort_columns =
659     map { $_, 1 } qw(
660       id customernumber vendornumber name contact phone fax email street
661       taxnumber business invnumber ordnumber quonumber zipcode city
662     );
663   my $sortorder    = $form->{sort} && $allowed_sort_columns{$form->{sort}} ? $form->{sort} : "name";
664   $form->{sort} = $sortorder;
665   my $sortdir   = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
666
667   if ($sortorder !~ /(business|id)/ && 1 >= scalar grep { $form->{$_} } qw(l_ordnumber l_quonumber l_invnumber )) {
668     $sortorder  = "lower($sortorder) ${sortdir}";
669   } else {
670     $sortorder .= " ${sortdir}";
671   }
672
673   if ($form->{"${cv}number"}) {
674     $where .= " AND ct.${cv}number ILIKE ?";
675     push(@values, '%' . $form->{"${cv}number"} . '%');
676   }
677
678   foreach my $key (qw(name contact email)) {
679     if ($form->{$key}) {
680       $where .= " AND ct.$key ILIKE ?";
681       push(@values, '%' . $form->{$key} . '%');
682     }
683   }
684
685   if ($form->{cp_name}) {
686     $where .= " AND ct.id IN (SELECT cp_cv_id FROM contacts WHERE lower(cp_name) LIKE lower(?))";
687     push @values, '%' . $form->{cp_name} . '%';
688   }
689
690   if ($form->{addr_city}) {
691     $where .= " AND ((lower(ct.city) LIKE lower(?))
692                      OR
693                      (ct.id IN (
694                         SELECT trans_id
695                         FROM shipto
696                         WHERE (module = 'CT')
697                           AND (lower(shiptocity) LIKE lower(?))
698                       ))
699                      )";
700     push @values, ('%' . $form->{addr_city} . '%') x 2;
701   }
702
703   if ( $form->{status} eq 'orphaned' ) {
704     $where .=
705       qq| AND ct.id NOT IN | .
706       qq|   (SELECT o.${cv}_id FROM oe o, $cv cv WHERE cv.id = o.${cv}_id)|;
707     if ($cv eq 'customer') {
708       $where .=
709         qq| AND ct.id NOT IN | .
710         qq| (SELECT a.customer_id FROM ar a, customer cv | .
711         qq|  WHERE cv.id = a.customer_id)|;
712     }
713     if ($cv eq 'vendor') {
714       $where .=
715         qq| AND ct.id NOT IN | .
716         qq| (SELECT a.vendor_id FROM ap a, vendor cv | .
717         qq|  WHERE cv.id = a.vendor_id)|;
718     }
719     $form->{l_invnumber} = $form->{l_ordnumber} = $form->{l_quonumber} = "";
720   }
721
722   if ($form->{obsolete} eq "Y") {
723     $where .= qq| AND obsolete|;
724   } elsif ($form->{obsolete} eq "N") {
725     $where .= qq| AND NOT obsolete|;
726   }
727
728   if ($form->{business_id}) {
729     $where .= qq| AND (business_id = ?)|;
730     push(@values, conv_i($form->{business_id}));
731   }
732
733   # Nur Kunden finden, bei denen ich selber der Verkäufer bin
734   # Gilt nicht für Lieferanten
735   if ($cv eq 'customer' &&   !$main::auth->assert('customer_vendor_all_edit', 1)) {
736     $where .= qq| AND ct.salesman_id = (select id from employee where login= ?)|;
737     push(@values, $form->{login});
738   }
739
740   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'CT',
741                                                             'trans_id_field' => 'ct.id',
742                                                             'filter'         => $form);
743
744   if ($cvar_where) {
745     $where .= qq| AND ($cvar_where)|;
746     push @values, @cvar_values;
747   }
748
749   if ($form->{addr_street}) {
750     $where .= qq| AND (street ILIKE ?)|;
751     push @values, '%' . $form->{addr_street} . '%';
752   }
753
754   if ($form->{addr_zipcode}) {
755     $where .= qq| AND (zipcode ILIKE ?)|;
756     push @values, $form->{addr_zipcode} . '%';
757   }
758
759   my $query =
760     qq|SELECT ct.*, b.description AS business | .
761     qq|FROM $cv ct | .
762     qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
763     qq|WHERE $where|;
764
765   my @saved_values = @values;
766   # redo for invoices, orders and quotations
767   if ($form->{l_invnumber} || $form->{l_ordnumber} || $form->{l_quonumber}) {
768     my ($ar, $union, $module);
769     $query = "";
770
771     if ($form->{l_invnumber}) {
772       my $ar = $cv eq 'customer' ? 'ar' : 'ap';
773       my $module = $ar eq 'ar' ? 'is' : 'ir';
774
775       $query =
776         qq|SELECT ct.*, b.description AS business, | .
777         qq|  a.invnumber, a.ordnumber, a.quonumber, a.id AS invid, | .
778         qq|  '$module' AS module, 'invoice' AS formtype, | .
779         qq|  (a.amount = a.paid) AS closed | .
780         qq|FROM $cv ct | .
781         qq|JOIN $ar a ON (a.${cv}_id = ct.id) | .
782         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
783         qq|WHERE $where AND (a.invoice = '1')|;
784
785       $union = qq|UNION|;
786     }
787
788     if ( $form->{l_ordnumber} ) {
789       if ($union eq "UNION") {
790         push(@values, @saved_values);
791       }
792       $query .=
793         qq| $union | .
794         qq|SELECT ct.*, b.description AS business,| .
795         qq|  ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
796         qq|  'oe' AS module, 'order' AS formtype, o.closed | .
797         qq|FROM $cv ct | .
798         qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
799         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
800         qq|WHERE $where AND (o.quotation = '0')|;
801
802       $union = qq|UNION|;
803     }
804
805     if ( $form->{l_quonumber} ) {
806       if ($union eq "UNION") {
807         push(@values, @saved_values);
808       }
809       $query .=
810         qq| $union | .
811         qq|SELECT ct.*, b.description AS business, | .
812         qq|  ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
813         qq|  'oe' AS module, 'quotation' AS formtype, o.closed | .
814         qq|FROM $cv ct | .
815         qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
816         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
817         qq|WHERE $where AND (o.quotation = '1')|;
818     }
819   }
820
821   $query .= qq| ORDER BY $sortorder|;
822
823   $form->{CT} = selectall_hashref_query($form, $dbh, $query, @values);
824
825   $main::lxdebug->leave_sub();
826 }
827
828 sub get_contact {
829   $main::lxdebug->enter_sub();
830
831   my ( $self, $myconfig, $form ) = @_;
832
833   die 'Missing argument: cp_id' unless $::form->{cp_id};
834
835   my $dbh   = $form->dbconnect($myconfig);
836   my $query =
837     qq|SELECT * FROM contacts c | .
838     qq|WHERE cp_id = ? ORDER BY cp_id limit 1|;
839   my $sth = prepare_execute_query($form, $dbh, $query, $form->{cp_id});
840   my $ref = $sth->fetchrow_hashref("NAME_lc");
841
842   map { $form->{$_} = $ref->{$_} } keys %$ref;
843
844   $query = qq|SELECT COUNT(cp_id) AS used FROM (
845     SELECT cp_id FROM oe UNION
846     SELECT cp_id FROM ar UNION
847     SELECT cp_id FROM ap UNION
848     SELECT cp_id FROM delivery_orders
849   ) AS cpid WHERE cp_id = ? OR ? = 0|;
850   ($form->{cp_used}) = selectfirst_array_query($form, $dbh, $query, ($form->{cp_id})x2);
851
852   $sth->finish;
853   $dbh->disconnect;
854
855   $main::lxdebug->leave_sub();
856 }
857
858 sub get_shipto {
859   $main::lxdebug->enter_sub();
860
861   my ( $self, $myconfig, $form ) = @_;
862   my $dbh   = $form->dbconnect($myconfig);
863   my $query = qq|SELECT * FROM shipto WHERE shipto_id = ?|;
864   my $sth = prepare_execute_query($form, $dbh, $query, $form->{shipto_id});
865
866   my $ref = $sth->fetchrow_hashref("NAME_lc");
867
868   map { $form->{$_} = $ref->{$_} } keys %$ref;
869
870   $query = qq|SELECT COUNT(shipto_id) AS used FROM (
871     SELECT shipto_id FROM oe UNION
872     SELECT shipto_id FROM ar UNION
873     SELECT shipto_id FROM delivery_orders
874   ) AS stid WHERE shipto_id = ? OR ? = 0|;
875   ($form->{shiptoused}) = selectfirst_array_query($form, $dbh, $query, ($form->{shipto_id})x2);
876
877   $sth->finish;
878   $dbh->disconnect;
879
880   $main::lxdebug->leave_sub();
881 }
882
883 sub get_delivery {
884   $main::lxdebug->enter_sub();
885
886   my ( $self, $myconfig, $form ) = @_;
887   my $dbh = $form->dbconnect($myconfig);
888
889   my $arap = $form->{db} eq "vendor" ? "ap" : "ar";
890   my $db = $form->{db} eq "customer" ? "customer" : "vendor";
891   my $qty_sign = $form->{db} eq 'vendor' ? ' * -1 AS qty' : '';
892
893   my $where = " WHERE 1=1 ";
894   my @values;
895
896   if ($form->{shipto_id} && ($arap eq "ar")) {
897     $where .= "AND ${arap}.shipto_id = ?";
898     push(@values, $form->{shipto_id});
899   } else {
900     $where .= "AND ${arap}.${db}_id = ?";
901     push(@values, $form->{id});
902   }
903
904   if ($form->{from}) {
905     $where .= "AND ${arap}.transdate >= ?";
906     push(@values, conv_date($form->{from}));
907   }
908   if ($form->{to}) {
909     $where .= "AND ${arap}.transdate <= ?";
910     push(@values, conv_date($form->{to}));
911   }
912   my $query =
913     qq|SELECT s.shiptoname, i.qty $qty_sign, | .
914     qq|  ${arap}.id, ${arap}.transdate, ${arap}.invnumber, ${arap}.ordnumber, | .
915     qq|  i.description, i.unit, i.sellprice, | .
916     qq|  oe.id AS oe_id, invoice | .
917     qq|FROM $arap | .
918     qq|LEFT JOIN shipto s ON | .
919     ($arap eq "ar"
920      ? qq|(ar.shipto_id = s.shipto_id) |
921      : qq|(ap.id = s.trans_id) |) .
922     qq|LEFT JOIN invoice i ON (${arap}.id = i.trans_id) | .
923     qq|LEFT join parts p ON (p.id = i.parts_id) | .
924     qq|LEFT JOIN oe ON (oe.ordnumber = ${arap}.ordnumber AND NOT ${arap}.ordnumber = '') | .
925     $where .
926     qq|ORDER BY ${arap}.transdate DESC LIMIT 15|;
927
928   $form->{DELIVERY} = selectall_hashref_query($form, $dbh, $query, @values);
929
930   $dbh->disconnect;
931
932   $main::lxdebug->leave_sub();
933 }
934
935 sub _save_note {
936   $main::lxdebug->enter_sub();
937
938   my $self   = shift;
939   my %params = @_;
940
941   my $form   = $main::form;
942
943   Common::check_params(\%params, 'dbh');
944
945   if (!$form->{NOTE_subject}) {
946     $main::lxdebug->leave_sub();
947     return;
948   }
949
950   my $dbh = $params{dbh};
951
952   my %follow_up;
953   my %note = (
954     'id'           => $form->{NOTE_id},
955     'subject'      => $form->{NOTE_subject},
956     'body'         => $form->{NOTE_body},
957     'trans_id'     => $form->{id},
958     'trans_module' => 'ct',
959   );
960
961   $note{id} = Notes->save(%note);
962
963   if ($form->{FU_date}) {
964     %follow_up = (
965       'id'               => $form->{FU_id},
966       'note_id'          => $note{id},
967       'follow_up_date'   => $form->{FU_date},
968       'created_for_user' => $form->{FU_created_for_user},
969       'done'             => $form->{FU_done} ? 1 : 0,
970       'subject'          => $form->{NOTE_subject},
971       'body'             => $form->{NOTE_body},
972       'LINKS'            => [
973         {
974           'trans_id'     => $form->{id},
975           'trans_type'   => $form->{db} eq 'customer' ? 'customer' : 'vendor',
976           'trans_info'   => $form->{name},
977         },
978       ],
979     );
980
981     $follow_up{id} = FU->save(%follow_up);
982
983   } elsif ($form->{FU_id}) {
984     do_query($form, $dbh, qq|DELETE FROM follow_up_links WHERE follow_up_id = ?|, conv_i($form->{FU_id}));
985     do_query($form, $dbh, qq|DELETE FROM follow_ups      WHERE id = ?|,           conv_i($form->{FU_id}));
986   }
987
988   delete @{$form}{grep { /^NOTE_|^FU_/ } keys %{ $form }};
989
990   $main::lxdebug->leave_sub();
991 }
992
993 sub _delete_selected_notes {
994   $main::lxdebug->enter_sub();
995
996   my $self   = shift;
997   my %params = @_;
998
999   Common::check_params(\%params, 'dbh');
1000
1001   my $form = $main::form;
1002   my $dbh  = $params{dbh};
1003
1004   foreach my $i (1 .. $form->{NOTES_rowcount}) {
1005     next unless ($form->{"NOTE_delete_$i"} && $form->{"NOTE_id_$i"});
1006
1007     Notes->delete('dbh' => $params{dbh},
1008                   'id'  => $form->{"NOTE_id_$i"});
1009   }
1010
1011   $main::lxdebug->leave_sub();
1012 }
1013
1014 # TODO: remove in 2.7.0 stable
1015 sub delete_shipto {
1016   $main::lxdebug->enter_sub();
1017
1018   my $self      = shift;
1019   my $shipto_id = shift;
1020
1021   my $form      = $main::form;
1022   my %myconfig  = %main::myconfig;
1023   my $dbh       = $form->get_standard_dbh(\%myconfig);
1024
1025   do_query($form, $dbh, qq|UPDATE shipto SET trans_id = NULL WHERE shipto_id = ?|, $shipto_id);
1026
1027   $dbh->commit();
1028
1029   $main::lxdebug->leave_sub();
1030 }
1031
1032 # TODO: remove in 2.7.0 stable
1033 sub delete_contact {
1034   $main::lxdebug->enter_sub();
1035
1036   my $self      = shift;
1037   my $cp_id     = shift;
1038
1039   my $form      = $main::form;
1040   my %myconfig  = %main::myconfig;
1041   my $dbh       = $form->get_standard_dbh(\%myconfig);
1042
1043   do_query($form, $dbh, qq|UPDATE contacts SET cp_cv_id = NULL WHERE cp_id = ?|, $cp_id);
1044
1045   $dbh->commit();
1046
1047   $main::lxdebug->leave_sub();
1048 }
1049
1050 sub get_bank_info {
1051   $main::lxdebug->enter_sub();
1052
1053   my $self     = shift;
1054   my %params   = @_;
1055
1056   Common::check_params(\%params, qw(vc id));
1057
1058   my $myconfig = \%main::myconfig;
1059   my $form     = $main::form;
1060
1061   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
1062
1063   my $table        = $params{vc} eq 'customer' ? 'customer' : 'vendor';
1064   my @ids          = ref $params{id} eq 'ARRAY' ? @{ $params{id} } : ($params{id});
1065   my $placeholders = join ", ", ('?') x scalar @ids;
1066   my $query        = qq|SELECT id, name, account_number, bank, bank_code, iban, bic
1067                         FROM ${table}
1068                         WHERE id IN (${placeholders})|;
1069
1070   my $result       = selectall_hashref_query($form, $dbh, $query, map { conv_i($_) } @ids);
1071
1072   if (ref $params{id} eq 'ARRAY') {
1073     $result = { map { $_->{id} => $_ } @{ $result } };
1074   } else {
1075     $result = $result->[0] || { 'id' => $params{id} };
1076   }
1077
1078   $main::lxdebug->leave_sub();
1079
1080   return $result;
1081 }
1082
1083 sub parse_excel_file {
1084   $main::lxdebug->enter_sub();
1085
1086   my ($self, $myconfig, $form) = @_;
1087   my $locale = $main::locale;
1088
1089   $form->{formname}   = 'sales_quotation';
1090   $form->{type}   = 'sales_quotation';
1091   $form->{format} = 'excel';
1092   $form->{media}  = 'screen';
1093   $form->{quonumber} = 1;
1094
1095
1096   # $form->{"notes"} will be overridden by the customer's/vendor's "notes" field. So save it here.
1097   $form->{ $form->{"formname"} . "notes" } = $form->{"notes"};
1098
1099   my $inv                  = "quo";
1100   my $due                  = "req";
1101   $form->{"${inv}date"} = $form->{transdate};
1102   $form->{label}        = $locale->text('Quotation');
1103   my $numberfld            = "sqnumber";
1104   my $order                = 1;
1105
1106   # assign number
1107   $form->{what_done} = $form->{formname};
1108
1109   map({ delete($form->{$_}); } grep(/^cp_/, keys(%{ $form })));
1110
1111   my $output_dateformat = $myconfig->{"dateformat"};
1112   my $output_numberformat = $myconfig->{"numberformat"};
1113   my $output_longdates = 1;
1114
1115   # map login user variables
1116   map { $form->{"login_$_"} = $myconfig->{$_} } ("name", "email", "fax", "tel", "company");
1117
1118   # format item dates
1119   for my $field (qw(transdate_oe deliverydate_oe)) {
1120     map {
1121       $form->{$field}[$_] = $locale->date($myconfig, $form->{$field}[$_], 1);
1122     } 0 .. $#{ $form->{$field} };
1123   }
1124
1125   if ($form->{shipto_id}) {
1126     $form->get_shipto($myconfig);
1127   }
1128
1129   $form->{notes} =~ s/^\s+//g;
1130
1131   $form->{templates} = $myconfig->{templates};
1132
1133   delete $form->{printer_command};
1134
1135   $form->get_employee_info($myconfig);
1136
1137   my ($cvar_date_fields, $cvar_number_fields) = CVar->get_field_format_list('module' => 'CT', 'prefix' => 'vc_');
1138
1139   if (scalar @{ $cvar_date_fields }) {
1140     format_dates($output_dateformat, $output_longdates, @{ $cvar_date_fields });
1141   }
1142
1143   while (my ($precision, $field_list) = each %{ $cvar_number_fields }) {
1144     reformat_numbers($output_numberformat, $precision, @{ $field_list });
1145   }
1146
1147   $form->{excel} = 1;
1148   my $extension            = 'xls';
1149
1150   $form->{IN}         = "$form->{formname}.${extension}";
1151
1152   delete $form->{OUT};
1153
1154   $form->parse_template($myconfig);
1155
1156   $main::lxdebug->leave_sub();
1157 }
1158
1159 sub search_contacts {
1160   $::lxdebug->enter_sub;
1161
1162   my $self      = shift;
1163   my %params    = @_;
1164
1165   my $dbh       = $params{dbh} || $::form->get_standard_dbh;
1166   my $vc        = $params{db} eq 'customer' ? 'customer' : 'vendor';
1167
1168   my %sortspecs = (
1169     'cp_name'   => 'cp_name, cp_givenname',
1170     'vcname'    => 'vcname, cp_name, cp_givenname',
1171     'vcnumber'  => 'vcnumber, cp_name, cp_givenname',
1172     );
1173
1174   my %sortcols  = map { $_ => 1 } qw(cp_name cp_givenname cp_phone1 cp_phone2 cp_mobile1 cp_email cp_street cp_zipcode cp_city vcname vcnumber);
1175
1176   my $order_by  = $sortcols{$::form->{sort}} ? $::form->{sort} : 'cp_name';
1177   $::form->{sort} = $order_by;
1178   $order_by     = $sortspecs{$order_by} if ($sortspecs{$order_by});
1179
1180   my $sortdir   = $::form->{sortdir} ? 'ASC' : 'DESC';
1181   $order_by     =~ s/,/ ${sortdir},/g;
1182   $order_by    .= " $sortdir";
1183
1184   my @where_tokens = ();
1185   my @values;
1186
1187   if ($params{search_term}) {
1188     my @tokens;
1189     push @tokens,
1190       'cp.cp_name      ILIKE ?',
1191       'cp.cp_givenname ILIKE ?',
1192       'cp.cp_email     ILIKE ?';
1193     push @values, ('%' . $params{search_term} . '%') x 3;
1194
1195     if (($params{search_term} =~ m/\d/) && ($params{search_term} !~ m/[^\d \(\)+\-]/)) {
1196       my $number =  $params{search_term};
1197       $number    =~ s/[^\d]//g;
1198       $number    =  join '[ /\(\)+\-]*', split(m//, $number);
1199
1200       push @tokens, map { "($_ ~ '$number')" } qw(cp_phone1 cp_phone2 cp_mobile1 cp_mobile2);
1201     }
1202
1203     push @where_tokens, map { "($_)" } join ' OR ', @tokens;
1204   }
1205
1206   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'Contacts',
1207                                                             'trans_id_field' => 'cp.cp_id',
1208                                                             'filter'         => $params{filter});
1209
1210   if ($cvar_where) {
1211     push @where_tokens, $cvar_where;
1212     push @values, @cvar_values;
1213   }
1214
1215   if (my $filter = $params{filter}) {
1216     for (qw(name title givenname email project abteilung)) {
1217       next unless $filter->{"cp_$_"};
1218       add_token(\@where_tokens, \@values, col =>  "cp.cp_$_", val => $filter->{"cp_$_"}, method => 'ILIKE', esc => 'substr');
1219     }
1220
1221     push @where_tokens, 'cp.cp_cv_id IS NOT NULL' if $filter->{status} eq 'active';
1222     push @where_tokens, 'cp.cp_cv_id IS NULL'     if $filter->{status} eq 'orphaned';
1223   }
1224
1225   my $where = @where_tokens ? 'WHERE ' . join ' AND ', @where_tokens : '';
1226
1227   my $query     = qq|SELECT cp.*,
1228                        COALESCE(c.id,             v.id)           AS vcid,
1229                        COALESCE(c.name,           v.name)         AS vcname,
1230                        COALESCE(c.customernumber, v.vendornumber) AS vcnumber,
1231                        CASE WHEN c.name IS NULL THEN 'vendor' ELSE 'customer' END AS db
1232                      FROM contacts cp
1233                      LEFT JOIN customer c ON (cp.cp_cv_id = c.id)
1234                      LEFT JOIN vendor v   ON (cp.cp_cv_id = v.id)
1235                      $where
1236                      ORDER BY $order_by|;
1237
1238   my $contacts  = selectall_hashref_query($::form, $dbh, $query, @values);
1239
1240   $::lxdebug->leave_sub;
1241
1242   return @{ $contacts };
1243 }
1244
1245
1246 1;