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