2016-04-28 13:15:50 +00:00
|
|
|
module Cti
|
|
|
|
class CallerId < ApplicationModel
|
|
|
|
self.table_name = 'cti_caller_ids'
|
|
|
|
|
2016-12-06 12:26:08 +00:00
|
|
|
DEFAULT_COUNTRY_ID = '49'.freeze
|
|
|
|
|
2018-07-23 08:24:23 +00:00
|
|
|
# adopt/orphan matching Cti::Log records
|
|
|
|
# (see https://github.com/zammad/zammad/issues/2057)
|
2019-02-28 14:21:59 +00:00
|
|
|
after_commit :update_cti_logs, on: :destroy, unless: -> { BulkImportInfo.enabled? }
|
|
|
|
after_commit :update_cti_logs_with_fg_optimization, on: :create, unless: -> { BulkImportInfo.enabled? }
|
2018-11-06 05:42:52 +00:00
|
|
|
|
2016-04-28 13:15:50 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
Cti::CallerId.maybe_add(
|
|
|
|
caller_id: '49123456789',
|
|
|
|
comment: 'Hairdresser Bob Smith, San Francisco', #optional
|
|
|
|
level: 'maybe', # known|maybe
|
|
|
|
user_id: 1, # optional
|
|
|
|
object: 'Ticket',
|
|
|
|
o_id: 123,
|
|
|
|
)
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.maybe_add(data)
|
2016-12-02 11:09:17 +00:00
|
|
|
record = find_or_initialize_by(
|
2016-04-28 13:15:50 +00:00
|
|
|
caller_id: data[:caller_id],
|
2016-12-02 11:09:17 +00:00
|
|
|
level: data[:level],
|
|
|
|
object: data[:object],
|
|
|
|
o_id: data[:o_id],
|
|
|
|
user_id: data[:user_id],
|
2016-04-28 13:15:50 +00:00
|
|
|
)
|
2016-12-06 14:27:07 +00:00
|
|
|
|
2016-12-05 12:30:55 +00:00
|
|
|
return record if !record.new_record?
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-12-05 09:19:18 +00:00
|
|
|
record.comment = data[:comment]
|
|
|
|
record.save!
|
2016-04-28 13:15:50 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
2019-07-09 22:07:32 +00:00
|
|
|
get items (users) for a certain caller id
|
|
|
|
|
2016-04-28 13:15:50 +00:00
|
|
|
caller_id_records = Cti::CallerId.lookup('49123456789')
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
[record1, record2, ...]
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.lookup(caller_id)
|
2018-08-07 09:51:12 +00:00
|
|
|
lookup_ids =
|
|
|
|
['known', 'maybe', nil].lazy.map do |level|
|
|
|
|
Cti::CallerId.select('MAX(id) as caller_id')
|
|
|
|
.where({ caller_id: caller_id, level: level }.compact)
|
|
|
|
.group(:user_id)
|
2019-07-04 11:16:55 +00:00
|
|
|
.order(Arel.sql('caller_id DESC')) # not used as `caller_id: :desc` because is needed for `as caller_id`
|
2018-08-07 09:51:12 +00:00
|
|
|
.limit(20)
|
|
|
|
.map(&:caller_id)
|
|
|
|
end.find(&:present?)
|
|
|
|
|
|
|
|
Cti::CallerId.where(id: lookup_ids).order(id: :desc).to_a
|
2016-04-28 13:15:50 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
Cti::CallerId.build(ticket)
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.build(record)
|
|
|
|
map = config
|
|
|
|
level = nil
|
|
|
|
model = nil
|
2017-10-01 12:25:52 +00:00
|
|
|
map.each do |item|
|
2016-04-28 13:15:50 +00:00
|
|
|
next if item[:model] != record.class
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-04-28 13:15:50 +00:00
|
|
|
level = item[:level]
|
|
|
|
model = item[:model]
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-04-28 13:15:50 +00:00
|
|
|
return if !level || !model
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-04-28 13:15:50 +00:00
|
|
|
build_item(record, model, level)
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
Cti::CallerId.build_item(record, model, level)
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.build_item(record, model, level)
|
|
|
|
|
|
|
|
# use first customer article
|
|
|
|
if model == Ticket
|
|
|
|
article = record.articles.first
|
|
|
|
return if !article
|
|
|
|
return if article.sender.name != 'Customer'
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-04-28 13:15:50 +00:00
|
|
|
record = article
|
|
|
|
end
|
|
|
|
|
|
|
|
# set user id
|
|
|
|
user_id = record[:created_by_id]
|
|
|
|
if model == User
|
2018-08-31 10:25:06 +00:00
|
|
|
if record.destroyed?
|
|
|
|
Cti::CallerId.where(user_id: user_id).destroy_all
|
|
|
|
return
|
|
|
|
end
|
2016-04-28 13:15:50 +00:00
|
|
|
user_id = record.id
|
|
|
|
end
|
|
|
|
return if !user_id
|
|
|
|
|
|
|
|
# get caller ids
|
|
|
|
caller_ids = []
|
|
|
|
attributes = record.attributes
|
2017-11-23 08:09:44 +00:00
|
|
|
attributes.each_value do |value|
|
2016-04-28 13:15:50 +00:00
|
|
|
next if value.class != String
|
2017-11-23 08:09:44 +00:00
|
|
|
next if value.blank?
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-12-06 12:26:08 +00:00
|
|
|
local_caller_ids = Cti::CallerId.extract_numbers(value)
|
2017-11-23 08:09:44 +00:00
|
|
|
next if local_caller_ids.blank?
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-04-28 13:15:50 +00:00
|
|
|
caller_ids = caller_ids.concat(local_caller_ids)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-04-28 13:15:50 +00:00
|
|
|
|
2018-08-17 07:48:12 +00:00
|
|
|
# search for caller ids to keep
|
|
|
|
caller_ids_to_add = []
|
|
|
|
existing_record_ids = Cti::CallerId.where(object: model.to_s, o_id: record.id).pluck(:id)
|
|
|
|
caller_ids.uniq.each do |caller_id|
|
|
|
|
existing_record_id = Cti::CallerId.where(
|
2018-12-19 17:31:51 +00:00
|
|
|
object: model.to_s,
|
|
|
|
o_id: record.id,
|
2018-08-17 07:48:12 +00:00
|
|
|
caller_id: caller_id,
|
2018-12-19 17:31:51 +00:00
|
|
|
level: level,
|
|
|
|
user_id: user_id,
|
2018-08-17 07:48:12 +00:00
|
|
|
).pluck(:id)
|
|
|
|
if existing_record_id[0]
|
|
|
|
existing_record_ids.delete(existing_record_id[0])
|
|
|
|
next
|
|
|
|
end
|
|
|
|
caller_ids_to_add.push caller_id
|
|
|
|
end
|
|
|
|
|
|
|
|
# delete not longer existing caller ids
|
|
|
|
existing_record_ids.each do |record_id|
|
|
|
|
Cti::CallerId.destroy(record_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
# create new caller ids
|
|
|
|
caller_ids_to_add.each do |caller_id|
|
2016-04-28 13:15:50 +00:00
|
|
|
Cti::CallerId.maybe_add(
|
|
|
|
caller_id: caller_id,
|
2018-12-19 17:31:51 +00:00
|
|
|
level: level,
|
|
|
|
object: model.to_s,
|
|
|
|
o_id: record.id,
|
|
|
|
user_id: user_id,
|
2016-04-28 13:15:50 +00:00
|
|
|
)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-04-28 13:15:50 +00:00
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
Cti::CallerId.rebuild
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.rebuild
|
2016-12-02 11:09:17 +00:00
|
|
|
transaction do
|
|
|
|
delete_all
|
2017-10-01 12:25:52 +00:00
|
|
|
config.each do |item|
|
2016-12-02 11:09:17 +00:00
|
|
|
level = item[:level]
|
|
|
|
model = item[:model]
|
|
|
|
item[:model].find_each(batch_size: 500) do |record|
|
|
|
|
build_item(record, model, level)
|
|
|
|
end
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-12-02 11:09:17 +00:00
|
|
|
end
|
2016-04-28 13:15:50 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
Cti::CallerId.config
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
[
|
|
|
|
{
|
|
|
|
model: User,
|
|
|
|
level: 'known',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
model: Ticket,
|
|
|
|
level: 'maybe',
|
|
|
|
},
|
|
|
|
]
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.config
|
|
|
|
[
|
|
|
|
{
|
|
|
|
model: User,
|
|
|
|
level: 'known',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
model: Ticket,
|
|
|
|
level: 'maybe',
|
|
|
|
},
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
2016-12-06 12:26:08 +00:00
|
|
|
caller_ids = Cti::CallerId.extract_numbers('...')
|
2016-04-28 13:15:50 +00:00
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
['49123456789', '49987654321']
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
2016-12-06 12:26:08 +00:00
|
|
|
def self.extract_numbers(text)
|
|
|
|
# see specs for example
|
2016-12-06 13:05:19 +00:00
|
|
|
return [] if !text.is_a?(String)
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2020-06-08 07:17:29 +00:00
|
|
|
text.scan(/([\d|\s|\-|(|)]{6,26})/).map do |match|
|
2016-12-06 12:26:08 +00:00
|
|
|
normalize_number(match[0])
|
|
|
|
end
|
|
|
|
end
|
2016-04-28 13:15:50 +00:00
|
|
|
|
2016-12-06 12:26:08 +00:00
|
|
|
def self.normalize_number(number)
|
|
|
|
number = number.gsub(/[\s-]/, '')
|
|
|
|
number.gsub!(/^(00)?(\+?\d\d)\(0?(\d*)\)/, '\\1\\2\\3')
|
|
|
|
number.gsub!(/\D/, '')
|
|
|
|
case number
|
|
|
|
when /^00/
|
2020-05-11 12:49:22 +00:00
|
|
|
number[2..]
|
2016-12-06 12:26:08 +00:00
|
|
|
when /^0/
|
2020-05-11 12:49:22 +00:00
|
|
|
DEFAULT_COUNTRY_ID + number[1..]
|
2016-12-06 12:26:08 +00:00
|
|
|
else
|
|
|
|
number
|
|
|
|
end
|
2016-04-28 13:15:50 +00:00
|
|
|
end
|
|
|
|
|
2018-10-16 08:45:15 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
from_comment, preferences = Cti::CallerId.get_comment_preferences('00491710000000', 'from')
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
[
|
|
|
|
"Bob Smith",
|
|
|
|
{
|
|
|
|
"from"=>[
|
|
|
|
{
|
|
|
|
"id"=>1961634,
|
|
|
|
"caller_id"=>"491710000000",
|
|
|
|
"comment"=>nil,
|
|
|
|
"level"=>"known",
|
|
|
|
"object"=>"User",
|
|
|
|
"o_id"=>3,
|
|
|
|
"user_id"=>3,
|
|
|
|
"preferences"=>nil,
|
|
|
|
"created_at"=>Mon, 24 Sep 2018 15:19:48 UTC +00:00,
|
|
|
|
"updated_at"=>Mon, 24 Sep 2018 15:19:48 UTC +00:00,
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
2016-11-29 20:12:27 +00:00
|
|
|
def self.get_comment_preferences(caller_id, direction)
|
|
|
|
from_comment_known = ''
|
|
|
|
from_comment_maybe = ''
|
|
|
|
preferences_known = {}
|
|
|
|
preferences_known[direction] = []
|
|
|
|
preferences_maybe = {}
|
|
|
|
preferences_maybe[direction] = []
|
|
|
|
|
2017-10-01 12:25:52 +00:00
|
|
|
lookup(extract_numbers(caller_id)).each do |record|
|
2016-11-29 20:12:27 +00:00
|
|
|
if record.level == 'known'
|
2017-09-08 08:28:34 +00:00
|
|
|
preferences_known[direction].push record.attributes
|
2016-11-29 20:12:27 +00:00
|
|
|
else
|
2017-09-08 08:28:34 +00:00
|
|
|
preferences_maybe[direction].push record.attributes
|
2016-11-29 20:12:27 +00:00
|
|
|
end
|
|
|
|
comment = ''
|
|
|
|
if record.user_id
|
|
|
|
user = User.lookup(id: record.user_id)
|
|
|
|
if user
|
|
|
|
comment += user.fullname
|
|
|
|
end
|
2017-11-23 08:09:44 +00:00
|
|
|
elsif record.comment.present?
|
2016-11-29 20:12:27 +00:00
|
|
|
comment += record.comment
|
|
|
|
end
|
|
|
|
if record.level == 'known'
|
2017-11-23 08:09:44 +00:00
|
|
|
if from_comment_known.present?
|
2016-11-29 20:12:27 +00:00
|
|
|
from_comment_known += ','
|
|
|
|
end
|
|
|
|
from_comment_known += comment
|
|
|
|
else
|
2017-11-23 08:09:44 +00:00
|
|
|
if from_comment_maybe.present?
|
2016-11-29 20:12:27 +00:00
|
|
|
from_comment_maybe += ','
|
|
|
|
end
|
|
|
|
from_comment_maybe += comment
|
|
|
|
end
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-11-23 08:09:44 +00:00
|
|
|
return [from_comment_known, preferences_known] if from_comment_known.present?
|
|
|
|
return ["maybe #{from_comment_maybe}", preferences_maybe] if from_comment_maybe.present?
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-11-29 20:12:27 +00:00
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
2019-07-09 22:07:32 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
return users by caller_id
|
|
|
|
|
|
|
|
[user1, user2] = Cti::CallerId.known_agents_by_number('491234567')
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.known_agents_by_number(number)
|
|
|
|
users = []
|
|
|
|
caller_ids = Cti::CallerId.extract_numbers(number)
|
|
|
|
caller_id_records = Cti::CallerId.lookup(caller_ids)
|
|
|
|
caller_id_records.each do |caller_id_record|
|
|
|
|
next if caller_id_record.level != 'known'
|
|
|
|
|
|
|
|
user = User.find_by(id: caller_id_record.user_id)
|
|
|
|
next if !user
|
|
|
|
next if !user.permissions?('cti.agent')
|
|
|
|
|
|
|
|
users.push user
|
|
|
|
end
|
|
|
|
users
|
|
|
|
end
|
|
|
|
|
2018-07-23 08:24:23 +00:00
|
|
|
def update_cti_logs
|
2018-08-17 07:48:12 +00:00
|
|
|
return if object != 'User'
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2018-07-23 08:24:23 +00:00
|
|
|
UpdateCtiLogsByCallerJob.perform_later(caller_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
def update_cti_logs_with_fg_optimization
|
2018-08-17 07:48:12 +00:00
|
|
|
return if object != 'User'
|
|
|
|
return if level != 'known'
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2018-07-23 08:24:23 +00:00
|
|
|
UpdateCtiLogsByCallerJob.perform_now(caller_id, limit: 20)
|
|
|
|
UpdateCtiLogsByCallerJob.perform_later(caller_id, limit: 40, offset: 20)
|
|
|
|
end
|
2016-04-28 13:15:50 +00:00
|
|
|
end
|
|
|
|
end
|