1 package SL::Controller::PhoneNumber;
5 use parent qw(SL::Controller::Base);
7 use List::MoreUtils qw(any);
8 use List::Util qw(first);
12 use SL::Locale::String;
24 my $number = $self->normalize_number($::form->{number} // '');
26 return $self->render(\to_json({}), { type => 'json', process => 0 }) if ($number eq '');
28 my $result = $self->find_contact_for_number($number)
29 // $self->find_customer_vendor_for_number($number)
32 $self->render(\to_json($result), { type => 'json', process => 0 });
35 sub find_contact_for_number {
36 my ($self, $number) = @_;
38 my @number_fields = qw(cp_phone1 cp_phone2 cp_mobile1 cp_mobile2 cp_fax);
40 my $contacts = SL::DB::Manager::Contact->get_all(
42 where => [ map({ (or => [ "!$_" => undef, "!$_" => "" ],) } @number_fields) ],
47 foreach my $contact (@{ $contacts }) {
48 foreach my $field (@number_fields) {
49 next if $self->normalize_number($contact->$field) ne $number;
58 my @cv_ids = grep { $_ } map { $_->cp_cv_id } @hits;
60 my %customers_vendors =
61 map { ($_->id => $_) } (
62 @{ SL::DB::Manager::Customer->get_all(where => [ id => \@cv_ids ], inject_results => 1) },
63 @{ SL::DB::Manager::Vendor ->get_all(where => [ id => \@cv_ids ], inject_results => 1) },
68 && $customers_vendors{$_->cp_cv_id}
69 && !$customers_vendors{$_->cp_cv_id}->obsolete
70 && ($_->cp_name !~ m{ungültig}i)
76 full_name => join(' ', grep { $_ ne '' } map { $_ // '' } ($chosen->cp_title, $chosen->cp_givenname, $chosen->cp_name)),
77 map({ my $method = "cp_$_"; ($_ => $chosen->$method // '') } qw(title givenname name phone1 phone2 mobile1 mobile2 fax)),
81 sub find_customer_vendor_for_number {
82 my ($self, $number) = @_;
84 my @number_fields = qw(phone fax);
86 my @customers_vendors = map {
87 my $class = "SL::DB::Manager::$_";
90 where => [ map({ (or => [ "!$_" => undef, "!$_" => "" ],) } @number_fields) ],
92 } qw(Customer Vendor);
96 foreach my $customer_vendor (@customers_vendors) {
97 foreach my $field (@number_fields) {
98 next if $self->normalize_number($customer_vendor->$field) ne $number;
100 push @hits, $customer_vendor;
107 my $chosen = first { !$_->obsolete } @hits;
108 $chosen //= $hits[0];
111 full_name => $chosen->name // '',
112 phone1 => $chosen->phone // '',
113 fax => $chosen->fax // '',
114 map({ ($_ => '') } qw(title givenname name phone2 mobile1 mobile2)),
118 sub normalize_number {
119 my ($self, $number) = @_;
121 return '' if ($number // '') eq '';
123 my $config = $::lx_office_conf{cti} || {};
124 my $idp = $config->{international_dialing_prefix} // '00';
125 my $country_code = $config->{our_country_code} // '49';
127 $number = SL::CTI->sanitize_number(number => $number);
129 return $number if $number =~ m{^$idp};
133 return $idp . $country_code . $number;
146 SL::Controller::Contact - Looking up information on contacts/customers/vendors based on a phone number
152 =item C<action_look_up>
154 This action can be used by external systems such as PBXes in order to
155 match a calling number to a name. Requires one form parameter to be
158 The number will then be normalized. This requires that the
159 international dialing prefix and the server's own country code be set
160 up in C<kivitendo.conf>, section C<[cti]>. They default to C<00> and
161 C<49> (Germany) respectively.
163 Next the function will look up a contact whose normalized numbers
164 equals the requested number. The fields C<phone1>, C<phone2>,
165 C<mobile1>, C<mobile2> and C<fax> are considered. Active contacts are
166 given preference over inactive ones (inactive meaning that they don't
167 belong to a customer/vendor anymore or that the customer/vendor itself
168 is flagged as obsolete).
170 If no contact is found, customers & vendors are searched. Their fields
171 C<phone> and C<fax> are considered. The first customer/vendor who
172 isn't flagged as being obsolete is chosen; if there's none, the first
175 The function always sends one JSON-encoded object. If there's no hit
176 for the number, an empty object is returned. Otherwise the following
181 =item C<full_name> — for contacts this is the concatenation of the
182 title, given name and family name; for customers/vendors it's the
185 =item C<title> — title (empty for customers/vendors)
187 =item C<givenname> — first/given name (empty for customers/vendors)
189 =item C<name> — last/family name (empty for customers/vendors)
191 =item C<phone1> — first phone number (for all object types)
193 =item C<phone2> — second phone number (empty for customers/vendors)
195 =item C<mobile1> — first mobile number (empty for customers/vendors)
197 =item C<mobile2> — second mobile number (empty for customers/vendors)
199 =item C<fax> — fax number (for all object types)
203 Here's an example how querying the API via C<curl> might look:
205 curl --user user_name:password 'https://…/kivitendo/controller.pl?action=PhoneNumber/look_up&number=0049987655443321'
207 Note that the request must be authenticated via a valid Kivitendo
208 login. However, the user doesn't need any special permissions within
209 Kivitendo; any valid Kivitendo user will do.
219 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>