a380f4373e42aa3a89891dcbd8720d72f5dc62e3
[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 List::MoreUtils qw(any);
7
8 use SL::JSON;
9 use SL::DBUtils;
10 use SL::Helper::Flash;
11 use SL::Locale::String;
12 use SL::Controller::Helper::GetModels;
13 use SL::Controller::Helper::ReportGenerator;
14 use SL::Controller::Helper::ParseFilter;
15
16 use SL::DB::Customer;
17 use SL::DB::Vendor;
18 use SL::DB::Business;
19 use SL::DB::Employee;
20 use SL::DB::Language;
21 use SL::DB::TaxZone;
22 use SL::DB::Note;
23 use SL::DB::PaymentTerm;
24 use SL::DB::Pricegroup;
25 use SL::DB::Contact;
26 use SL::DB::FollowUp;
27 use SL::DB::FollowUpLink;
28 use SL::DB::History;
29 use SL::DB::Currency;
30 use SL::DB::Invoice;
31 use SL::DB::PurchaseInvoice;
32 use SL::DB::Order;
33
34 use Data::Dumper;
35
36 use Rose::Object::MakeMethods::Generic (
37   'scalar --get_set_init' => [ qw(customer_models vendor_models) ],
38 );
39
40 # safety
41 __PACKAGE__->run_before(
42   sub {
43     $::auth->assert('customer_vendor_edit');
44   }
45 );
46 __PACKAGE__->run_before(
47   '_instantiate_args',
48   only => [
49     'save',
50     'save_and_ap_transaction',
51     'save_and_ar_transaction',
52     'save_and_close',
53     'save_and_invoice',
54     'save_and_order',
55     'save_and_quotation',
56     'save_and_rfq',
57     'delete',
58     'delete_contact',
59     'delete_shipto',
60   ]
61 );
62
63 __PACKAGE__->run_before(
64   '_load_customer_vendor',
65   only => [
66     'edit',
67     'show',
68     'update',
69     'ajaj_get_shipto',
70     'ajaj_get_contact',
71   ]
72 );
73
74 # make sure this comes after _load_customer_vendor
75 __PACKAGE__->run_before(
76   '_check_customer_vendor_all_edit',
77   only => [
78     'edit',
79     'show',
80     'update',
81     'delete',
82     'save',
83     'save_and_ap_transaction',
84     'save_and_ar_transaction',
85     'save_and_close',
86     'save_and_invoice',
87     'save_and_order',
88     'save_and_quotation',
89     'save_and_rfq',
90     'delete',
91     'delete_contact',
92     'delete_shipto',
93   ]
94 );
95
96 __PACKAGE__->run_before(
97   '_create_customer_vendor',
98   only => [
99     'add',
100   ]
101 );
102
103 __PACKAGE__->run_before('normalize_name');
104
105
106 sub action_add {
107   my ($self) = @_;
108
109   $self->_pre_render();
110   $self->{cv}->assign_attributes(hourly_rate => $::instance_conf->get_customer_hourly_rate) if $self->{cv}->is_customer;
111
112   $self->render(
113     'customer_vendor/form',
114     title => ($self->is_vendor() ? $::locale->text('Add Vendor') : $::locale->text('Add Customer')),
115     %{$self->{template_args}}
116   );
117 }
118
119 sub action_edit {
120   my ($self) = @_;
121
122   $self->_pre_render();
123   $self->render(
124     'customer_vendor/form',
125     title => ($self->is_vendor() ? $::locale->text('Edit Vendor') : $::locale->text('Edit Customer')),
126     %{$self->{template_args}}
127   );
128 }
129
130 sub action_show {
131   my ($self) = @_;
132
133   if ($::request->type eq 'json') {
134     my $cv_hash;
135     if (!$self->{cv}) {
136       # TODO error
137     } else {
138       $cv_hash          = $self->{cv}->as_tree;
139       $cv_hash->{cvars} = $self->{cv}->cvar_as_hashref;
140     }
141
142     $self->render(\ SL::JSON::to_json($cv_hash), { layout => 0, type => 'json', process => 0 });
143   }
144 }
145
146 sub _save {
147   my ($self) = @_;
148
149   my @errors = $self->{cv}->validate;
150   if (@errors) {
151     flash('error', @errors);
152     $self->_pre_render();
153     $self->render(
154       'customer_vendor/form',
155       title => ($self->is_vendor() ? t8('Edit Vendor') : t8('Edit Customer')),
156       %{$self->{template_args}}
157     );
158     $::dispatcher->end_request;
159   }
160
161   my $db = $self->{cv}->db;
162
163   $db->with_transaction(sub {
164     my $cvs_by_nr;
165     if ( $self->is_vendor() ) {
166       if ( $self->{cv}->vendornumber ) {
167         $cvs_by_nr = SL::DB::Manager::Vendor->get_all(query => [vendornumber => $self->{cv}->vendornumber]);
168       }
169     } else {
170       if ( $self->{cv}->customernumber ) {
171         $cvs_by_nr = SL::DB::Manager::Customer->get_all(query => [customernumber => $self->{cv}->customernumber]);
172       }
173     }
174
175     foreach my $entry (@{$cvs_by_nr}) {
176       if( $entry->id != $self->{cv}->id ) {
177         my $msg =
178           $self->is_vendor() ? $::locale->text('This vendor number is already in use.') : $::locale->text('This customer number is already in use.');
179
180         $::form->error($msg);
181       }
182     }
183
184     $self->{cv}->save(cascade => 1);
185
186     $self->{contact}->cp_cv_id($self->{cv}->id);
187     if( $self->{contact}->cp_name ne '' || $self->{contact}->cp_givenname ne '' ) {
188       $self->{contact}->save(cascade => 1);
189     }
190
191     if( $self->{note}->subject ne '' && $self->{note}->body ne '' ) {
192
193       if ( !$self->{note_followup}->follow_up_date ) {
194         $::form->error($::locale->text('Date missing!'));
195       }
196
197       $self->{note}->trans_id($self->{cv}->id);
198       $self->{note}->save();
199
200       $self->{note_followup}->save();
201
202       $self->{note_followup_link}->follow_up_id($self->{note_followup}->id);
203       $self->{note_followup_link}->trans_id($self->{cv}->id);
204       $self->{note_followup_link}->save();
205
206       SL::Helper::Flash::flash_later('info', $::locale->text('Follow-Up saved.'));
207     }
208
209     $self->{shipto}->trans_id($self->{cv}->id);
210     if(any { $self->{shipto}->$_ ne '' } qw(shiptoname shiptodepartment_1 shiptodepartment_2 shiptostreet shiptozipcode shiptocity shiptocountry shiptogln shiptocontact shiptophone shiptofax shiptoemail)) {
211       $self->{shipto}->save(cascade => 1);
212     }
213
214     my $snumbers = $self->is_vendor() ? 'vendornumber_'. $self->{cv}->vendornumber : 'customernumber_'. $self->{cv}->customernumber;
215     SL::DB::History->new(
216       trans_id => $self->{cv}->id,
217       snumbers => $snumbers,
218       employee_id => SL::DB::Manager::Employee->current->id,
219       addition => 'SAVED',
220     )->save();
221
222     if ( $::form->{delete_notes} ) {
223       foreach my $note_id (@{ $::form->{delete_notes} }) {
224         my $note = SL::DB::Note->new(id => $note_id)->load();
225         if ( $note->follow_up ) {
226           if ( $note->follow_up->follow_up_link ) {
227             $note->follow_up->follow_up_link->delete(cascade => 'delete');
228           }
229           $note->follow_up->delete(cascade => 'delete');
230         }
231         $note->delete(cascade => 'delete');
232       }
233     }
234
235     1;
236   }) || die($db->error);
237
238 }
239
240 sub action_save {
241   my ($self) = @_;
242
243   $self->_save();
244
245   my @redirect_params = (
246     action => 'edit',
247     id     => $self->{cv}->id,
248     db     => ($self->is_vendor() ? 'vendor' : 'customer'),
249   );
250
251   if ( $self->{contact}->cp_id ) {
252     push(@redirect_params, contact_id => $self->{contact}->cp_id);
253   }
254
255   if ( $self->{shipto}->shipto_id ) {
256     push(@redirect_params, shipto_id => $self->{shipto}->shipto_id);
257   }
258
259   $self->redirect_to(@redirect_params);
260 }
261
262 sub action_save_and_close {
263   my ($self) = @_;
264
265   $self->_save();
266
267   my $msg = $self->is_vendor() ? $::locale->text('Vendor saved') : $::locale->text('Customer saved');
268   $::form->redirect($msg);
269 }
270
271 sub _transaction {
272   my ($self, $script) = @_;
273
274   $::auth->assert('gl_transactions | ap_transactions | ar_transactions'.
275                     '| invoice_edit         | vendor_invoice_edit | ' .
276                  ' request_quotation_edit | sales_quotation_edit | sales_order_edit    | purchase_order_edit');
277
278   $self->_save();
279
280   my $name = $::form->escape($self->{cv}->name, 1);
281   my $db = $self->is_vendor() ? 'vendor' : 'customer';
282   my $action = 'add';
283
284   if ($::instance_conf->get_feature_experimental && 'oe.pl' eq $script) {
285     $script = 'controller.pl';
286     $action = 'Order/' . $action;
287   }
288
289   my $url = $self->url_for(
290     controller => $script,
291     action     => $action,
292     vc         => $db,
293     $db .'_id' => $self->{cv}->id,
294     $db        => $name,
295     type       => $::form->{type},
296     callback   => $::form->{callback},
297   );
298
299   print $::form->redirect_header($url);
300 }
301
302 sub action_save_and_ar_transaction {
303   my ($self) = @_;
304
305   $main::auth->assert('ar_transactions');
306
307   $self->_transaction('ar.pl');
308 }
309
310 sub action_save_and_ap_transaction {
311   my ($self) = @_;
312
313   $main::auth->assert('ap_transactions');
314
315   $self->_transaction('ap.pl');
316 }
317
318 sub action_save_and_invoice {
319   my ($self) = @_;
320
321   if ( $self->is_vendor() ) {
322     $::auth->assert('vendor_invoice_edit');
323   } else {
324     $::auth->assert('invoice_edit');
325   }
326
327   $::form->{type} = 'invoice';
328   $self->_transaction($self->is_vendor() ? 'ir.pl' : 'is.pl');
329 }
330
331 sub action_save_and_order {
332   my ($self) = @_;
333
334   if ( $self->is_vendor() ) {
335     $::auth->assert('purchase_order_edit');
336   } else {
337     $::auth->assert('sales_order_edit');
338   }
339
340   $::form->{type} = $self->is_vendor() ? 'purchase_order' : 'sales_order';
341   $self->_transaction('oe.pl');
342 }
343
344 sub action_save_and_rfq {
345   my ($self) = @_;
346
347   $::auth->assert('request_quotation_edit');
348
349   $::form->{type} = 'request_quotation';
350   $self->_transaction('oe.pl');
351 }
352
353 sub action_save_and_quotation {
354   my ($self) = @_;
355
356   $::auth->assert('sales_quotation_edit');
357
358   $::form->{type} = 'sales_quotation';
359   $self->_transaction('oe.pl');
360 }
361
362 sub action_delete {
363   my ($self) = @_;
364
365   my $db = $self->{cv}->db;
366
367   if( !$self->is_orphaned() ) {
368     $self->action_edit();
369   } else {
370
371     $db->with_transaction(sub {
372       $self->{cv}->delete(cascade => 1);
373
374       my $snumbers = $self->is_vendor() ? 'vendornumber_'. $self->{cv}->vendornumber : 'customernumber_'. $self->{cv}->customernumber;
375       SL::DB::History->new(
376         trans_id => $self->{cv}->id,
377         snumbers => $snumbers,
378         employee_id => SL::DB::Manager::Employee->current->id,
379         addition => 'DELETED',
380       )->save();
381     }) || die($db->error);
382
383     my $msg = $self->is_vendor() ? $::locale->text('Vendor deleted!') : $::locale->text('Customer deleted!');
384     $::form->redirect($msg);
385   }
386
387 }
388
389
390 sub action_delete_contact {
391   my ($self) = @_;
392
393   my $db = $self->{contact}->db;
394
395   if ( !$self->{contact}->cp_id ) {
396     SL::Helper::Flash::flash('error', $::locale->text('No contact selected to delete'));
397   } else {
398
399     $db->with_transaction(sub {
400       if ( $self->{contact}->used ) {
401         $self->{contact}->detach();
402         $self->{contact}->save();
403         SL::Helper::Flash::flash('info', $::locale->text('Contact is in use and was flagged invalid.'));
404       } else {
405         $self->{contact}->delete(cascade => 1);
406         SL::Helper::Flash::flash('info', $::locale->text('Contact deleted.'));
407       }
408
409       1;
410     }) || die($db->error);
411
412     $self->{contact} = $self->_new_contact_object;
413   }
414
415   $self->action_edit();
416 }
417
418 sub action_delete_shipto {
419   my ($self) = @_;
420
421   my $db = $self->{shipto}->db;
422
423   if ( !$self->{shipto}->shipto_id ) {
424     SL::Helper::Flash::flash('error', $::locale->text('No shipto selected to delete'));
425   } else {
426
427     $db->with_transaction(sub {
428       if ( $self->{shipto}->used ) {
429         $self->{shipto}->detach();
430         $self->{shipto}->save(cascade => 1);
431         SL::Helper::Flash::flash('info', $::locale->text('Shipto is in use and was flagged invalid.'));
432       } else {
433         $self->{shipto}->delete(cascade => 1);
434         SL::Helper::Flash::flash('info', $::locale->text('Shipto deleted.'));
435       }
436
437       1;
438     }) || die($db->error);
439
440     $self->{shipto} = SL::DB::Shipto->new();
441   }
442
443   $self->action_edit();
444 }
445
446
447 sub action_search {
448   my ($self) = @_;
449
450   my @url_params = (
451     controller => 'ct.pl',
452     action => 'search',
453     db => $self->is_vendor() ? 'vendor' : 'customer',
454   );
455
456   if ( $::form->{callback} ) {
457     push(@url_params, callback => $::form->{callback});
458   }
459
460   $self->redirect_to(@url_params);
461 }
462
463
464 sub action_search_contact {
465   my ($self) = @_;
466
467   my $url = 'ct.pl?action=search_contact&db=customer';
468
469   if ( $::form->{callback} ) {
470     $url .= '&callback='. $::form->escape($::form->{callback});
471   }
472
473   print $::form->redirect_header($url);
474 }
475
476 sub action_get_delivery {
477   my ($self) = @_;
478
479   $::auth->assert('sales_all_edit');
480
481   my $dbh = $::form->get_standard_dbh();
482
483   my ($arap, $db, $qty_sign);
484   if ( $self->is_vendor() ) {
485     $arap = 'ap';
486     $db = 'vendor';
487     $qty_sign = ' * -1 AS qty';
488   } else {
489     $arap = 'ar';
490     $db = 'customer';
491     $qty_sign = '';
492   }
493
494   my $where = ' WHERE 1=1';
495   my @values;
496
497   if ( !$self->is_vendor() && $::form->{shipto_id} && $::form->{shipto_id} ne 'all' ) {
498     $where .= " AND ${arap}.shipto_id = ?";
499     push(@values, $::form->{shipto_id});
500   } else {
501     $where .= " AND ${arap}.${db}_id = ?";
502     push(@values, $::form->{id});
503   }
504
505   if ( $::form->{delivery_from} ) {
506     $where .= " AND ${arap}.transdate >= ?";
507     push(@values, conv_date($::form->{delivery_from}));
508   }
509
510   if ( $::form->{delivery_to} ) {
511     $where .= " AND ${arap}.transdate <= ?";
512     push(@values, conv_date($::form->{delivery_to}));
513   }
514
515   my $query =
516     "SELECT
517        s.shiptoname,
518        i.qty ${qty_sign},
519        ${arap}.id,
520        ${arap}.transdate,
521        ${arap}.invnumber,
522        ${arap}.ordnumber,
523        i.description,
524        i.unit,
525        i.sellprice,
526        oe.id AS oe_id,
527        invoice
528      FROM ${arap}
529
530      LEFT JOIN shipto s
531       ON ". ($arap eq 'ar' ? '(ar.shipto_id = s.shipto_id) ' : '(ap.id = s.trans_id) ') ."
532
533      LEFT JOIN invoice i
534        ON ${arap}.id = i.trans_id
535
536      LEFT JOIN parts p
537        ON p.id = i.parts_id
538
539      LEFT JOIN oe
540        ON (oe.ordnumber = ${arap}.ordnumber AND NOT ${arap}.ordnumber = ''
541            AND ". ($arap eq 'ar' ? 'oe.customer_id IS NOT NULL' : 'oe.vendor_id IS NOT NULL') ." )
542
543      ${where}
544      ORDER BY ${arap}.transdate DESC LIMIT 15";
545
546   $self->{delivery} = selectall_hashref_query($::form, $dbh, $query, @values);
547
548   $self->render('customer_vendor/get_delivery', { layout => 0 });
549 }
550
551 sub action_ajaj_get_shipto {
552   my ($self) = @_;
553
554   my $data = {};
555   $data->{shipto} = {
556     map(
557       {
558         my $name = 'shipto'. $_;
559         $name => $self->{shipto}->$name;
560       }
561       qw(_id name department_1 department_2 street zipcode city gln country contact phone fax email)
562     )
563   };
564
565   $data->{shipto_cvars} = $self->_prepare_cvar_configs_for_ajaj($self->{shipto}->cvars_by_config);
566
567   $self->render(\SL::JSON::to_json($data), { type => 'json', process => 0 });
568 }
569
570 sub action_ajaj_get_contact {
571   my ($self) = @_;
572
573   my $data;
574
575   $data->{contact} = {
576     map(
577       {
578         my $name = 'cp_'. $_;
579
580         if ( $_ eq 'birthday' && $self->{contact}->$name ) {
581           $name => $self->{contact}->$name->to_lxoffice;
582         } else {
583           $name => $self->{contact}->$name;
584         }
585       }
586       qw(
587         id gender abteilung title position givenname name email phone1 phone2 fax mobile1 mobile2
588         satphone satfax project street zipcode city privatphone privatemail birthday
589       )
590     )
591   };
592
593   $data->{contact_cvars} = $self->_prepare_cvar_configs_for_ajaj($self->{contact}->cvars_by_config);
594
595   $self->render(\SL::JSON::to_json($data), { type => 'json', process => 0 });
596 }
597
598 sub action_ajaj_autocomplete {
599   my ($self, %params) = @_;
600
601   my ($model, $manager, $number, $matches);
602
603   # first see if this is customer or vendor picking
604   if ($::form->{type} eq 'customer') {
605      $model   = $self->customer_models;
606      $manager = 'SL::DB::Manager::Customer';
607      $number  = 'customernumber';
608   } elsif ($::form->{type} eq 'vendor')  {
609      $model   = $self->vendor_models;
610      $manager = 'SL::DB::Manager::Vendor';
611      $number  = 'vendornumber';
612   } else {
613      die "unknown type $::form->{type}";
614   }
615
616   # if someone types something, and hits enter, assume he entered the full name.
617   # if something matches, treat that as sole match
618   # unfortunately get_models can't do more than one per package atm, so we d it
619   # the oldfashioned way.
620   if ($::form->{prefer_exact}) {
621     my $exact_matches;
622     if (1 == scalar @{ $exact_matches = $manager->get_all(
623       query => [
624         obsolete => 0,
625         (salesman_id => SL::DB::Manager::Employee->current->id) x !$::auth->assert('customer_vendor_all_edit', 1),
626         or => [
627           name    => { ilike => $::form->{filter}{'all:substr:multi::ilike'} },
628           $number => { ilike => $::form->{filter}{'all:substr:multi::ilike'} },
629         ]
630       ],
631       limit => 2,
632     ) }) {
633       $matches = $exact_matches;
634     }
635   }
636
637   $matches //= $model->get;
638
639   my @hashes = map {
640    +{
641      value       => $_->displayable_name,
642      label       => $_->displayable_name,
643      id          => $_->id,
644      $number     => $_->$number,
645      name        => $_->name,
646      type        => $::form->{type},
647      cvars       => { map { ($_->config->name => { value => $_->value_as_text, is_valid => $_->is_valid }) } @{ $_->cvars_by_config } },
648     }
649   } @{ $matches };
650
651   $self->render(\ SL::JSON::to_json(\@hashes), { layout => 0, type => 'json', process => 0 });
652 }
653
654 sub action_test_page {
655   $_[0]->render('customer_vendor/test_page');
656 }
657
658 sub is_vendor {
659   return $::form->{db} eq 'vendor';
660 }
661
662 sub is_customer {
663   return $::form->{db} eq 'customer';
664 }
665
666 sub is_orphaned {
667   my ($self) = @_;
668
669   if ( defined($self->{_is_orphaned}) ) {
670     return $self->{_is_orphaned};
671   }
672
673   my $arap      = $self->is_vendor ? 'ap' : 'ar';
674   my $num_args  = 3;
675
676   my $cv = $self->is_vendor ? 'vendor' : 'customer';
677
678   my $query =
679    'SELECT a.id
680     FROM '. $arap .' AS a
681     JOIN '. $cv .' ct ON (a.'. $cv .'_id = ct.id)
682     WHERE ct.id = ?
683
684     UNION
685
686     SELECT a.id
687     FROM oe a
688     JOIN '. $cv .' ct ON (a.'. $cv .'_id = ct.id)
689     WHERE ct.id = ?
690
691     UNION
692
693     SELECT a.id
694     FROM delivery_orders a
695     JOIN '. $cv .' ct ON (a.'. $cv .'_id = ct.id)
696     WHERE ct.id = ?';
697
698
699   if ( $self->is_vendor ) {
700     $query .=
701      ' UNION
702       SELECT 1 FROM makemodel mm WHERE mm.make = ?';
703     $num_args++;
704   }
705
706   my ($dummy) = selectrow_query($::form, $::form->get_standard_dbh(), $query, (conv_i($self->{cv}->id)) x $num_args);
707
708   return $self->{_is_orphaned} = !$dummy;
709 }
710
711 sub _copy_form_to_cvars {
712   my ($self, %params) = @_;
713
714   foreach my $cvar (@{ $params{target}->cvars_by_config }) {
715     my $value = $params{source}->{$cvar->config->name};
716     $value    = $::form->parse_amount(\%::myconfig, $value) if $cvar->config->type eq 'number';
717
718     $cvar->value($value);
719   }
720 }
721
722 sub _instantiate_args {
723   my ($self) = @_;
724
725   my $curr_employee = SL::DB::Manager::Employee->current;
726
727   if ( $::form->{cv}->{id} ) {
728     if ( $self->is_vendor() ) {
729       $self->{cv} = SL::DB::Vendor->new(id => $::form->{cv}->{id})->load();
730     } else {
731       $self->{cv} = SL::DB::Customer->new(id => $::form->{cv}->{id})->load();
732     }
733   } else {
734     $self->{cv} = $self->_new_customer_vendor_object;
735   }
736   $self->{cv}->assign_attributes(%{$::form->{cv}});
737
738   if ( $self->is_customer() && $::form->{cv}->{taxincluded_checked} eq '' ) {
739     $self->{cv}->taxincluded_checked(undef);
740   }
741
742   $self->{cv}->hourly_rate($::instance_conf->get_customer_hourly_rate) if $self->is_customer && !$self->{cv}->hourly_rate;
743
744   if ( $::form->{note}->{id} ) {
745     $self->{note} = SL::DB::Note->new(id => $::form->{note}->{id})->load();
746     $self->{note_followup} = $self->{note}->follow_up;
747     $self->{note_followup_link} = $self->{note_followup}->follow_up_link;
748   } else {
749     $self->{note} = SL::DB::Note->new();
750     $self->{note_followup} = SL::DB::FollowUp->new();
751     $self->{note_followup_link} = SL::DB::FollowUpLink->new();
752   }
753
754   $self->{note}->assign_attributes(%{$::form->{note}});
755   $self->{note}->created_by($curr_employee->id);
756   $self->{note}->trans_module('ct');
757
758   $self->{note_followup}->assign_attributes(%{$::form->{note_followup}});
759   $self->{note_followup}->note($self->{note});
760   $self->{note_followup}->created_by($curr_employee->id);
761
762   $self->{note_followup_link}->trans_type($self->is_vendor() ? 'vendor' : 'customer');
763   $self->{note_followup_link}->trans_info($self->{cv}->name);
764
765   if ( $::form->{shipto}->{shipto_id} ) {
766     $self->{shipto} = SL::DB::Shipto->new(shipto_id => $::form->{shipto}->{shipto_id})->load();
767   } else {
768     $self->{shipto} = SL::DB::Shipto->new();
769   }
770   $self->{shipto}->assign_attributes(%{$::form->{shipto}});
771   $self->{shipto}->module('CT');
772
773   if ( $::form->{contact}->{cp_id} ) {
774     $self->{contact} = SL::DB::Contact->new(cp_id => $::form->{contact}->{cp_id})->load();
775   } else {
776     $self->{contact} = $self->_new_contact_object;
777   }
778   $self->{contact}->assign_attributes(%{$::form->{contact}});
779
780   $self->_copy_form_to_cvars(target => $self->{cv},      source => $::form->{cv_cvars});
781   $self->_copy_form_to_cvars(target => $self->{contact}, source => $::form->{contact_cvars});
782   $self->_copy_form_to_cvars(target => $self->{shipto},  source => $::form->{shipto_cvars});
783 }
784
785 sub _load_customer_vendor {
786   my ($self) = @_;
787
788   if ( $self->is_vendor() ) {
789     $self->{cv} = SL::DB::Vendor->new(id => $::form->{id})->load();
790   } else {
791     $self->{cv} = SL::DB::Customer->new(id => $::form->{id})->load();
792   }
793
794   if ( $::form->{note_id} ) {
795     $self->{note} = SL::DB::Note->new(id => $::form->{note_id})->load();
796     $self->{note_followup} = $self->{note}->follow_up;
797     $self->{note_followup_link} = $self->{note_followup}->follow_up_link;
798   } else {
799     $self->{note} = SL::DB::Note->new();
800     $self->{note_followup} = SL::DB::FollowUp->new();
801     $self->{note_followup_link} = SL::DB::FollowUpLink->new();
802   }
803
804   if ( $::form->{shipto_id} ) {
805     $self->{shipto} = SL::DB::Shipto->new(shipto_id => $::form->{shipto_id})->load();
806
807     if ( $self->{shipto}->trans_id != $self->{cv}->id ) {
808       die($::locale->text('Error'));
809     }
810   } else {
811     $self->{shipto} = SL::DB::Shipto->new();
812   }
813
814   if ( $::form->{contact_id} ) {
815     $self->{contact} = SL::DB::Contact->new(cp_id => $::form->{contact_id})->load();
816
817     if ( $self->{contact}->cp_cv_id != $self->{cv}->id ) {
818       die($::locale->text('Error'));
819     }
820   } else {
821     $self->{contact} = $self->_new_contact_object;
822   }
823 }
824
825 sub _check_customer_vendor_all_edit {
826   my ($self) = @_;
827
828   unless ($::auth->assert('customer_vendor_all_edit', 1)) {
829     die($::locale->text("You don't have the rights to edit this customer.") . "\n")
830       if $self->{cv}->is_customer and
831          SL::DB::Manager::Employee->current->id != $self->{cv}->salesman_id;
832   };
833 };
834
835 sub _create_customer_vendor {
836   my ($self) = @_;
837
838   $self->{cv} = $self->_new_customer_vendor_object;
839   $self->{cv}->currency_id($::instance_conf->get_currency_id());
840
841   $self->{note} = SL::DB::Note->new();
842
843   $self->{note_followup} = SL::DB::FollowUp->new();
844
845   $self->{shipto} = SL::DB::Shipto->new();
846
847   $self->{contact} = $self->_new_contact_object;
848 }
849
850 sub _pre_render {
851   my ($self) = @_;
852
853   my $dbh = $::form->get_standard_dbh();
854
855   my $query;
856
857   $self->{all_business} = SL::DB::Manager::Business->get_all();
858
859   $self->{all_employees} = SL::DB::Manager::Employee->get_all(query => [ deleted => 0 ]);
860
861   $query =
862     'SELECT DISTINCT(greeting)
863      FROM customer
864      WHERE greeting IS NOT NULL AND greeting != \'\'
865      UNION
866        SELECT DISTINCT(greeting)
867        FROM vendor
868        WHERE greeting IS NOT NULL AND greeting != \'\'
869      ORDER BY greeting';
870   $self->{all_greetings} = [
871     map(
872       { $_->{greeting}; }
873       selectall_hashref_query($::form, $dbh, $query)
874     )
875   ];
876
877   $query =
878     'SELECT DISTINCT(cp_title) AS title
879      FROM contacts
880      WHERE cp_title IS NOT NULL AND cp_title != \'\'
881      ORDER BY cp_title';
882   $self->{all_titles} = [
883     map(
884       { $_->{title}; }
885       selectall_hashref_query($::form, $dbh, $query)
886     )
887   ];
888
889   $self->{all_currencies} = SL::DB::Manager::Currency->get_all();
890
891   $self->{all_languages} = SL::DB::Manager::Language->get_all();
892
893   $self->{all_taxzones} = SL::DB::Manager::TaxZone->get_all_sorted();
894
895   if ( $::instance_conf->get_vertreter() ) {
896     $query =
897       'SELECT id
898        FROM business
899        WHERE salesman';
900     my $business_ids = [
901       map(
902         { $_->{id}; }
903         selectall_hashref_query($::form, $dbh, $query)
904       )
905     ];
906
907     if ( $business_ids->[0] ) {
908       $self->{all_salesman_customers} = SL::DB::Manager::Customer->get_all(query => [business_id => $business_ids]);
909     } else {
910       $self->{all_salesman_customers} = [];
911     }
912   } else {
913     $self->{all_salesmen} = SL::DB::Manager::Employee->get_all(query => [ or => [ id => $self->{cv}->salesman_id,  deleted => 0 ] ]);
914   }
915
916   $self->{all_payment_terms} = SL::DB::Manager::PaymentTerm->get_all_sorted(where => [ or => [ id       => $self->{cv}->payment_id,
917                                                                                                obsolete => 0 ] ]);
918
919   $self->{all_delivery_terms} = SL::DB::Manager::DeliveryTerm->get_all();
920
921   if ($self->{cv}->is_customer) {
922     $self->{all_pricegroups} = SL::DB::Manager::Pricegroup->get_all_sorted(query => [ or => [ id => $self->{cv}->pricegroup_id, obsolete => 0 ] ]);
923   }
924
925   $query =
926     'SELECT DISTINCT(cp_abteilung) AS department
927      FROM contacts
928      WHERE cp_abteilung IS NOT NULL AND cp_abteilung != \'\'
929      ORDER BY cp_abteilung';
930   $self->{all_departments} = [
931     map(
932       { $_->{department}; }
933       selectall_hashref_query($::form, $dbh, $query)
934     )
935   ];
936
937   $self->{contacts} = $self->{cv}->contacts;
938   $self->{contacts} ||= [];
939
940   $self->{shiptos} = $self->{cv}->shipto;
941   $self->{shiptos} ||= [];
942
943   $self->{notes} = SL::DB::Manager::Note->get_all(
944     query => [
945       trans_id => $self->{cv}->id,
946       trans_module => 'ct',
947     ],
948     with_objects => ['follow_up'],
949   );
950
951   if ( $self->is_vendor()) {
952     $self->{open_items} = SL::DB::Manager::PurchaseInvoice->get_all_count(
953       query => [
954         vendor_id => $self->{cv}->id,
955         paid => {lt_sql => 'amount'},
956       ],
957     );
958   } else {
959     $self->{open_items} = SL::DB::Manager::Invoice->get_all_count(
960       query => [
961         customer_id => $self->{cv}->id,
962         paid => {lt_sql => 'amount'},
963       ],
964     );
965   }
966
967   if ( $self->is_vendor() ) {
968     $self->{open_orders} = SL::DB::Manager::Order->get_all_count(
969       query => [
970         vendor_id => $self->{cv}->id,
971         closed => 'F',
972       ],
973     );
974   } else {
975     $self->{open_orders} = SL::DB::Manager::Order->get_all_count(
976       query => [
977         customer_id => $self->{cv}->id,
978         closed => 'F',
979       ],
980     );
981   }
982   $self->{template_args} ||= {};
983
984   $::request->{layout}->add_javascripts('kivi.CustomerVendor.js');
985   $::request->{layout}->add_javascripts('kivi.File.js');
986
987   $self->_setup_form_action_bar;
988 }
989
990 sub _setup_form_action_bar {
991   my ($self) = @_;
992
993   for my $bar ($::request->layout->get('actionbar')) {
994     $bar->add(
995       combobox => [
996         action => [
997           t8('Save'),
998           submit    => [ '#form', { action => "CustomerVendor/save" } ],
999           checks    => [ 'check_taxzone_and_ustid' ],
1000           accesskey => 'enter',
1001         ],
1002         action => [
1003           t8('Save and Close'),
1004           submit => [ '#form', { action => "CustomerVendor/save_and_close" } ],
1005           checks => [ 'check_taxzone_and_ustid' ],
1006         ],
1007       ], # end of combobox "Save"
1008
1009       combobox => [
1010         action => [ t8('Workflow') ],
1011         (action => [
1012           t8('Save and AP Transaction'),
1013           submit => [ '#form', { action => "CustomerVendor/save_and_ap_transaction" } ],
1014           checks => [ 'check_taxzone_and_ustid' ],
1015         ]) x !!$self->is_vendor,
1016         (action => [
1017           t8('Save and AR Transaction'),
1018           submit => [ '#form', { action => "CustomerVendor/save_and_ar_transaction" } ],
1019           checks => [ 'check_taxzone_and_ustid' ],
1020         ]) x !$self->is_vendor,
1021         action => [
1022           t8('Save and Invoice'),
1023           submit => [ '#form', { action => "CustomerVendor/save_and_invoice" } ],
1024           checks => [ 'check_taxzone_and_ustid' ],
1025         ],
1026         action => [
1027           t8('Save and Order'),
1028           submit => [ '#form', { action => "CustomerVendor/save_and_order" } ],
1029           checks => [ 'check_taxzone_and_ustid' ],
1030         ],
1031         (action => [
1032           t8('Save and RFQ'),
1033           submit => [ '#form', { action => "CustomerVendor/save_and_rfq" } ],
1034           checks => [ 'check_taxzone_and_ustid' ],
1035         ]) x !!$self->is_vendor,
1036         (action => [
1037           t8('Save and Quotation'),
1038           submit => [ '#form', { action => "CustomerVendor/save_and_quotation" } ],
1039           checks => [ 'check_taxzone_and_ustid' ],
1040         ]) x !$self->is_vendor,
1041       ], # end of combobox "Workflow"
1042
1043       action => [
1044         t8('Delete'),
1045         submit   => [ '#form', { action => "CustomerVendor/delete" } ],
1046         confirm  => t8('Do you really want to delete this object?'),
1047         disabled => !$self->{cv}->id    ? t8('This object has not been saved yet.')
1048                   : !$self->is_orphaned ? t8('This object has already been used.')
1049                   :                       undef,
1050       ],
1051
1052       'separator',
1053
1054       action => [
1055         t8('History'),
1056         call     => [ 'kivi.CustomerVendor.showHistoryWindow', $self->{cv}->id ],
1057         disabled => !$self->{cv}->id ? t8('This object has not been saved yet.') : undef,
1058       ],
1059     );
1060   }
1061 }
1062
1063 sub _prepare_cvar_configs_for_ajaj {
1064   my ($self, $cvars) = @_;
1065
1066   return {
1067     map {
1068       my $cvar   = $_;
1069       my $result = { type => $cvar->config->type };
1070
1071       if ($cvar->config->type eq 'number') {
1072         $result->{value} = $::form->format_amount(\%::myconfig, $cvar->value, -2);
1073
1074       } elsif ($result->{type} eq 'date') {
1075         $result->{value} = $cvar->value ? $cvar->value->to_kivitendo : undef;
1076
1077       } elsif ($result->{type} =~ m{customer|vendor|part}) {
1078         my $object       = $cvar->value;
1079         my $method       = $result->{type} eq 'part' ? 'description' : 'name';
1080
1081         $result->{id}    = int($cvar->number_value) || undef;
1082         $result->{value} = $object ? $object->$method // '' : '';
1083
1084       } else {
1085         $result->{value} = $cvar->value;
1086       }
1087
1088       ( $cvar->config->name => $result )
1089
1090     } grep { $_->is_valid } @{ $cvars }
1091   };
1092 }
1093
1094 sub normalize_name {
1095   my ($self) = @_;
1096
1097   # check if feature is enabled (select normalize_vc_names from defaults)
1098   return unless ($::instance_conf->get_normalize_vc_names);
1099
1100   return unless $self->{cv};
1101   my $name = $self->{cv}->name;
1102   $name =~ s/\s+$//;
1103   $name =~ s/^\s+//;
1104   $name =~ s/\s+/ /g;
1105   $self->{cv}->name($name);
1106 }
1107
1108 sub home_address_for_google_maps {
1109   my ($self)  = @_;
1110
1111   my $address = $::instance_conf->get_address // '';
1112   $address    =~ s{^\s+|\s+$|\r+}{}g;
1113   $address    =~ s{\n+}{,}g;
1114   $address    =~ s{\s+}{ }g;
1115
1116   return $address;
1117 }
1118
1119 sub init_customer_models {
1120   my ($self) = @_;
1121
1122   SL::Controller::Helper::GetModels->new(
1123     controller   => $self,
1124     model        => 'Customer',
1125     sorted => {
1126       _default  => {
1127         by => 'customernumber',
1128         dir  => 1,
1129       },
1130       customernumber => t8('Customer Number'),
1131     },
1132     query => [
1133      ( salesman_id => SL::DB::Manager::Employee->current->id) x !$::auth->assert('customer_vendor_all_edit', 1),
1134     ],
1135   );
1136 }
1137
1138 sub init_vendor_models {
1139   my ($self) = @_;
1140
1141   SL::Controller::Helper::GetModels->new(
1142     controller => $self,
1143     model      => 'Vendor',
1144     sorted => {
1145       _default  => {
1146         by => 'vendornumber',
1147         dir  => 1,
1148       },
1149       vendornumber => t8('Vendor Number'),
1150     },
1151   );
1152 }
1153
1154 sub _new_customer_vendor_object {
1155   my ($self) = @_;
1156
1157   my $class  = 'SL::DB::' . ($self->is_vendor ? 'Vendor' : 'Customer');
1158   return $class->new(
1159     contacts         => [],
1160     shipto           => [],
1161     custom_variables => [],
1162   );
1163 }
1164
1165 sub _new_contact_object {
1166   my ($self) = @_;
1167
1168   return SL::DB::Contact->new(custom_variables => []);
1169 }
1170
1171 1;