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