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(
556     {
557       if ( $_ eq 'cp_gender' ) {
558         $form->{$_} eq 'f' ? 'f' : 'm';
559       } elsif ( $_ eq 'cp_birthday' && $form->{cp_birthday} eq '' ) {
560         undef;
561       } else {
562         $form->{$_};
563       }
564     }
565     @columns
566   );
567
568   my ($query, $cp_id);
569   if ($form->{cp_id}) {
570     $query = qq|UPDATE contacts SET | . join(', ', map { "${_} = ?" } @columns) . qq| WHERE cp_id = ?|;
571     push @values, $form->{cp_id};
572     $cp_id = $form->{cp_id};
573
574   } else {
575     ($cp_id) = selectrow_query($form, $dbh, qq|SELECT nextval('id')|);
576
577     $query = qq|INSERT INTO contacts (| . join(', ', @columns, 'cp_cv_id', 'cp_id') . qq|) VALUES (| . join(', ', ('?') x (2 + scalar @columns)) . qq|)|;
578     push @values, $form->{id}, $cp_id;
579   }
580
581   do_query($form, $dbh, $query, @values);
582
583   return $cp_id;
584 }
585
586 sub delete {
587   $main::lxdebug->enter_sub();
588
589   my ( $self, $myconfig, $form ) = @_;
590   # connect to database
591   my $dbh = $form->dbconnect($myconfig);
592
593   # delete vendor
594   my $cv = $form->{db} eq "customer" ? "customer" : "vendor";
595   my $query = qq|DELETE FROM $cv WHERE id = ?|;
596   do_query($form, $dbh, $query, $form->{id});
597
598   $dbh->disconnect;
599
600   $main::lxdebug->leave_sub();
601 }
602
603 sub search {
604   $main::lxdebug->enter_sub();
605
606   my ( $self, $myconfig, $form ) = @_;
607
608   # connect to database
609   my $dbh = $form->dbconnect($myconfig);
610
611   my $cv = $form->{db} eq "customer" ? "customer" : "vendor";
612   my $join_records = $form->{l_invnumber} || $form->{l_ordnumber} || $form->{l_quonumber};
613
614   my $where = "1 = 1";
615   my @values;
616
617   my %allowed_sort_columns =
618     map { $_, 1 } qw(
619       id customernumber vendornumber name contact phone fax email street
620       taxnumber business invnumber ordnumber quonumber zipcode city
621     );
622   my $sortorder    = $form->{sort} && $allowed_sort_columns{$form->{sort}} ? $form->{sort} : "name";
623   $form->{sort} = $sortorder;
624   my $sortdir   = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
625
626   if ($sortorder !~ /(business|id)/ && !$join_records) {
627     $sortorder  = "lower($sortorder) ${sortdir}";
628   } else {
629     $sortorder .= " ${sortdir}";
630   }
631
632   if ($form->{"${cv}number"}) {
633     $where .= " AND ct.${cv}number ILIKE ?";
634     push(@values, '%' . $form->{"${cv}number"} . '%');
635   }
636
637   foreach my $key (qw(name contact email)) {
638     if ($form->{$key}) {
639       $where .= " AND ct.$key ILIKE ?";
640       push(@values, '%' . $form->{$key} . '%');
641     }
642   }
643
644   if ($form->{cp_name}) {
645     $where .= " AND ct.id IN (SELECT cp_cv_id FROM contacts WHERE lower(cp_name) LIKE lower(?))";
646     push @values, '%' . $form->{cp_name} . '%';
647   }
648
649   if ($form->{addr_city}) {
650     $where .= " AND ((lower(ct.city) LIKE lower(?))
651                      OR
652                      (ct.id IN (
653                         SELECT trans_id
654                         FROM shipto
655                         WHERE (module = 'CT')
656                           AND (lower(shiptocity) LIKE lower(?))
657                       ))
658                      )";
659     push @values, ('%' . $form->{addr_city} . '%') x 2;
660   }
661
662   if ( $form->{status} eq 'orphaned' ) {
663     $where .=
664       qq| AND ct.id NOT IN | .
665       qq|   (SELECT o.${cv}_id FROM oe o, $cv cv WHERE cv.id = o.${cv}_id)|;
666     if ($cv eq 'customer') {
667       $where .=
668         qq| AND ct.id NOT IN | .
669         qq| (SELECT a.customer_id FROM ar a, customer cv | .
670         qq|  WHERE cv.id = a.customer_id)|;
671     }
672     if ($cv eq 'vendor') {
673       $where .=
674         qq| AND ct.id NOT IN | .
675         qq| (SELECT a.vendor_id FROM ap a, vendor cv | .
676         qq|  WHERE cv.id = a.vendor_id)|;
677     }
678     $form->{l_invnumber} = $form->{l_ordnumber} = $form->{l_quonumber} = "";
679   }
680
681   if ($form->{obsolete} eq "Y") {
682     $where .= qq| AND obsolete|;
683   } elsif ($form->{obsolete} eq "N") {
684     $where .= qq| AND NOT obsolete|;
685   }
686
687   if ($form->{business_id}) {
688     $where .= qq| AND (business_id = ?)|;
689     push(@values, conv_i($form->{business_id}));
690   }
691
692   # Nur Kunden finden, bei denen ich selber der Verkäufer bin
693   # Gilt nicht für Lieferanten
694   if ($cv eq 'customer' &&   !$main::auth->assert('customer_vendor_all_edit', 1)) {
695     $where .= qq| AND ct.salesman_id = (select id from employee where login= ?)|;
696     push(@values, $form->{login});
697   }
698
699   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'CT',
700                                                             'trans_id_field' => 'ct.id',
701                                                             'filter'         => $form);
702
703   if ($cvar_where) {
704     $where .= qq| AND ($cvar_where)|;
705     push @values, @cvar_values;
706   }
707
708   if ($form->{addr_street}) {
709     $where .= qq| AND (street ILIKE ?)|;
710     push @values, '%' . $form->{addr_street} . '%';
711   }
712
713   if ($form->{addr_zipcode}) {
714     $where .= qq| AND (zipcode ILIKE ?)|;
715     push @values, $form->{addr_zipcode} . '%';
716   }
717
718   my $query =
719     qq|SELECT ct.*, b.description AS business | .
720     (qq|, NULL AS invnumber, NULL AS ordnumber, NULL AS quonumber, NULL AS invid, NULL AS module, NULL AS formtype, NULL AS closed | x!! $join_records) .
721     qq|FROM $cv ct | .
722     qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
723     qq|WHERE $where|;
724
725   my @saved_values = @values;
726   # redo for invoices, orders and quotations
727   if ($join_records) {
728     my $union = "UNION";
729
730     if ($form->{l_invnumber}) {
731       my $ar = $cv eq 'customer' ? 'ar' : 'ap';
732       my $module = $ar eq 'ar' ? 'is' : 'ir';
733       push(@values, @saved_values);
734       $query .=
735         qq| UNION | .
736         qq|SELECT ct.*, b.description AS business, | .
737         qq|  a.invnumber, a.ordnumber, a.quonumber, a.id AS invid, | .
738         qq|  '$module' AS module, 'invoice' AS formtype, | .
739         qq|  (a.amount = a.paid) AS closed | .
740         qq|FROM $cv ct | .
741         qq|JOIN $ar a ON (a.${cv}_id = ct.id) | .
742         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
743         qq|WHERE $where AND (a.invoice = '1')|;
744     }
745
746     if ( $form->{l_ordnumber} ) {
747       push(@values, @saved_values);
748       $query .=
749         qq| UNION | .
750         qq|SELECT ct.*, b.description AS business,| .
751         qq|  ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
752         qq|  'oe' AS module, 'order' AS formtype, o.closed | .
753         qq|FROM $cv ct | .
754         qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
755         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
756         qq|WHERE $where AND (o.quotation = '0')|;
757     }
758
759     if ( $form->{l_quonumber} ) {
760       push(@values, @saved_values);
761       $query .=
762         qq| UNION | .
763         qq|SELECT ct.*, b.description AS business, | .
764         qq|  ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
765         qq|  'oe' AS module, 'quotation' AS formtype, o.closed | .
766         qq|FROM $cv ct | .
767         qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
768         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
769         qq|WHERE $where AND (o.quotation = '1')|;
770     }
771   }
772
773   $query .= qq| ORDER BY $sortorder|;
774
775   $form->{CT} = selectall_hashref_query($form, $dbh, $query, @values);
776
777   $main::lxdebug->leave_sub();
778 }
779
780 sub get_contact {
781   $main::lxdebug->enter_sub();
782
783   my ( $self, $myconfig, $form ) = @_;
784
785   die 'Missing argument: cp_id' unless $::form->{cp_id};
786
787   my $dbh   = $form->dbconnect($myconfig);
788   my $query =
789     qq|SELECT * FROM contacts c | .
790     qq|WHERE cp_id = ? ORDER BY cp_id limit 1|;
791   my $sth = prepare_execute_query($form, $dbh, $query, $form->{cp_id});
792   my $ref = $sth->fetchrow_hashref("NAME_lc");
793
794   map { $form->{$_} = $ref->{$_} } keys %$ref;
795
796   $query = qq|SELECT COUNT(cp_id) AS used FROM (
797     SELECT cp_id FROM oe UNION
798     SELECT cp_id FROM ar UNION
799     SELECT cp_id FROM ap UNION
800     SELECT cp_id FROM delivery_orders
801   ) AS cpid WHERE cp_id = ? OR ? = 0|;
802   ($form->{cp_used}) = selectfirst_array_query($form, $dbh, $query, ($form->{cp_id})x2);
803
804   $sth->finish;
805   $dbh->disconnect;
806
807   $main::lxdebug->leave_sub();
808 }
809
810 sub get_shipto {
811   $main::lxdebug->enter_sub();
812
813   my ( $self, $myconfig, $form ) = @_;
814   my $dbh   = $form->dbconnect($myconfig);
815   my $query = qq|SELECT * FROM shipto WHERE shipto_id = ?|;
816   my $sth = prepare_execute_query($form, $dbh, $query, $form->{shipto_id});
817
818   my $ref = $sth->fetchrow_hashref("NAME_lc");
819
820   map { $form->{$_} = $ref->{$_} } keys %$ref;
821
822   $query = qq|SELECT COUNT(shipto_id) AS used FROM (
823     SELECT shipto_id FROM oe UNION
824     SELECT shipto_id FROM ar UNION
825     SELECT shipto_id FROM delivery_orders
826   ) AS stid WHERE shipto_id = ? OR ? = 0|;
827   ($form->{shiptoused}) = selectfirst_array_query($form, $dbh, $query, ($form->{shipto_id})x2);
828
829   $sth->finish;
830   $dbh->disconnect;
831
832   $main::lxdebug->leave_sub();
833 }
834
835 sub get_delivery {
836   $main::lxdebug->enter_sub();
837
838   my ( $self, $myconfig, $form ) = @_;
839   my $dbh = $form->dbconnect($myconfig);
840
841   my $arap = $form->{db} eq "vendor" ? "ap" : "ar";
842   my $db = $form->{db} eq "customer" ? "customer" : "vendor";
843   my $qty_sign = $form->{db} eq 'vendor' ? ' * -1 AS qty' : '';
844
845   my $where = " WHERE 1=1 ";
846   my @values;
847
848   if ($form->{shipto_id} && ($arap eq "ar")) {
849     $where .= "AND ${arap}.shipto_id = ?";
850     push(@values, $form->{shipto_id});
851   } else {
852     $where .= "AND ${arap}.${db}_id = ?";
853     push(@values, $form->{id});
854   }
855
856   if ($form->{from}) {
857     $where .= "AND ${arap}.transdate >= ?";
858     push(@values, conv_date($form->{from}));
859   }
860   if ($form->{to}) {
861     $where .= "AND ${arap}.transdate <= ?";
862     push(@values, conv_date($form->{to}));
863   }
864   my $query =
865     qq|SELECT s.shiptoname, i.qty $qty_sign, | .
866     qq|  ${arap}.id, ${arap}.transdate, ${arap}.invnumber, ${arap}.ordnumber, | .
867     qq|  i.description, i.unit, i.sellprice, | .
868     qq|  oe.id AS oe_id, invoice | .
869     qq|FROM $arap | .
870     qq|LEFT JOIN shipto s ON | .
871     ($arap eq "ar"
872      ? qq|(ar.shipto_id = s.shipto_id) |
873      : qq|(ap.id = s.trans_id) |) .
874     qq|LEFT JOIN invoice i ON (${arap}.id = i.trans_id) | .
875     qq|LEFT join parts p ON (p.id = i.parts_id) | .
876     qq|LEFT JOIN oe ON (oe.ordnumber = ${arap}.ordnumber AND NOT ${arap}.ordnumber = '') | .
877     $where .
878     qq|ORDER BY ${arap}.transdate DESC LIMIT 15|;
879
880   $form->{DELIVERY} = selectall_hashref_query($form, $dbh, $query, @values);
881
882   $dbh->disconnect;
883
884   $main::lxdebug->leave_sub();
885 }
886
887 sub _save_note {
888   $main::lxdebug->enter_sub();
889
890   my $self   = shift;
891   my %params = @_;
892
893   my $form   = $main::form;
894
895   Common::check_params(\%params, 'dbh');
896
897   if (!$form->{NOTE_subject}) {
898     $main::lxdebug->leave_sub();
899     return;
900   }
901
902   my $dbh = $params{dbh};
903
904   my %follow_up;
905   my %note = (
906     'id'           => $form->{NOTE_id},
907     'subject'      => $form->{NOTE_subject},
908     'body'         => $form->{NOTE_body},
909     'trans_id'     => $form->{id},
910     'trans_module' => 'ct',
911   );
912
913   $note{id} = Notes->save(%note);
914
915   if ($form->{FU_date}) {
916     %follow_up = (
917       'id'               => $form->{FU_id},
918       'note_id'          => $note{id},
919       'follow_up_date'   => $form->{FU_date},
920       'created_for_user' => $form->{FU_created_for_user},
921       'done'             => $form->{FU_done} ? 1 : 0,
922       'subject'          => $form->{NOTE_subject},
923       'body'             => $form->{NOTE_body},
924       'LINKS'            => [
925         {
926           'trans_id'     => $form->{id},
927           'trans_type'   => $form->{db} eq 'customer' ? 'customer' : 'vendor',
928           'trans_info'   => $form->{name},
929         },
930       ],
931     );
932
933     $follow_up{id} = FU->save(%follow_up);
934
935   } elsif ($form->{FU_id}) {
936     do_query($form, $dbh, qq|DELETE FROM follow_up_links WHERE follow_up_id = ?|, conv_i($form->{FU_id}));
937     do_query($form, $dbh, qq|DELETE FROM follow_ups      WHERE id = ?|,           conv_i($form->{FU_id}));
938   }
939
940   delete @{$form}{grep { /^NOTE_|^FU_/ } keys %{ $form }};
941
942   $main::lxdebug->leave_sub();
943 }
944
945 sub _delete_selected_notes {
946   $main::lxdebug->enter_sub();
947
948   my $self   = shift;
949   my %params = @_;
950
951   Common::check_params(\%params, 'dbh');
952
953   my $form = $main::form;
954   my $dbh  = $params{dbh};
955
956   foreach my $i (1 .. $form->{NOTES_rowcount}) {
957     next unless ($form->{"NOTE_delete_$i"} && $form->{"NOTE_id_$i"});
958
959     Notes->delete('dbh' => $params{dbh},
960                   'id'  => $form->{"NOTE_id_$i"});
961   }
962
963   $main::lxdebug->leave_sub();
964 }
965
966 # TODO: remove in 2.7.0 stable
967 sub delete_shipto {
968   $main::lxdebug->enter_sub();
969
970   my $self      = shift;
971   my $shipto_id = shift;
972
973   my $form      = $main::form;
974   my %myconfig  = %main::myconfig;
975   my $dbh       = $form->get_standard_dbh(\%myconfig);
976
977   do_query($form, $dbh, qq|UPDATE shipto SET trans_id = NULL WHERE shipto_id = ?|, $shipto_id);
978
979   $dbh->commit();
980
981   $main::lxdebug->leave_sub();
982 }
983
984 # TODO: remove in 2.7.0 stable
985 sub delete_contact {
986   $main::lxdebug->enter_sub();
987
988   my $self      = shift;
989   my $cp_id     = shift;
990
991   my $form      = $main::form;
992   my %myconfig  = %main::myconfig;
993   my $dbh       = $form->get_standard_dbh(\%myconfig);
994
995   do_query($form, $dbh, qq|UPDATE contacts SET cp_cv_id = NULL WHERE cp_id = ?|, $cp_id);
996
997   $dbh->commit();
998
999   $main::lxdebug->leave_sub();
1000 }
1001
1002 sub get_bank_info {
1003   $main::lxdebug->enter_sub();
1004
1005   my $self     = shift;
1006   my %params   = @_;
1007
1008   Common::check_params(\%params, qw(vc id));
1009
1010   my $myconfig = \%main::myconfig;
1011   my $form     = $main::form;
1012
1013   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
1014
1015   my $table        = $params{vc} eq 'customer' ? 'customer' : 'vendor';
1016   my @ids          = ref $params{id} eq 'ARRAY' ? @{ $params{id} } : ($params{id});
1017   my $placeholders = join ", ", ('?') x scalar @ids;
1018   my $query        = qq|SELECT id, name, account_number, bank, bank_code, iban, bic
1019                         FROM ${table}
1020                         WHERE id IN (${placeholders})|;
1021
1022   my $result       = selectall_hashref_query($form, $dbh, $query, map { conv_i($_) } @ids);
1023
1024   if (ref $params{id} eq 'ARRAY') {
1025     $result = { map { $_->{id} => $_ } @{ $result } };
1026   } else {
1027     $result = $result->[0] || { 'id' => $params{id} };
1028   }
1029
1030   $main::lxdebug->leave_sub();
1031
1032   return $result;
1033 }
1034
1035 sub parse_excel_file {
1036   $main::lxdebug->enter_sub();
1037
1038   my ($self, $myconfig, $form) = @_;
1039   my $locale = $main::locale;
1040
1041   $form->{formname}   = 'sales_quotation';
1042   $form->{type}   = 'sales_quotation';
1043   $form->{format} = 'excel';
1044   $form->{media}  = 'screen';
1045   $form->{quonumber} = 1;
1046
1047
1048   # $form->{"notes"} will be overridden by the customer's/vendor's "notes" field. So save it here.
1049   $form->{ $form->{"formname"} . "notes" } = $form->{"notes"};
1050
1051   my $inv                  = "quo";
1052   my $due                  = "req";
1053   $form->{"${inv}date"} = $form->{transdate};
1054   $form->{label}        = $locale->text('Quotation');
1055   my $numberfld            = "sqnumber";
1056   my $order                = 1;
1057
1058   # assign number
1059   $form->{what_done} = $form->{formname};
1060
1061   map({ delete($form->{$_}); } grep(/^cp_/, keys(%{ $form })));
1062
1063   my $output_dateformat = $myconfig->{"dateformat"};
1064   my $output_numberformat = $myconfig->{"numberformat"};
1065   my $output_longdates = 1;
1066
1067   # map login user variables
1068   map { $form->{"login_$_"} = $myconfig->{$_} } ("name", "email", "fax", "tel", "company");
1069
1070   # format item dates
1071   for my $field (qw(transdate_oe deliverydate_oe)) {
1072     map {
1073       $form->{$field}[$_] = $locale->date($myconfig, $form->{$field}[$_], 1);
1074     } 0 .. $#{ $form->{$field} };
1075   }
1076
1077   if ($form->{shipto_id}) {
1078     $form->get_shipto($myconfig);
1079   }
1080
1081   $form->{notes} =~ s/^\s+//g;
1082
1083   $form->{templates} = $myconfig->{templates};
1084
1085   delete $form->{printer_command};
1086
1087   $form->get_employee_info($myconfig);
1088
1089   my ($cvar_date_fields, $cvar_number_fields) = CVar->get_field_format_list('module' => 'CT', 'prefix' => 'vc_');
1090
1091   if (scalar @{ $cvar_date_fields }) {
1092     format_dates($output_dateformat, $output_longdates, @{ $cvar_date_fields });
1093   }
1094
1095   while (my ($precision, $field_list) = each %{ $cvar_number_fields }) {
1096     reformat_numbers($output_numberformat, $precision, @{ $field_list });
1097   }
1098
1099   $form->{excel} = 1;
1100   my $extension            = 'xls';
1101
1102   $form->{IN}         = "$form->{formname}.${extension}";
1103
1104   delete $form->{OUT};
1105
1106   $form->parse_template($myconfig);
1107
1108   $main::lxdebug->leave_sub();
1109 }
1110
1111 sub search_contacts {
1112   $::lxdebug->enter_sub;
1113
1114   my $self      = shift;
1115   my %params    = @_;
1116
1117   my $dbh       = $params{dbh} || $::form->get_standard_dbh;
1118   my $vc        = $params{db} eq 'customer' ? 'customer' : 'vendor';
1119
1120   my %sortspecs = (
1121     'cp_name'   => 'cp_name, cp_givenname',
1122     'vcname'    => 'vcname, cp_name, cp_givenname',
1123     'vcnumber'  => 'vcnumber, cp_name, cp_givenname',
1124     );
1125
1126   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);
1127
1128   my $order_by  = $sortcols{$::form->{sort}} ? $::form->{sort} : 'cp_name';
1129   $::form->{sort} = $order_by;
1130   $order_by     = $sortspecs{$order_by} if ($sortspecs{$order_by});
1131
1132   my $sortdir   = $::form->{sortdir} ? 'ASC' : 'DESC';
1133   $order_by     =~ s/,/ ${sortdir},/g;
1134   $order_by    .= " $sortdir";
1135
1136   my @where_tokens = ();
1137   my @values;
1138
1139   if ($params{search_term}) {
1140     my @tokens;
1141     push @tokens,
1142       'cp.cp_name      ILIKE ?',
1143       'cp.cp_givenname ILIKE ?',
1144       'cp.cp_email     ILIKE ?';
1145     push @values, ('%' . $params{search_term} . '%') x 3;
1146
1147     if (($params{search_term} =~ m/\d/) && ($params{search_term} !~ m/[^\d \(\)+\-]/)) {
1148       my $number =  $params{search_term};
1149       $number    =~ s/[^\d]//g;
1150       $number    =  join '[ /\(\)+\-]*', split(m//, $number);
1151
1152       push @tokens, map { "($_ ~ '$number')" } qw(cp_phone1 cp_phone2 cp_mobile1 cp_mobile2);
1153     }
1154
1155     push @where_tokens, map { "($_)" } join ' OR ', @tokens;
1156   }
1157
1158   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'Contacts',
1159                                                             'trans_id_field' => 'cp.cp_id',
1160                                                             'filter'         => $params{filter});
1161
1162   if ($cvar_where) {
1163     push @where_tokens, $cvar_where;
1164     push @values, @cvar_values;
1165   }
1166
1167   if (my $filter = $params{filter}) {
1168     for (qw(name title givenname email project abteilung)) {
1169       next unless $filter->{"cp_$_"};
1170       add_token(\@where_tokens, \@values, col =>  "cp.cp_$_", val => $filter->{"cp_$_"}, method => 'ILIKE', esc => 'substr');
1171     }
1172
1173     push @where_tokens, 'cp.cp_cv_id IS NOT NULL' if $filter->{status} eq 'active';
1174     push @where_tokens, 'cp.cp_cv_id IS NULL'     if $filter->{status} eq 'orphaned';
1175   }
1176
1177   my $where = @where_tokens ? 'WHERE ' . join ' AND ', @where_tokens : '';
1178
1179   my $query     = qq|SELECT cp.*,
1180                        COALESCE(c.id,             v.id)           AS vcid,
1181                        COALESCE(c.name,           v.name)         AS vcname,
1182                        COALESCE(c.customernumber, v.vendornumber) AS vcnumber,
1183                        CASE WHEN c.name IS NULL THEN 'vendor' ELSE 'customer' END AS db
1184                      FROM contacts cp
1185                      LEFT JOIN customer c ON (cp.cp_cv_id = c.id)
1186                      LEFT JOIN vendor v   ON (cp.cp_cv_id = v.id)
1187                      $where
1188                      ORDER BY $order_by|;
1189
1190   my $contacts  = selectall_hashref_query($::form, $dbh, $query, @values);
1191
1192   $::lxdebug->leave_sub;
1193
1194   return @{ $contacts };
1195 }
1196
1197
1198 1;