9becb61da3a0ac56a13f1e0bf92ad01615417c23
[kivitendo-erp.git] / SL / Controller / CustomerVendor.pm
1 package SL::Controller::CustomerVendor;
2
3 use strict;
4 use parent qw(SL::Controller::Base);
5
6 use SL::JSON;
7 use SL::DBUtils;
8 use SL::Helper::Flash;
9
10 use SL::DB::Customer;
11 use SL::DB::Vendor;
12 use SL::DB::Business;
13 use SL::DB::Employee;
14 use SL::DB::Language;
15 use SL::DB::TaxZone;
16 use SL::DB::Note;
17 use SL::DB::PaymentTerm;
18 use SL::DB::Pricegroup;
19 use SL::DB::Contact;
20 use SL::DB::FollowUp;
21 use SL::DB::History;
22
23 # safety
24 __PACKAGE__->run_before(
25   sub {
26     $::auth->assert('customer_vendor_edit');
27   }
28 );
29
30 __PACKAGE__->run_before(
31   '_instantiate_args',
32   only => [
33     'save',
34     'save_and_ap_transaction',
35     'save_and_ar_transaction',
36     'save_and_close',
37     'save_and_invoice',
38     'save_and_order',
39     'save_and_quotation',
40     'save_and_rfq',
41     'delete_contact',
42     'delete_shipto',
43   ]
44 );
45
46 __PACKAGE__->run_before(
47   '_load_customer_vendor',
48   only => [
49     'edit',
50     'update',
51     'ajaj_get_shipto',
52     'ajaj_get_contact',
53   ]
54 );
55 __PACKAGE__->run_before(
56   '_create_customer_vendor',
57   only => [
58     'add',
59   ]
60 );
61
62 sub action_add {
63   my ($self) = @_;
64
65   $self->_pre_render();
66   $self->render(
67     'customer_vendor/form',
68     title => ($self->is_vendor() ? $::locale->text('Add Vendor') : $::locale->text('Add Customer')),
69     %{$self->{template_args}}
70   );
71 }
72
73 sub action_edit {
74   my ($self) = @_;
75
76   $self->_pre_render();
77   $self->render(
78     'customer_vendor/form',
79     title => ($self->is_vendor() ? $::locale->text('Edit Vendor') : $::locale->text('Edit Customer')),
80     %{$self->{template_args}}
81   );
82 }
83
84 sub _save {
85   my ($self) = @_;
86
87   my $cvs_by_nr;
88   if ( $self->is_vendor() ) {
89     if ( $self->{cv}->vendornumber ) {
90       $cvs_by_nr = SL::DB::Manager::Vendor->get_all(query => [vendornumber => $self->{cv}->vendornumber]);
91     }
92   }
93   else {
94     if ( $self->{cv}->customernumber ) {
95       $cvs_by_nr = SL::DB::Manager::Customer->get_all(query => [customernumber => $self->{cv}->customernumber]);
96     }
97   }
98
99   foreach my $entry (@{$cvs_by_nr}) {
100     if( $entry->id != $self->{cv}->id ) {
101       my $msg =
102         $self->is_vendor() ? $::locale->text('This vendor number is already in use.') : $::locale->text('This customer number is already in use.');
103
104       $::form->error($msg);
105     }
106   }
107
108   $self->{cv}->save(cascade => 1);
109
110   $self->{contact}->cp_cv_id($self->{cv}->id);
111   if( $self->{contact}->cp_name ne '' || $self->{contact}->cp_givenname ne '' ) {
112     $self->{contact}->save();
113   }
114
115   if( $self->{note}->subject ne '' && $self->{note}->body ne '' ) {
116     $self->{note}->trans_id($self->{cv}->id);
117     $self->{note}->save();
118     $self->{note_followup}->save();
119
120     $self->{note} = SL::DB::Note->new();
121     $self->{note_followup} = SL::DB::FollowUp->new();
122   }
123
124   $self->{shipto}->trans_id($self->{cv}->id);
125   if( $self->{shipto}->shiptoname ne '' ) {
126     $self->{shipto}->save();
127   }
128
129   my $snumbers = $self->is_vendor() ? 'vendornumber_'. $self->{cv}->vendornumber : 'customernumber_'. $self->{cv}->customernumber;
130   SL::DB::History->new(
131     trans_id => $self->{cv}->id,
132     snumbers => $snumbers,
133     employee_id => SL::DB::Manager::Employee->current->id,
134     addition => 'SAVED',
135   )->save();
136 }
137
138 sub action_save {
139   my ($self) = @_;
140
141   $self->_save();
142
143   $self->action_edit();
144 }
145
146 sub action_save_and_close {
147   my ($self) = @_;
148
149   $self->_save();
150
151   my $msg = $self->is_vendor() ? $::locale->text('Vendor saved') : $::locale->text('Customer saved');
152   $::form->redirect($msg);
153 }
154
155 sub _transaction {
156   my ($self, $script) = @_;
157
158   $::auth->assert('general_ledger         | invoice_edit         | vendor_invoice_edit | ' .
159                  ' request_quotation_edit | sales_quotation_edit | sales_order_edit    | purchase_order_edit');
160
161   $self->_save();
162
163   my $callback = $::form->escape($::form->{callback}, 1);
164   my $name = $::form->escape($self->{cv}->name, 1);
165   my $db = $self->is_vendor() ? 'vendor' : 'customer';
166
167   my $url =
168     $script .'?'.
169     'action=add&'.
170     'vc='. $db .'&'.
171     $db .'_id=' . $self->{cv}->id .'&'.
172     $db .'='. $name .'&'.
173     'type='. $::form->{type} .'&'.
174     'callback='. $callback;
175
176   print $::form->redirect_header($url);
177 }
178
179 sub action_save_and_ar_transaction {
180   my ($self) = @_;
181
182   $main::auth->assert('general_ledger');
183
184   $self->_transaction('ar.pl');
185 }
186
187 sub action_save_and_ap_transaction {
188   my ($self) = @_;
189
190   $main::auth->assert('general_ledger');
191
192   $self->_transaction('ap.pl');
193 }
194
195 sub action_save_and_invoice {
196   my ($self) = @_;
197
198   if ( $self->is_vendor() ) {
199     $::auth->assert('vendor_invoice_edit');
200   } else {
201     $::auth->assert('invoice_edit');
202   }
203
204   $::form->{type} = 'invoice';
205   $self->_transaction($self->is_vendor() ? 'ir.pl' : 'is.pl');
206 }
207
208 sub action_save_and_order {
209   my ($self) = @_;
210
211   if ( $self->is_vendor() ) {
212     $::auth->assert('purchase_order_edit');
213   } else {
214     $::auth->assert('sales_order_edit');
215   }
216
217   $::form->{type} = $self->is_vendor() ? 'purchase_order' : 'sales_order';
218   $self->_transaction('oe.pl');
219 }
220
221 sub action_save_and_rfq {
222   my ($self) = @_;
223
224   $::auth->assert('request_quotation_edit');
225
226   $::form->{type} = 'request_quotation';
227   $self->_transaction('oe.pl');
228 }
229
230 sub action_save_and_quotation {
231   my ($self) = @_;
232
233   $::auth->assert('sales_quotation_edit');
234
235   $::form->{type} = 'sales_quotation';
236   $self->_transaction('oe.pl');
237 }
238
239 sub action_delete {
240   my ($self) = @_;
241
242   if( !$self->is_orphaned() ) {
243     SL::Helper::Flash::flash('error', $::locale->text('blaabla'));
244
245     $self->action_edit();
246   }
247   else {
248     $self->{cv}->delete();
249
250     my $snumbers = $self->is_vendor() ? 'vendornumber_'. $self->{cv}->vendornumber : 'customernumber_'. $self->{cv}->customernumber;
251     SL::DB::History->new(
252       trans_id => $self->{cv}->id,
253       snumbers => $snumbers,
254       employee_id => SL::DB::Manager::Employee->current->id,
255       addition => 'DELETED',
256     )->save();
257
258     my $msg = $self->is_vendor() ? $::locale->text('Vendor deleted!') : $::locale->text('Customer deleted!');
259     $::form->redirect($msg);
260   }
261
262 }
263
264
265 sub action_delete_contact {
266   my ($self) = @_;
267
268   if ( !$self->{contact}->cp_id ) {
269     SL::Helper::Flash::flash('error', $::locale->text('No contact selected to delete'));
270   } else {
271     if ( $self->{contact}->used ) {
272       $self->{contact}->detach();
273       $self->{contact}->save();
274       SL::Helper::Flash::flash('info', $::locale->text('Contact is in use and was flagged invalid.'));
275     } else {
276       $self->{contact}->delete();
277       SL::Helper::Flash::flash('info', $::locale->text('Contact deleted.'));
278     }
279
280     $self->{contact} = SL::DB::Contact->new();
281   }
282
283   $self->action_edit();
284 }
285
286 sub action_delete_shipto {
287   my ($self) = @_;
288
289   if ( !$self->{shipto}->shipto_id ) {
290     SL::Helper::Flash::flash('error', $::locale->text('No shipto selected to delete'));
291   } else {
292     if ( $self->{shipto}->used ) {
293       $self->{shipto}->detach();
294       $self->{shipto}->save();
295       SL::Helper::Flash::flash('info', $::locale->text('Shipto is in use and was flagged invalid.'));
296     } else {
297       $self->{shipto}->delete();
298       SL::Helper::Flash::flash('info', $::locale->text('Shipto deleted.'));
299     }
300
301     $self->{shipto} = SL::DB::Shipto->new();
302   }
303
304   $self->action_edit();
305 }
306
307
308 sub action_search {
309   my ($self) = @_;
310
311   my $url = 'ct.pl?action=search&db='. ($self->is_vendor() ? 'vendor' : 'customer');
312
313   if ( $::form->{callback} ) {
314     $url .= '&callback='. $::from->escape($::form->{callback});
315   }
316
317   print $::form->redirect_header($url);
318 }
319
320
321 sub action_search_contact {
322   my ($self) = @_;
323
324   my $url = 'ct.pl?action=search_contact&db=customer';
325
326   if ( $::form->{callback} ) {
327     $url .= '&callback='. $::from->escape($::form->{callback});
328   }
329
330   print $::form->redirect_header($url);
331 }
332
333
334 sub action_get_delivery {
335   my ($self) = @_;
336
337   my $dbh = $::form->get_standard_dbh();
338
339   my ($arap, $db, $qty_sign);
340   if ( $self->is_vendor() ) {
341     $arap = 'ap';
342     $db = 'vendor';
343     $qty_sign = ' * -1 AS qty';
344   }
345   else {
346     $arap = 'ar';
347     $db = 'customer';
348     $qty_sign = '';
349   }
350
351   my $where = ' WHERE 1=1 ';
352   my @values;
353
354   if ( !$self->is_vendor() && $::form->{shipto_id} && $::form->{shipto_id} ne 'all' ) {
355     $where .= "AND ${arap}.shipto_id = ?";
356     push(@values, $::form->{shipto_id});
357   }
358
359   if ( $::form->{delivery_from} ) {
360     $where .= "AND ${arap}.transdate >= ?";
361     push(@values, conv_date($::form->{delivery_from}));
362   }
363
364   if ( $::form->{delivery_to} ) {
365     $where .= "AND ${arap}.transdate <= ?";
366     push(@values, conv_date($::form->{delivery_to}));
367   }
368
369   my $query =
370     "SELECT
371        s.shiptoname,
372        i.qty ${qty_sign},
373        ${arap}.id,
374        ${arap}.transdate,
375        ${arap}.invnumber,
376        ${arap}.ordnumber,
377        i.description,
378        i.unit,
379        i.sellprice,
380        oe.id AS oe_id,
381        invoice
382      FROM ${arap}
383
384      LEFT JOIN shipto s
385       ON ". ($arap eq 'ar' ? '(ar.shipto_id = s.shipto_id) ' : '(ap.id = s.trans_id) ') ."
386
387      LEFT JOIN invoice i
388        ON ${arap}.id = i.trans_id
389
390      LEFT JOIN parts p
391        ON p.id = i.parts_id
392
393      LEFT JOIN oe
394        ON (oe.ordnumber = ${arap}.ordnumber AND NOT ${arap}.ordnumber = '')
395
396      ${where}
397      ORDER BY ${arap}.transdate DESC LIMIT 15";
398
399   $self->{delivery} = selectall_hashref_query($::form, $dbh, $query, @values);
400
401   $self->render('customer_vendor/get_delivery', { layout => 0 });
402 }
403
404 sub action_ajaj_get_shipto {
405   my ($self) = @_;
406
407   my $data = {
408     map(
409       {
410         my $name = 'shipto'. $_;
411         $name => $self->{shipto}->$name;
412       }
413       qw(_id name department_1 department_2 street zipcode city country contact phone fax email)
414     )
415   };
416
417   $self->render(\SL::JSON::to_json($data), { type => 'json', process => 0 });
418 }
419
420 sub action_ajaj_get_contact {
421   my ($self) = @_;
422
423   my $data;
424
425   $data->{contact} = {
426     map(
427       {
428         my $name = 'cp_'. $_;
429
430         if ( $_ eq 'birthday' && $self->{contact}->$name ) {
431           $name => $self->{contact}->$name->to_lxoffice;
432         }
433         else {
434           $name => $self->{contact}->$name;
435         }
436       }
437       qw(
438         id gender abteilung title position givenname name email phone1 phone2 fax mobile1 mobile2
439         satphone satfax project street zipcode city privatphone privatemail birthday
440       )
441     )
442   };
443
444   $data->{contact_cvars} = {
445     map(
446       {
447         if ( $_->config->type eq 'number' ) {
448           $_->config->name => $::form->format_amount(\%::myconfig, $_->value, -2);
449         }
450         else {
451           $_->config->name => $_->value;
452         }
453       }
454       grep(
455         { $_->is_valid; }
456         @{$self->{contact}->cvars_by_config}
457       )
458     )
459   };
460
461   $self->render(\SL::JSON::to_json($data), { type => 'json', process => 0 });
462 }
463
464 sub action_ajaj_customer_autocomplete {
465   my ($self, %params) = @_;
466
467   my $limit = $::form->{limit} || 20;
468   my $type  = $::form->{type}  || {};
469   my $query = { ilike => '%'. $::form->{term} .'%' };
470
471   my @filter;
472   push(
473     @filter,
474     $::form->{column} ? ($::form->{column} => $query) : (or => [ customernumber => $query, name => $query ])
475   );
476
477   my $customers = SL::DB::Manager::Customer->get_all(query => [ @filter ], limit => $limit);
478   my $value_col = $::form->{column} || 'name';
479
480   my $data = [
481     map(
482       {
483         {
484           value => $_->can($value_col)->($_),
485           label => $_->displayable_name,
486           id    => $_->id,
487           customernumber => $_->customernumber,
488           name  => $_->name,
489         }
490       }
491       @{$customers}
492     )
493   ];
494
495   $self->render(\SL::JSON::to_json($data), { layout => 0, type => 'json' });
496 }
497
498 sub is_vendor {
499   return $::form->{db} eq 'vendor';
500 }
501
502 sub is_customer {
503   return $::form->{db} eq 'customer';
504 }
505
506 sub is_orphaned {
507   my ($self) = @_;
508
509   if ( defined($self->{_is_orphaned}) ) {
510     return $self->{_is_orphaned};
511   }
512
513   my $arap      = $self->is_vendor ? 'ap' : 'ar';
514   my $num_args  = 2;
515
516   my $cv = $self->is_vendor ? 'vendor' : 'customer';
517
518   my $query =
519    'SELECT a.id
520     FROM '. $arap .' AS a
521     JOIN '. $cv .' ct ON (a.'. $cv .'_id = ct.id)
522     WHERE ct.id = ?
523
524     UNION
525
526     SELECT a.id
527     FROM oe a
528     JOIN '. $cv .' ct ON (a.'. $cv .'_id = ct.id)
529     WHERE ct.id = ?';
530
531
532   if ( $self->is_vendor ) {
533     $query .=
534      ' UNION
535       SELECT 1 FROM makemodel mm WHERE mm.make = ?';
536     $num_args++;
537   }
538
539   my ($dummy) = selectrow_query($::form, $::form->get_standard_dbh(), $query, (conv_i($self->{cv}->id)) x $num_args);
540
541   return $self->{_is_orphaned} = !$dummy;
542 }
543
544 sub _instantiate_args {
545   my ($self) = @_;
546
547   my $curr_employee = SL::DB::Manager::Employee->current;
548
549   if ( $::form->{cv}->{id} ) {
550     if ( $self->is_vendor() ) {
551       $self->{cv} = SL::DB::Vendor->new(id => $::form->{cv}->{id})->load();
552     }
553     else {
554       $self->{cv} = SL::DB::Customer->new(id => $::form->{cv}->{id})->load();
555     }
556   }
557   else {
558     if ( $self->is_vendor() ) {
559       $self->{cv} = SL::DB::Vendor->new();
560     }
561     else {
562       $self->{cv} = SL::DB::Customer->new();
563     }
564   }
565   $self->{cv}->assign_attributes(%{$::form->{cv}});
566
567   foreach my $cvar (@{$self->{cv}->cvars_by_config()}) {
568     my $value = $::form->{cv_cvars}->{$cvar->config->name};
569
570     if ( $cvar->config->type eq 'number' ) {
571       $value = $::form->parse_amount(\%::myconfig, $value);
572     }
573
574     $cvar->value($value);
575   }
576
577 #  foreach my $cvar_key (keys(%{$::form->{cv_cvars}})) {
578 #    my $cvar_value = $::form->{cv_cvars}->{$cvar_key};
579 #    my $cvar = $self->{cv}->cvar_by_name($cvar_key);
580 #    $cvar->value($cvar_value);
581 #  }
582
583   if ( $::form->{note}->{id} ) {
584     $self->{note} = SL::DB::Note->new(id => $::form->{note}->{id})->load();
585   }
586   else {
587     $self->{note} = SL::DB::Note->new();
588   }
589   $self->{note}->assign_attributes(%{$::form->{note}});
590   $self->{note}->created_by($curr_employee->id);
591   $self->{note}->trans_module('ct');
592   #  if ( $self->{note}->trans_id != $self->{cv}->id ) {
593   #    die($::locale->text('Error'));
594   #  }
595
596
597   $self->{note_followup} = SL::DB::FollowUp->new();
598   $self->{note_followup}->assign_attributes(%{$::form->{note_followup}});
599   $self->{note_followup}->note($self->{note});
600   $self->{note_followup}->created_by($curr_employee->id);
601
602   if ( $::form->{shipto}->{shipto_id} ) {
603     $self->{shipto} = SL::DB::Shipto->new(shipto_id => $::form->{shipto}->{shipto_id})->load();
604   }
605   else {
606     $self->{shipto} = SL::DB::Shipto->new();
607   }
608   $self->{shipto}->assign_attributes(%{$::form->{shipto}});
609   $self->{shipto}->module('CT');
610 #  if ( $self->{shipto}->trans_id != $self->{cv}->id ) {
611 #    die($::locale->text('Error'));
612 #  }
613
614   if ( $::form->{contact}->{cp_id} ) {
615     $self->{contact} = SL::DB::Contact->new(cp_id => $::form->{contact}->{cp_id})->load();
616   }
617   else {
618     $self->{contact} = SL::DB::Contact->new();
619   }
620   $self->{contact}->assign_attributes(%{$::form->{contact}});
621 #  if ( $self->{contact}->cp_cv_id != $self->{cv}->id ) {
622 #    die($::locale->text('Error'));
623 #  }
624
625   foreach my $cvar (@{$self->{contact}->cvars_by_config()}) {
626     my $value = $::form->{contact_cvars}->{$cvar->config->name};
627
628     if ( $cvar->config->type eq 'number' ) {
629       $value = $::form->parse_amount(\%::myconfig, $value);
630     }
631
632     $cvar->value($value);
633   }
634 }
635
636 sub _load_customer_vendor {
637   my ($self) = @_;
638
639   if ( $self->is_vendor() ) {
640     $self->{cv} = SL::DB::Vendor->new(id => $::form->{id})->load();
641   }
642   else {
643     $self->{cv} = SL::DB::Customer->new(id => $::form->{id})->load();
644   }
645
646   $self->{note} = SL::DB::Note->new();
647   $self->{note_followup} = SL::DB::FollowUp->new();
648
649   if ( $::form->{shipto_id} ) {
650     $self->{shipto} = SL::DB::Shipto->new(shipto_id => $::form->{shipto_id})->load();
651
652     if ( $self->{shipto}->trans_id != $self->{cv}->id ) {
653       die($::locale->text('Error'));
654     }
655   }
656   else {
657     $self->{shipto} = SL::DB::Shipto->new();
658   }
659
660   if ( $::form->{contact_id} ) {
661     $self->{contact} = SL::DB::Contact->new(cp_id => $::form->{contact_id})->load();
662
663     if ( $self->{contact}->cp_cv_id != $self->{cv}->id ) {
664       die($::locale->text('Error'));
665     }
666   }
667   else {
668     $self->{contact} = SL::DB::Contact->new();
669   }
670 }
671
672 sub _create_customer_vendor {
673   my ($self) = @_;
674
675   if ( $self->is_vendor() ) {
676     $self->{cv} = SL::DB::Vendor->new();
677   }
678   else {
679     $self->{cv} = SL::DB::Customer->new();
680   }
681
682   $self->{note} = SL::DB::Note->new();
683
684   $self->{note_followup} = SL::DB::FollowUp->new();
685
686   $self->{shipto} = SL::DB::Shipto->new();
687
688   $self->{contact} = SL::DB::Contact->new();
689 }
690
691 sub _pre_render {
692   my ($self) = @_;
693
694   my $dbh = $::form->get_standard_dbh();
695
696   my $query;
697
698   $self->{all_business} = SL::DB::Manager::Business->get_all();
699
700   $self->{all_employees} = SL::DB::Manager::Employee->get_all();
701
702   $query =
703     'SELECT DISTINCT(greeting)
704      FROM customer
705      WHERE greeting IS NOT NULL AND greeting != \'\'
706      UNION
707        SELECT DISTINCT(greeting)
708        FROM vendor
709        WHERE greeting IS NOT NULL AND greeting != \'\'
710      ORDER BY greeting';
711   $self->{all_greetings} = [
712     map(
713       { $_->{greeting}; }
714       selectall_hashref_query($::form, $dbh, $query)
715     )
716   ];
717
718   $query =
719     'SELECT DISTINCT(cp_title) AS title
720      FROM contacts
721      WHERE cp_title IS NOT NULL AND cp_title != \'\'
722      ORDER BY cp_title';
723   $self->{all_titles} = [
724     map(
725       { $_->{title}; }
726       selectall_hashref_query($::form, $dbh, $query)
727     )
728   ];
729
730   $query =
731     'SELECT curr
732      FROM defaults';
733   my $curr = selectall_hashref_query($::form, $dbh, $query)->[0]->{curr};
734   my @currencies = grep(
735     { $_; }
736     map(
737       { s/\s//g; $_; }
738       split(m/:/, $curr)
739     )
740   );
741   $self->{all_currencies} = \@currencies;
742
743   $self->{all_languages} = SL::DB::Manager::Language->get_all();
744
745   $self->{all_taxzones} = SL::DB::Manager::TaxZone->get_all();
746
747   #Employee:
748   #TODO: ALL_SALESMAN
749   #TODO: ALL_SALESMAN_CUSTOMERS
750
751   $self->{all_payment_terms} = SL::DB::Manager::PaymentTerm->get_all();
752
753   $self->{all_pricegroups} = SL::DB::Manager::Pricegroup->get_all();
754
755   $query =
756     'SELECT DISTINCT(cp_abteilung) AS department
757      FROM contacts
758      WHERE cp_abteilung IS NOT NULL AND cp_abteilung != \'\'
759      ORDER BY cp_abteilung';
760   $self->{all_departments} = [
761     map(
762       { $_->{department}; }
763       selectall_hashref_query($::form, $dbh, $query)
764     )
765   ];
766
767   $self->{contacts} = $self->{cv}->contacts;
768   $self->{contacts} ||= [];
769
770   $self->{shiptos} = $self->{cv}->shipto;
771   $self->{shiptos} ||= [];
772
773   $self->{template_args} = {};
774
775   $::request->{layout}->add_javascripts('autocomplete_customer.js');
776 }
777
778 1;