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|taxincluded_checked = ? | .
324     qq|WHERE id = ?|;
325   my @values = (
326     $form->{customernumber},
327     $form->{name},
328     $form->{greeting},
329     $form->{department_1},
330     $form->{department_2},
331     $form->{street},
332     $form->{zipcode},
333     $form->{city},
334     $form->{country},
335     $form->{homepage},
336     $form->{contact},
337     $form->{phone},
338     $form->{fax},
339     $form->{email},
340     $form->{cc},
341     $form->{bcc},
342     $form->{notes},
343     $form->{discount},
344     $form->{creditlimit},
345     conv_i($form->{terms}),
346     conv_i($form->{business}),
347     $form->{taxnumber},
348     $form->{language},
349     $form->{account_number},
350     $form->{bank_code},
351     $form->{bank},
352     $form->{iban},
353     $form->{bic},
354     $form->{obsolete} ? 't' : 'f',
355     $form->{direct_debit} ? 't' : 'f',
356     $form->{ustid},
357     $form->{username},
358     conv_i($form->{salesman_id}),
359     conv_i($form->{language_id}),
360     conv_i($form->{payment_id}),
361     conv_i($form->{taxzone_id}, 0),
362     $form->{user_password},
363     $form->{c_vendor_id},
364     conv_i($form->{klass}),
365     substr($form->{currency}, 0, 3),
366     $form->{taxincluded_checked} ne '' ? $form->{taxincluded_checked} : undef,
367     $form->{id}
368     );
369   do_query( $form, $dbh, $query, @values );
370
371   $form->{cp_id} = $self->_save_contact($form, $dbh);
372
373   # add shipto
374   $form->add_shipto( $dbh, $form->{id}, "CT" );
375
376   $self->_save_note('dbh' => $dbh);
377   $self->_delete_selected_notes('dbh' => $dbh);
378
379   CVar->save_custom_variables('dbh'       => $dbh,
380                               'module'    => 'CT',
381                               'trans_id'  => $form->{id},
382                               'variables' => $form,
383                               'always_valid' => 1);
384   if ($form->{cp_id}) {
385     CVar->save_custom_variables('dbh'       => $dbh,
386                                 'module'    => 'Contacts',
387                                 'trans_id'  => $form->{cp_id},
388                                 'variables' => $form,
389                                 'name_prefix'  => 'cp',
390                                 'always_valid' => 1);
391   }
392
393   my $rc = $dbh->commit();
394
395   $main::lxdebug->leave_sub();
396   return $rc;
397 }
398
399 sub save_vendor {
400   $main::lxdebug->enter_sub();
401
402   my ( $self, $myconfig, $form ) = @_;
403
404   $form->{taxzone_id} *= 1;
405   # connect to database
406   my $dbh = $form->get_standard_dbh;
407
408   map( {
409     $form->{"cp_${_}"} = $form->{"selected_cp_${_}"}
410     if ( $form->{"selected_cp_${_}"} );
411        } qw(title greeting abteilung) );
412   $form->{"greeting"} = $form->{"selected_company_greeting"}
413   if ( $form->{"selected_company_greeting"} );
414
415   $form->{discount} = $form->parse_amount( $myconfig, $form->{discount} );
416   $form->{discount} /= 100;
417   $form->{creditlimit} = $form->parse_amount( $myconfig, $form->{creditlimit} );
418
419   my $query;
420
421   if (!$form->{id}) {
422     $query = qq|SELECT nextval('id')|;
423     ($form->{id}) = selectrow_query($form, $dbh, $query);
424
425     $query = qq|INSERT INTO vendor (id, name) VALUES (?, '')|;
426     do_query($form, $dbh, $query, $form->{id});
427
428     my $vendornumber      = SL::TransNumber->new(type   => 'vendor',
429                                                  dbh    => $dbh,
430                                                  number => $form->{vendornumber},
431                                                  save   => 1);
432     $form->{vendornumber} = $vendornumber->create_unique unless $vendornumber->is_unique;
433   }
434
435   $query =
436     qq|UPDATE vendor SET | .
437     qq|  vendornumber = ?, | .
438     qq|  name = ?, | .
439     qq|  greeting = ?, | .
440     qq|  department_1 = ?, | .
441     qq|  department_2 = ?, | .
442     qq|  street = ?, | .
443     qq|  zipcode = ?, | .
444     qq|  city = ?, | .
445     qq|  country = ?, | .
446     qq|  homepage = ?, | .
447     qq|  contact = ?, | .
448     qq|  phone = ?, | .
449     qq|  fax = ?, | .
450     qq|  email = ?, | .
451     qq|  cc = ?, | .
452     qq|  bcc = ?, | .
453     qq|  notes = ?, | .
454     qq|  terms = ?, | .
455     qq|  discount = ?, | .
456     qq|  creditlimit = ?, | .
457     qq|  business_id = ?, | .
458     qq|  taxnumber = ?, | .
459     qq|  language = ?, | .
460     qq|  account_number = ?, | .
461     qq|  bank_code = ?, | .
462     qq|  bank = ?, | .
463     qq|  iban = ?, | .
464     qq|  bic = ?, | .
465     qq|  obsolete = ?, | .
466     qq|  direct_debit = ?, | .
467     qq|  ustid = ?, | .
468     qq|  payment_id = ?, | .
469     qq|  taxzone_id = ?, | .
470     qq|  language_id = ?, | .
471     qq|  username = ?, | .
472     qq|  user_password = ?, | .
473     qq|  v_customer_id = ?, | .
474     qq|  curr = ? | .
475     qq|WHERE id = ?|;
476   my @values = (
477     $form->{vendornumber},
478     $form->{name},
479     $form->{greeting},
480     $form->{department_1},
481     $form->{department_2},
482     $form->{street},
483     $form->{zipcode},
484     $form->{city},
485     $form->{country},
486     $form->{homepage},
487     $form->{contact},
488     $form->{phone},
489     $form->{fax},
490     $form->{email},
491     $form->{cc},
492     $form->{bcc},
493     $form->{notes},
494     conv_i($form->{terms}),
495     $form->{discount},
496     $form->{creditlimit},
497     conv_i($form->{business}),
498     $form->{taxnumber},
499     $form->{language},
500     $form->{account_number},
501     $form->{bank_code},
502     $form->{bank},
503     $form->{iban},
504     $form->{bic},
505     $form->{obsolete} ? 't' : 'f',
506     $form->{direct_debit} ? 't' : 'f',
507     $form->{ustid},
508     conv_i($form->{payment_id}),
509     conv_i($form->{taxzone_id}, 0),
510     conv_i( $form->{language_id}),
511     $form->{username},
512     $form->{user_password},
513     $form->{v_customer_id},
514     substr($form->{currency}, 0, 3),
515     $form->{id}
516     );
517   do_query($form, $dbh, $query, @values);
518
519   $form->{cp_id} = $self->_save_contact($form, $dbh);
520
521   # add shipto
522   $form->add_shipto( $dbh, $form->{id}, "CT" );
523
524   $self->_save_note('dbh' => $dbh);
525   $self->_delete_selected_notes('dbh' => $dbh);
526
527   CVar->save_custom_variables('dbh'       => $dbh,
528                               'module'    => 'CT',
529                               'trans_id'  => $form->{id},
530                               'variables' => $form,
531                               'always_valid' => 1);
532   if ($form->{cp_id}) {
533     CVar->save_custom_variables('dbh'       => $dbh,
534                                 'module'    => 'Contacts',
535                                 'trans_id'  => $form->{cp_id},
536                                 'variables' => $form,
537                                 'name_prefix'  => 'cp',
538                                 'always_valid' => 1);
539   }
540
541   my $rc = $dbh->commit();
542
543   $main::lxdebug->leave_sub();
544   return $rc;
545 }
546
547 sub _save_contact {
548   my ($self, $form, $dbh) = @_;
549
550   return undef unless $form->{cp_id} || $form->{cp_name} || $form->{cp_givenname};
551
552   my @columns = qw(cp_title cp_givenname cp_name cp_email cp_phone1 cp_phone2 cp_abteilung cp_fax
553                    cp_mobile1 cp_mobile2 cp_satphone cp_satfax cp_project cp_privatphone cp_privatemail cp_birthday cp_gender
554                    cp_street cp_zipcode cp_city);
555   my @values  = map { $_ eq 'cp_gender' ? ($form->{$_} eq 'f' ? 'f' : 'm') : $form->{$_} } @columns;
556
557   my ($query, $cp_id);
558   if ($form->{cp_id}) {
559     $query = qq|UPDATE contacts SET | . join(', ', map { "${_} = ?" } @columns) . qq| WHERE cp_id = ?|;
560     push @values, $form->{cp_id};
561     $cp_id = $form->{cp_id};
562
563   } else {
564     ($cp_id) = selectrow_query($form, $dbh, qq|SELECT nextval('id')|);
565
566     $query = qq|INSERT INTO contacts (| . join(', ', @columns, 'cp_cv_id', 'cp_id') . qq|) VALUES (| . join(', ', ('?') x (2 + scalar @columns)) . qq|)|;
567     push @values, $form->{id}, $cp_id;
568   }
569
570   do_query($form, $dbh, $query, @values);
571
572   return $cp_id;
573 }
574
575 sub delete {
576   $main::lxdebug->enter_sub();
577
578   my ( $self, $myconfig, $form ) = @_;
579   # connect to database
580   my $dbh = $form->dbconnect($myconfig);
581
582   # delete vendor
583   my $cv = $form->{db} eq "customer" ? "customer" : "vendor";
584   my $query = qq|DELETE FROM $cv WHERE id = ?|;
585   do_query($form, $dbh, $query, $form->{id});
586
587   $dbh->disconnect;
588
589   $main::lxdebug->leave_sub();
590 }
591
592 sub search {
593   $main::lxdebug->enter_sub();
594
595   my ( $self, $myconfig, $form ) = @_;
596
597   # connect to database
598   my $dbh = $form->dbconnect($myconfig);
599
600   my $cv = $form->{db} eq "customer" ? "customer" : "vendor";
601
602   my $where = "1 = 1";
603   my @values;
604
605   my %allowed_sort_columns =
606     map { $_, 1 } qw(
607       id customernumber vendornumber name contact phone fax email street
608       taxnumber business invnumber ordnumber quonumber zipcode city
609     );
610   my $sortorder    = $form->{sort} && $allowed_sort_columns{$form->{sort}} ? $form->{sort} : "name";
611   $form->{sort} = $sortorder;
612   my $sortdir   = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
613
614   if ($sortorder !~ /(business|id)/ && 1 >= scalar grep { $form->{$_} } qw(l_ordnumber l_quonumber l_invnumber )) {
615     $sortorder  = "lower($sortorder) ${sortdir}";
616   } else {
617     $sortorder .= " ${sortdir}";
618   }
619
620   if ($form->{"${cv}number"}) {
621     $where .= " AND ct.${cv}number ILIKE ?";
622     push(@values, '%' . $form->{"${cv}number"} . '%');
623   }
624
625   foreach my $key (qw(name contact email)) {
626     if ($form->{$key}) {
627       $where .= " AND ct.$key ILIKE ?";
628       push(@values, '%' . $form->{$key} . '%');
629     }
630   }
631
632   if ($form->{cp_name}) {
633     $where .= " AND ct.id IN (SELECT cp_cv_id FROM contacts WHERE lower(cp_name) LIKE lower(?))";
634     push @values, '%' . $form->{cp_name} . '%';
635   }
636
637   if ($form->{addr_city}) {
638     $where .= " AND ((lower(ct.city) LIKE lower(?))
639                      OR
640                      (ct.id IN (
641                         SELECT trans_id
642                         FROM shipto
643                         WHERE (module = 'CT')
644                           AND (lower(shiptocity) LIKE lower(?))
645                       ))
646                      )";
647     push @values, ('%' . $form->{addr_city} . '%') x 2;
648   }
649
650   if ( $form->{status} eq 'orphaned' ) {
651     $where .=
652       qq| AND ct.id NOT IN | .
653       qq|   (SELECT o.${cv}_id FROM oe o, $cv cv WHERE cv.id = o.${cv}_id)|;
654     if ($cv eq 'customer') {
655       $where .=
656         qq| AND ct.id NOT IN | .
657         qq| (SELECT a.customer_id FROM ar a, customer cv | .
658         qq|  WHERE cv.id = a.customer_id)|;
659     }
660     if ($cv eq 'vendor') {
661       $where .=
662         qq| AND ct.id NOT IN | .
663         qq| (SELECT a.vendor_id FROM ap a, vendor cv | .
664         qq|  WHERE cv.id = a.vendor_id)|;
665     }
666     $form->{l_invnumber} = $form->{l_ordnumber} = $form->{l_quonumber} = "";
667   }
668
669   if ($form->{obsolete} eq "Y") {
670     $where .= qq| AND obsolete|;
671   } elsif ($form->{obsolete} eq "N") {
672     $where .= qq| AND NOT obsolete|;
673   }
674
675   if ($form->{business_id}) {
676     $where .= qq| AND (business_id = ?)|;
677     push(@values, conv_i($form->{business_id}));
678   }
679
680   # Nur Kunden finden, bei denen ich selber der Verkäufer bin
681   # Gilt nicht für Lieferanten
682   if ($cv eq 'customer' &&   !$main::auth->assert('customer_vendor_all_edit', 1)) {
683     $where .= qq| AND ct.salesman_id = (select id from employee where login= ?)|;
684     push(@values, $form->{login});
685   }
686
687   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'CT',
688                                                             'trans_id_field' => 'ct.id',
689                                                             'filter'         => $form);
690
691   if ($cvar_where) {
692     $where .= qq| AND ($cvar_where)|;
693     push @values, @cvar_values;
694   }
695
696   if ($form->{addr_street}) {
697     $where .= qq| AND (street ILIKE ?)|;
698     push @values, '%' . $form->{addr_street} . '%';
699   }
700
701   if ($form->{addr_zipcode}) {
702     $where .= qq| AND (zipcode ILIKE ?)|;
703     push @values, $form->{addr_zipcode} . '%';
704   }
705
706   my $query =
707     qq|SELECT ct.*, b.description AS business | .
708     qq|FROM $cv ct | .
709     qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
710     qq|WHERE $where|;
711
712   my @saved_values = @values;
713   # redo for invoices, orders and quotations
714   if ($form->{l_invnumber} || $form->{l_ordnumber} || $form->{l_quonumber}) {
715     my ($ar, $union, $module);
716     $query = "";
717
718     if ($form->{l_invnumber}) {
719       my $ar = $cv eq 'customer' ? 'ar' : 'ap';
720       my $module = $ar eq 'ar' ? 'is' : 'ir';
721
722       $query =
723         qq|SELECT ct.*, b.description AS business, | .
724         qq|  a.invnumber, a.ordnumber, a.quonumber, a.id AS invid, | .
725         qq|  '$module' AS module, 'invoice' AS formtype, | .
726         qq|  (a.amount = a.paid) AS closed | .
727         qq|FROM $cv ct | .
728         qq|JOIN $ar a ON (a.${cv}_id = ct.id) | .
729         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
730         qq|WHERE $where AND (a.invoice = '1')|;
731
732       $union = qq|UNION|;
733     }
734
735     if ( $form->{l_ordnumber} ) {
736       if ($union eq "UNION") {
737         push(@values, @saved_values);
738       }
739       $query .=
740         qq| $union | .
741         qq|SELECT ct.*, b.description AS business,| .
742         qq|  ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
743         qq|  'oe' AS module, 'order' AS formtype, o.closed | .
744         qq|FROM $cv ct | .
745         qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
746         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
747         qq|WHERE $where AND (o.quotation = '0')|;
748
749       $union = qq|UNION|;
750     }
751
752     if ( $form->{l_quonumber} ) {
753       if ($union eq "UNION") {
754         push(@values, @saved_values);
755       }
756       $query .=
757         qq| $union | .
758         qq|SELECT ct.*, b.description AS business, | .
759         qq|  ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
760         qq|  'oe' AS module, 'quotation' AS formtype, o.closed | .
761         qq|FROM $cv ct | .
762         qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
763         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
764         qq|WHERE $where AND (o.quotation = '1')|;
765     }
766   }
767
768   $query .= qq| ORDER BY $sortorder|;
769
770   $form->{CT} = selectall_hashref_query($form, $dbh, $query, @values);
771
772   $main::lxdebug->leave_sub();
773 }
774
775 sub get_contact {
776   $main::lxdebug->enter_sub();
777
778   my ( $self, $myconfig, $form ) = @_;
779
780   die 'Missing argument: cp_id' unless $::form->{cp_id};
781
782   my $dbh   = $form->dbconnect($myconfig);
783   my $query =
784     qq|SELECT * FROM contacts c | .
785     qq|WHERE cp_id = ? ORDER BY cp_id limit 1|;
786   my $sth = prepare_execute_query($form, $dbh, $query, $form->{cp_id});
787   my $ref = $sth->fetchrow_hashref("NAME_lc");
788
789   map { $form->{$_} = $ref->{$_} } keys %$ref;
790
791   $query = qq|SELECT COUNT(cp_id) AS used FROM (
792     SELECT cp_id FROM oe UNION
793     SELECT cp_id FROM ar UNION
794     SELECT cp_id FROM ap UNION
795     SELECT cp_id FROM delivery_orders
796   ) AS cpid WHERE cp_id = ? OR ? = 0|;
797   ($form->{cp_used}) = selectfirst_array_query($form, $dbh, $query, ($form->{cp_id})x2);
798
799   $sth->finish;
800   $dbh->disconnect;
801
802   $main::lxdebug->leave_sub();
803 }
804
805 sub get_shipto {
806   $main::lxdebug->enter_sub();
807
808   my ( $self, $myconfig, $form ) = @_;
809   my $dbh   = $form->dbconnect($myconfig);
810   my $query = qq|SELECT * FROM shipto WHERE shipto_id = ?|;
811   my $sth = prepare_execute_query($form, $dbh, $query, $form->{shipto_id});
812
813   my $ref = $sth->fetchrow_hashref("NAME_lc");
814
815   map { $form->{$_} = $ref->{$_} } keys %$ref;
816
817   $query = qq|SELECT COUNT(shipto_id) AS used FROM (
818     SELECT shipto_id FROM oe UNION
819     SELECT shipto_id FROM ar UNION
820     SELECT shipto_id FROM delivery_orders
821   ) AS stid WHERE shipto_id = ? OR ? = 0|;
822   ($form->{shiptoused}) = selectfirst_array_query($form, $dbh, $query, ($form->{shipto_id})x2);
823
824   $sth->finish;
825   $dbh->disconnect;
826
827   $main::lxdebug->leave_sub();
828 }
829
830 sub get_delivery {
831   $main::lxdebug->enter_sub();
832
833   my ( $self, $myconfig, $form ) = @_;
834   my $dbh = $form->dbconnect($myconfig);
835
836   my $arap = $form->{db} eq "vendor" ? "ap" : "ar";
837   my $db = $form->{db} eq "customer" ? "customer" : "vendor";
838   my $qty_sign = $form->{db} eq 'vendor' ? ' * -1 AS qty' : '';
839
840   my $where = " WHERE 1=1 ";
841   my @values;
842
843   if ($form->{shipto_id} && ($arap eq "ar")) {
844     $where .= "AND ${arap}.shipto_id = ?";
845     push(@values, $form->{shipto_id});
846   } else {
847     $where .= "AND ${arap}.${db}_id = ?";
848     push(@values, $form->{id});
849   }
850
851   if ($form->{from}) {
852     $where .= "AND ${arap}.transdate >= ?";
853     push(@values, conv_date($form->{from}));
854   }
855   if ($form->{to}) {
856     $where .= "AND ${arap}.transdate <= ?";
857     push(@values, conv_date($form->{to}));
858   }
859   my $query =
860     qq|SELECT s.shiptoname, i.qty $qty_sign, | .
861     qq|  ${arap}.id, ${arap}.transdate, ${arap}.invnumber, ${arap}.ordnumber, | .
862     qq|  i.description, i.unit, i.sellprice, | .
863     qq|  oe.id AS oe_id, invoice | .
864     qq|FROM $arap | .
865     qq|LEFT JOIN shipto s ON | .
866     ($arap eq "ar"
867      ? qq|(ar.shipto_id = s.shipto_id) |
868      : qq|(ap.id = s.trans_id) |) .
869     qq|LEFT JOIN invoice i ON (${arap}.id = i.trans_id) | .
870     qq|LEFT join parts p ON (p.id = i.parts_id) | .
871     qq|LEFT JOIN oe ON (oe.ordnumber = ${arap}.ordnumber AND NOT ${arap}.ordnumber = '') | .
872     $where .
873     qq|ORDER BY ${arap}.transdate DESC LIMIT 15|;
874
875   $form->{DELIVERY} = selectall_hashref_query($form, $dbh, $query, @values);
876
877   $dbh->disconnect;
878
879   $main::lxdebug->leave_sub();
880 }
881
882 sub _save_note {
883   $main::lxdebug->enter_sub();
884
885   my $self   = shift;
886   my %params = @_;
887
888   my $form   = $main::form;
889
890   Common::check_params(\%params, 'dbh');
891
892   if (!$form->{NOTE_subject}) {
893     $main::lxdebug->leave_sub();
894     return;
895   }
896
897   my $dbh = $params{dbh};
898
899   my %follow_up;
900   my %note = (
901     'id'           => $form->{NOTE_id},
902     'subject'      => $form->{NOTE_subject},
903     'body'         => $form->{NOTE_body},
904     'trans_id'     => $form->{id},
905     'trans_module' => 'ct',
906   );
907
908   $note{id} = Notes->save(%note);
909
910   if ($form->{FU_date}) {
911     %follow_up = (
912       'id'               => $form->{FU_id},
913       'note_id'          => $note{id},
914       'follow_up_date'   => $form->{FU_date},
915       'created_for_user' => $form->{FU_created_for_user},
916       'done'             => $form->{FU_done} ? 1 : 0,
917       'subject'          => $form->{NOTE_subject},
918       'body'             => $form->{NOTE_body},
919       'LINKS'            => [
920         {
921           'trans_id'     => $form->{id},
922           'trans_type'   => $form->{db} eq 'customer' ? 'customer' : 'vendor',
923           'trans_info'   => $form->{name},
924         },
925       ],
926     );
927
928     $follow_up{id} = FU->save(%follow_up);
929
930   } elsif ($form->{FU_id}) {
931     do_query($form, $dbh, qq|DELETE FROM follow_up_links WHERE follow_up_id = ?|, conv_i($form->{FU_id}));
932     do_query($form, $dbh, qq|DELETE FROM follow_ups      WHERE id = ?|,           conv_i($form->{FU_id}));
933   }
934
935   delete @{$form}{grep { /^NOTE_|^FU_/ } keys %{ $form }};
936
937   $main::lxdebug->leave_sub();
938 }
939
940 sub _delete_selected_notes {
941   $main::lxdebug->enter_sub();
942
943   my $self   = shift;
944   my %params = @_;
945
946   Common::check_params(\%params, 'dbh');
947
948   my $form = $main::form;
949   my $dbh  = $params{dbh};
950
951   foreach my $i (1 .. $form->{NOTES_rowcount}) {
952     next unless ($form->{"NOTE_delete_$i"} && $form->{"NOTE_id_$i"});
953
954     Notes->delete('dbh' => $params{dbh},
955                   'id'  => $form->{"NOTE_id_$i"});
956   }
957
958   $main::lxdebug->leave_sub();
959 }
960
961 # TODO: remove in 2.7.0 stable
962 sub delete_shipto {
963   $main::lxdebug->enter_sub();
964
965   my $self      = shift;
966   my $shipto_id = shift;
967
968   my $form      = $main::form;
969   my %myconfig  = %main::myconfig;
970   my $dbh       = $form->get_standard_dbh(\%myconfig);
971
972   do_query($form, $dbh, qq|UPDATE shipto SET trans_id = NULL WHERE shipto_id = ?|, $shipto_id);
973
974   $dbh->commit();
975
976   $main::lxdebug->leave_sub();
977 }
978
979 # TODO: remove in 2.7.0 stable
980 sub delete_contact {
981   $main::lxdebug->enter_sub();
982
983   my $self      = shift;
984   my $cp_id     = shift;
985
986   my $form      = $main::form;
987   my %myconfig  = %main::myconfig;
988   my $dbh       = $form->get_standard_dbh(\%myconfig);
989
990   do_query($form, $dbh, qq|UPDATE contacts SET cp_cv_id = NULL WHERE cp_id = ?|, $cp_id);
991
992   $dbh->commit();
993
994   $main::lxdebug->leave_sub();
995 }
996
997 sub get_bank_info {
998   $main::lxdebug->enter_sub();
999
1000   my $self     = shift;
1001   my %params   = @_;
1002
1003   Common::check_params(\%params, qw(vc id));
1004
1005   my $myconfig = \%main::myconfig;
1006   my $form     = $main::form;
1007
1008   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
1009
1010   my $table        = $params{vc} eq 'customer' ? 'customer' : 'vendor';
1011   my @ids          = ref $params{id} eq 'ARRAY' ? @{ $params{id} } : ($params{id});
1012   my $placeholders = join ", ", ('?') x scalar @ids;
1013   my $query        = qq|SELECT id, name, account_number, bank, bank_code, iban, bic
1014                         FROM ${table}
1015                         WHERE id IN (${placeholders})|;
1016
1017   my $result       = selectall_hashref_query($form, $dbh, $query, map { conv_i($_) } @ids);
1018
1019   if (ref $params{id} eq 'ARRAY') {
1020     $result = { map { $_->{id} => $_ } @{ $result } };
1021   } else {
1022     $result = $result->[0] || { 'id' => $params{id} };
1023   }
1024
1025   $main::lxdebug->leave_sub();
1026
1027   return $result;
1028 }
1029
1030 sub parse_excel_file {
1031   $main::lxdebug->enter_sub();
1032
1033   my ($self, $myconfig, $form) = @_;
1034   my $locale = $main::locale;
1035
1036   $form->{formname}   = 'sales_quotation';
1037   $form->{type}   = 'sales_quotation';
1038   $form->{format} = 'excel';
1039   $form->{media}  = 'screen';
1040   $form->{quonumber} = 1;
1041
1042
1043   # $form->{"notes"} will be overridden by the customer's/vendor's "notes" field. So save it here.
1044   $form->{ $form->{"formname"} . "notes" } = $form->{"notes"};
1045
1046   my $inv                  = "quo";
1047   my $due                  = "req";
1048   $form->{"${inv}date"} = $form->{transdate};
1049   $form->{label}        = $locale->text('Quotation');
1050   my $numberfld            = "sqnumber";
1051   my $order                = 1;
1052
1053   # assign number
1054   $form->{what_done} = $form->{formname};
1055
1056   map({ delete($form->{$_}); } grep(/^cp_/, keys(%{ $form })));
1057
1058   my $output_dateformat = $myconfig->{"dateformat"};
1059   my $output_numberformat = $myconfig->{"numberformat"};
1060   my $output_longdates = 1;
1061
1062   # map login user variables
1063   map { $form->{"login_$_"} = $myconfig->{$_} } ("name", "email", "fax", "tel", "company");
1064
1065   # format item dates
1066   for my $field (qw(transdate_oe deliverydate_oe)) {
1067     map {
1068       $form->{$field}[$_] = $locale->date($myconfig, $form->{$field}[$_], 1);
1069     } 0 .. $#{ $form->{$field} };
1070   }
1071
1072   if ($form->{shipto_id}) {
1073     $form->get_shipto($myconfig);
1074   }
1075
1076   $form->{notes} =~ s/^\s+//g;
1077
1078   $form->{templates} = $myconfig->{templates};
1079
1080   delete $form->{printer_command};
1081
1082   $form->get_employee_info($myconfig);
1083
1084   my ($cvar_date_fields, $cvar_number_fields) = CVar->get_field_format_list('module' => 'CT', 'prefix' => 'vc_');
1085
1086   if (scalar @{ $cvar_date_fields }) {
1087     format_dates($output_dateformat, $output_longdates, @{ $cvar_date_fields });
1088   }
1089
1090   while (my ($precision, $field_list) = each %{ $cvar_number_fields }) {
1091     reformat_numbers($output_numberformat, $precision, @{ $field_list });
1092   }
1093
1094   $form->{excel} = 1;
1095   my $extension            = 'xls';
1096
1097   $form->{IN}         = "$form->{formname}.${extension}";
1098
1099   delete $form->{OUT};
1100
1101   $form->parse_template($myconfig);
1102
1103   $main::lxdebug->leave_sub();
1104 }
1105
1106 sub search_contacts {
1107   $::lxdebug->enter_sub;
1108
1109   my $self      = shift;
1110   my %params    = @_;
1111
1112   my $dbh       = $params{dbh} || $::form->get_standard_dbh;
1113   my $vc        = $params{db} eq 'customer' ? 'customer' : 'vendor';
1114
1115   my %sortspecs = (
1116     'cp_name'   => 'cp_name, cp_givenname',
1117     'vcname'    => 'vcname, cp_name, cp_givenname',
1118     'vcnumber'  => 'vcnumber, cp_name, cp_givenname',
1119     );
1120
1121   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);
1122
1123   my $order_by  = $sortcols{$::form->{sort}} ? $::form->{sort} : 'cp_name';
1124   $::form->{sort} = $order_by;
1125   $order_by     = $sortspecs{$order_by} if ($sortspecs{$order_by});
1126
1127   my $sortdir   = $::form->{sortdir} ? 'ASC' : 'DESC';
1128   $order_by     =~ s/,/ ${sortdir},/g;
1129   $order_by    .= " $sortdir";
1130
1131   my @where_tokens = ();
1132   my @values;
1133
1134   if ($params{search_term}) {
1135     my @tokens;
1136     push @tokens,
1137       'cp.cp_name      ILIKE ?',
1138       'cp.cp_givenname ILIKE ?',
1139       'cp.cp_email     ILIKE ?';
1140     push @values, ('%' . $params{search_term} . '%') x 3;
1141
1142     if (($params{search_term} =~ m/\d/) && ($params{search_term} !~ m/[^\d \(\)+\-]/)) {
1143       my $number =  $params{search_term};
1144       $number    =~ s/[^\d]//g;
1145       $number    =  join '[ /\(\)+\-]*', split(m//, $number);
1146
1147       push @tokens, map { "($_ ~ '$number')" } qw(cp_phone1 cp_phone2 cp_mobile1 cp_mobile2);
1148     }
1149
1150     push @where_tokens, map { "($_)" } join ' OR ', @tokens;
1151   }
1152
1153   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'Contacts',
1154                                                             'trans_id_field' => 'cp.cp_id',
1155                                                             'filter'         => $params{filter});
1156
1157   if ($cvar_where) {
1158     push @where_tokens, $cvar_where;
1159     push @values, @cvar_values;
1160   }
1161
1162   if (my $filter = $params{filter}) {
1163     for (qw(name title givenname email project abteilung)) {
1164       next unless $filter->{"cp_$_"};
1165       add_token(\@where_tokens, \@values, col =>  "cp.cp_$_", val => $filter->{"cp_$_"}, method => 'ILIKE', esc => 'substr');
1166     }
1167
1168     push @where_tokens, 'cp.cp_cv_id IS NOT NULL' if $filter->{status} eq 'active';
1169     push @where_tokens, 'cp.cp_cv_id IS NULL'     if $filter->{status} eq 'orphaned';
1170   }
1171
1172   my $where = @where_tokens ? 'WHERE ' . join ' AND ', @where_tokens : '';
1173
1174   my $query     = qq|SELECT cp.*,
1175                        COALESCE(c.id,             v.id)           AS vcid,
1176                        COALESCE(c.name,           v.name)         AS vcname,
1177                        COALESCE(c.customernumber, v.vendornumber) AS vcnumber,
1178                        CASE WHEN c.name IS NULL THEN 'vendor' ELSE 'customer' END AS db
1179                      FROM contacts cp
1180                      LEFT JOIN customer c ON (cp.cp_cv_id = c.id)
1181                      LEFT JOIN vendor v   ON (cp.cp_cv_id = v.id)
1182                      $where
1183                      ORDER BY $order_by|;
1184
1185   my $contacts  = selectall_hashref_query($::form, $dbh, $query, @values);
1186
1187   $::lxdebug->leave_sub;
1188
1189   return @{ $contacts };
1190 }
1191
1192
1193 1;