diff --git a/app/assets/javascripts/app/controllers/_integration/placetel.coffee b/app/assets/javascripts/app/controllers/_integration/placetel.coffee
new file mode 100644
index 000000000..8c337700e
--- /dev/null
+++ b/app/assets/javascripts/app/controllers/_integration/placetel.coffee
@@ -0,0 +1,158 @@
+class Index extends App.ControllerIntegrationBase
+ featureIntegration: 'placetel_integration'
+ featureName: 'Placetel'
+ featureConfig: 'placetel_config'
+ description: [
+ ['This service shows you contacts of incoming calls and a caller list in realtime.']
+ ['Also caller id of outbound calls can be changed.']
+ ]
+ events:
+ 'click .js-select': 'selectAll'
+ 'change .js-switch input': 'switch'
+
+ render: =>
+ super
+ new Form(
+ el: @$('.js-form')
+ )
+
+ new App.HttpLog(
+ el: @$('.js-log')
+ facility: 'placetel'
+ )
+
+class Form extends App.Controller
+ events:
+ 'submit form': 'update'
+ 'click .js-inboundBlockCallerId .js-add': 'addInboundBlockCallerId'
+ 'click .js-outboundRouting .js-add': 'addOutboundRouting'
+ 'click .js-inboundBlockCallerId .js-remove': 'removeInboundBlockCallerId'
+ 'click .js-outboundRouting .js-remove': 'removeOutboundRouting'
+
+ constructor: ->
+ super
+ @render()
+
+ currentConfig: ->
+ config = App.Setting.get('placetel_config')
+ if !config.outbound
+ config.outbound = {}
+ if !config.outbound.routing_table
+ config.outbound.routing_table = []
+ if !config.inbound
+ config.inbound = {}
+ if !config.inbound.block_caller_ids
+ config.inbound.block_caller_ids = []
+ config
+
+ setConfig: (value) ->
+ App.Setting.set('placetel_config', value, {notify: true})
+
+ render: =>
+ @config = @currentConfig()
+
+ @html App.view('integration/placetel')(
+ config: @config
+ placetel_token: App.Setting.get('placetel_token')
+ )
+
+ updateCurrentConfig: =>
+ config = @config
+ cleanupInput = @cleanupInput
+
+ # default caller_id
+ default_caller_id = @$('input[name=default_caller_id]').val()
+ config.outbound.default_caller_id = cleanupInput(default_caller_id)
+
+ # routing table
+ config.outbound.routing_table = []
+ @$('.js-outboundRouting .js-row').each(->
+ dest = cleanupInput($(@).find('input[name="dest"]').val())
+ caller_id = cleanupInput($(@).find('input[name="caller_id"]').val())
+ note = $(@).find('input[name="note"]').val()
+ config.outbound.routing_table.push {
+ dest: dest
+ caller_id: caller_id
+ note: note
+ }
+ )
+
+ # blocked caller ids
+ config.inbound.block_caller_ids = []
+ @$('.js-inboundBlockCallerId .js-row').each(->
+ caller_id = $(@).find('input[name="caller_id"]').val()
+ note = $(@).find('input[name="note"]').val()
+ config.inbound.block_caller_ids.push {
+ caller_id: cleanupInput(caller_id)
+ note: note
+ }
+ )
+
+ @config = config
+
+ update: (e) =>
+ e.preventDefault()
+ @updateCurrentConfig()
+ @setConfig(@config)
+
+ cleanupInput: (value) ->
+ return value if !value
+ value.replace(/\s/g, '').trim()
+
+ addInboundBlockCallerId: (e) =>
+ e.preventDefault()
+ @updateCurrentConfig()
+ element = $(e.currentTarget).closest('tr')
+ caller_id = element.find('input[name="caller_id"]').val()
+ note = element.find('input[name="note"]').val()
+ return if _.isEmpty(caller_id) || _.isEmpty(note)
+ @config.inbound.block_caller_ids.push {
+ caller_id: @cleanupInput(caller_id)
+ note: note
+ }
+ @render()
+
+ addOutboundRouting: (e) =>
+ e.preventDefault()
+ @updateCurrentConfig()
+ element = $(e.currentTarget).closest('tr')
+ dest = @cleanupInput(element.find('input[name="dest"]').val())
+ caller_id = @cleanupInput(element.find('input[name="caller_id"]').val())
+ note = element.find('input[name="note"]').val()
+ return if _.isEmpty(caller_id) || _.isEmpty(dest) || _.isEmpty(note)
+ @config.outbound.routing_table.push {
+ dest: dest
+ caller_id: caller_id
+ note: note
+ }
+ @render()
+
+ removeInboundBlockCallerId: (e) =>
+ e.preventDefault()
+ @updateCurrentConfig()
+ element = $(e.currentTarget).closest('tr')
+ element.remove()
+ @updateCurrentConfig()
+
+ removeOutboundRouting: (e) =>
+ e.preventDefault()
+ @updateCurrentConfig()
+ element = $(e.currentTarget).closest('tr')
+ element.remove()
+ @updateCurrentConfig()
+
+class State
+ @current: ->
+ App.Setting.get('placetel_integration')
+
+App.Config.set(
+ 'IntegrationPlacetel'
+ {
+ name: 'Placetel'
+ target: '#system/integration/placetel'
+ description: 'VoIP service provider with realtime push.'
+ controller: Index
+ state: State
+ }
+ 'NavBarIntegrations'
+)
diff --git a/app/assets/javascripts/app/controllers/cti.coffee b/app/assets/javascripts/app/controllers/cti.coffee
index 5ae318b38..02ebe3387 100644
--- a/app/assets/javascripts/app/controllers/cti.coffee
+++ b/app/assets/javascripts/app/controllers/cti.coffee
@@ -99,6 +99,7 @@ class App.CTI extends App.Controller
featureActive: =>
return true if @Config.get('sipgate_integration')
return true if @Config.get('cti_integration')
+ return true if @Config.get('placetel_integration')
false
render: ->
diff --git a/app/assets/javascripts/app/views/integration/cti.jst.eco b/app/assets/javascripts/app/views/integration/cti.jst.eco
index d8ed35186..18346d10a 100644
--- a/app/assets/javascripts/app/views/integration/cti.jst.eco
+++ b/app/assets/javascripts/app/views/integration/cti.jst.eco
@@ -40,7 +40,7 @@
<% end %>
|
- |
+ |
| <%- @Icon('plus-small') %> <%- @T('Add') %>
diff --git a/app/controllers/cti_controller.rb b/app/controllers/cti_controller.rb
index 2fdc71b4d..cbfa90e24 100644
--- a/app/controllers/cti_controller.rb
+++ b/app/controllers/cti_controller.rb
@@ -15,6 +15,11 @@ class CtiController < ApplicationController
name: 'sipgate.io',
enabled: Setting.get('sipgate_integration'),
url: '#system/integration/sipgate',
+ },
+ {
+ name: 'Placetel',
+ enabled: Setting.get('placetel_integration'),
+ url: '#system/integration/placetel',
}
]
diff --git a/app/controllers/integration/placetel_controller.rb b/app/controllers/integration/placetel_controller.rb
new file mode 100644
index 000000000..58c0cc215
--- /dev/null
+++ b/app/controllers/integration/placetel_controller.rb
@@ -0,0 +1,167 @@
+# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
+require 'builder'
+
+class Integration::PlacetelController < ApplicationController
+ skip_before_action :verify_csrf_token
+ before_action :check_configured, :check_token
+
+ # notify about inbound call / block inbound call
+ def event
+
+ local_params = ActiveSupport::HashWithIndifferentAccess.new(params.permit!.to_h)
+
+ # do placetel event mapping
+ if local_params['event'] == 'IncomingCall'
+ local_params['direction'] = 'in'
+ local_params['event'] = 'newCall'
+ elsif local_params['event'] == 'HungUp'
+ local_params['event'] = 'hangup'
+ elsif local_params['event'] == 'CallAccepted'
+ local_params['event'] = 'answer'
+ end
+
+ if local_params['direction'].blank?
+ entry = Cti::Log.find_by(call_id: params[:call_id])
+ if entry
+ local_params['direction'] = entry.direction
+ end
+ end
+
+ if local_params['type'] == 'missed'
+ local_params['cause'] = 'cancel'
+ elsif local_params['type'] == 'voicemail'
+ local_params['cause'] = 'voicemail'
+ elsif local_params['type'] == 'blocked'
+ local_params['cause'] = 'blocked'
+ elsif local_params['type'] == 'accepted'
+ local_params['cause'] = 'normalClearing'
+ end
+
+ if local_params['direction'] == 'in'
+ if local_params['event'] == 'newCall'
+ config_inbound = config_integration[:inbound] || {}
+ block_caller_ids = config_inbound[:block_caller_ids] || []
+
+ # check if call need to be blocked
+ block_caller_ids.each do |item|
+ next unless item[:caller_id] == local_params['from']
+
+ xml = Builder::XmlMarkup.new(indent: 2)
+ xml.instruct!
+ content = xml.Response() do
+ xml.Reject('reason' => 'busy')
+ end
+ send_data content, type: 'application/xml; charset=UTF-8;'
+
+ #local_params['Reject'] = 'busy'
+ local_params['comment'] = 'reject, busy'
+ if local_params['user']
+ local_params['comment'] = "#{local_params['user']} -> reject, busy"
+ end
+ Cti::Log.process(local_params)
+ return true
+ end
+ end
+
+ Cti::Log.process(local_params)
+
+ xml = Builder::XmlMarkup.new(indent: 2)
+ xml.instruct!
+ content = xml.Response()
+ send_data content, type: 'application/xml; charset=UTF-8;'
+ return true
+ elsif local_params['direction'] == 'out'
+ config_outbound = config_integration[:outbound]
+ routing_table = nil
+ default_caller_id = nil
+ if config_outbound.present?
+ routing_table = config_outbound[:routing_table]
+ default_caller_id = config_outbound[:default_caller_id]
+ end
+
+ xml = Builder::XmlMarkup.new(indent: 2)
+ xml.instruct!
+
+ # set callerId
+ content = nil
+ to = local_params[:to]
+ from = nil
+ if to && routing_table.present?
+ routing_table.each do |row|
+ dest = row[:dest].gsub(/\*/, '.+?')
+ next if to !~ /^#{dest}$/
+
+ from = row[:caller_id]
+ content = xml.Response() do
+ xml.Dial(callerId: from) { xml.Number(params[:to]) }
+ end
+ break
+ end
+ if !content && default_caller_id.present?
+ from = default_caller_id
+ content = xml.Response() do
+ xml.Dial(callerId: default_caller_id) { xml.Number(params[:to]) }
+ end
+ end
+ else
+ content = xml.Response()
+ end
+ send_data(content, type: 'application/xml; charset=UTF-8;')
+
+ if from.present?
+ local_params['from'] = from
+ end
+ Cti::Log.process(local_params)
+ return true
+ end
+ response_error('Invalid direction!')
+ end
+
+ private
+
+ def check_token
+ if Setting.get('placetel_token') != params[:token]
+ response_unauthorized('Invalid token, please contact your admin!')
+ return
+ end
+
+ true
+ end
+
+ def check_configured
+ http_log_config facility: 'placetel'
+
+ if !Setting.get('placetel_integration')
+ response_error('Feature is disable, please contact your admin to enable it!')
+ return
+ end
+ if config_integration.blank? || config_integration[:inbound].blank? || config_integration[:outbound].blank?
+ response_error('Feature not configured, please contact your admin!')
+ return
+ end
+
+ true
+ end
+
+ def xml_error(error, code)
+ xml = Builder::XmlMarkup.new(indent: 2)
+ xml.instruct!
+ content = xml.Response() do
+ xml.Error(error)
+ end
+ send_data content, type: 'application/xml; charset=UTF-8;', status: code
+ end
+
+ def config_integration
+ @config_integration ||= Setting.get('placetel_config')
+ end
+
+ def response_error(error)
+ xml_error(error, 422)
+ end
+
+ def response_unauthorized(error)
+ xml_error(error, 401)
+ end
+
+end
diff --git a/config/routes/integration_placetel.rb b/config/routes/integration_placetel.rb
new file mode 100644
index 000000000..d2cde16bd
--- /dev/null
+++ b/config/routes/integration_placetel.rb
@@ -0,0 +1,5 @@
+Zammad::Application.routes.draw do
+
+ match '/api/v1/placetel/:token', to: 'integration/placetel#event', via: :post
+
+end
diff --git a/db/migrate/20180921000001_setting_add_placetel.rb b/db/migrate/20180921000001_setting_add_placetel.rb
new file mode 100644
index 000000000..20ffbcc71
--- /dev/null
+++ b/db/migrate/20180921000001_setting_add_placetel.rb
@@ -0,0 +1,71 @@
+class SettingAddPlacetel < ActiveRecord::Migration[5.1]
+ def change
+
+ # return if it's a new setup
+ return if !Setting.find_by(name: 'system_init_done')
+
+ Setting.create_if_not_exists(
+ title: 'Placetel integration',
+ name: 'placetel_integration',
+ area: 'Integration::Switch',
+ description: 'Defines if Placetel (http://www.placetel.de) is enabled or not.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'placetel_integration',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ prio: 1,
+ trigger: ['menu:render', 'cti:reload'],
+ authentication: true,
+ permission: ['admin.integration'],
+ },
+ frontend: true
+ )
+ Setting.create_if_not_exists(
+ title: 'Placetel config',
+ name: 'placetel_config',
+ area: 'Integration::Placetel',
+ description: 'Defines the Placetel config.',
+ options: {},
+ state: { 'outbound' => { 'routing_table' => [], 'default_caller_id' => '' }, 'inbound' => { 'block_caller_ids' => [] } },
+ preferences: {
+ prio: 2,
+ permission: ['admin.integration'],
+ },
+ frontend: false,
+ )
+ Setting.create_if_not_exists(
+ title: 'PLACETEL Token',
+ name: 'placetel_token',
+ area: 'Integration::Placetel',
+ description: 'Token for placetel.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'placetel_token',
+ tag: 'input',
+ },
+ ],
+ },
+ state: ENV['PLACETEL_TOKEN'] || SecureRandom.urlsafe_base64(20),
+ preferences: {
+ permission: ['admin.integration'],
+ },
+ frontend: false
+ )
+
+ end
+end
diff --git a/db/seeds/settings.rb b/db/seeds/settings.rb
index c7cd1075e..fd26be282 100644
--- a/db/seeds/settings.rb
+++ b/db/seeds/settings.rb
@@ -3996,6 +3996,68 @@ Setting.create_if_not_exists(
},
frontend: false
)
+Setting.create_if_not_exists(
+ title: 'Placetel integration',
+ name: 'placetel_integration',
+ area: 'Integration::Switch',
+ description: 'Defines if Placetel (http://www.placetel.de) is enabled or not.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'placetel_integration',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ state: false,
+ preferences: {
+ prio: 1,
+ trigger: ['menu:render', 'cti:reload'],
+ authentication: true,
+ permission: ['admin.integration'],
+ },
+ frontend: true
+)
+Setting.create_if_not_exists(
+ title: 'Placetel config',
+ name: 'placetel_config',
+ area: 'Integration::Placetel',
+ description: 'Defines the Placetel config.',
+ options: {},
+ state: { 'outbound' => { 'routing_table' => [], 'default_caller_id' => '' }, 'inbound' => { 'block_caller_ids' => [] } },
+ preferences: {
+ prio: 2,
+ permission: ['admin.integration'],
+ },
+ frontend: false,
+)
+Setting.create_if_not_exists(
+ title: 'PLACETEL Token',
+ name: 'placetel_token',
+ area: 'Integration::Placetel',
+ description: 'Token for placetel.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: false,
+ name: 'placetel_token',
+ tag: 'input',
+ },
+ ],
+ },
+ state: ENV['PLACETEL_TOKEN'] || SecureRandom.urlsafe_base64(20),
+ preferences: {
+ permission: ['admin.integration'],
+ },
+ frontend: false
+)
Setting.create_if_not_exists(
title: 'Clearbit integration',
name: 'clearbit_integration',
diff --git a/script/build/cleanup.sh b/script/build/cleanup.sh
index a4287ae7f..20449769d 100755
--- a/script/build/cleanup.sh
+++ b/script/build/cleanup.sh
@@ -5,3 +5,4 @@ set -ex
rm app/assets/javascripts/app/controllers/layout_ref.coffee
rm -rf app/assets/javascripts/app/views/layout_ref/
rm app/assets/javascripts/app/controllers/karma.coffee
+rm app/assets/javascripts/app/controllers/_integration/placetel.coffee
diff --git a/spec/requests/integration/placetel_spec.rb b/spec/requests/integration/placetel_spec.rb
new file mode 100644
index 000000000..2aa6cbf6d
--- /dev/null
+++ b/spec/requests/integration/placetel_spec.rb
@@ -0,0 +1,514 @@
+require 'rails_helper'
+
+RSpec.describe 'Integration Placetel', type: :request do
+
+ let(:agent_user) do
+ create(:agent_user)
+ end
+ let!(:customer_user1) do
+ create(
+ :customer_user,
+ login: 'ticket-caller_id_cti-customer1@example.com',
+ firstname: 'CallerId',
+ lastname: 'Customer1',
+ phone: '+49 99999 222222',
+ fax: '+49 99999 222223',
+ mobile: '+01114100300',
+ note: 'Phone at home: +49 99999 222224',
+ )
+ end
+ let!(:customer_user2) do
+ create(
+ :customer_user,
+ login: 'ticket-caller_id_cti-customer2@example.com',
+ firstname: 'CallerId',
+ lastname: 'Customer2',
+ phone: '+49 99999 222222 2',
+ )
+ end
+ let!(:customer_user3) do
+ create(
+ :customer_user,
+ login: 'ticket-caller_id_cti-customer3@example.com',
+ firstname: 'CallerId',
+ lastname: 'Customer3',
+ phone: '+49 99999 222222 2',
+ )
+ end
+
+ before(:each) do
+ Cti::Log.destroy_all
+
+ Setting.set('placetel_integration', true)
+ Setting.set('placetel_config', {
+ outbound: {
+ routing_table: [
+ {
+ dest: '41*',
+ caller_id: '41715880339000',
+ },
+ {
+ dest: '491714000000',
+ caller_id: '41715880339000',
+ },
+ ],
+ default_caller_id: '4930777000000',
+ },
+ inbound: {
+ block_caller_ids: [
+ {
+ caller_id: '491715000000',
+ note: 'some note',
+ }
+ ],
+ notify_user_ids: {
+ 2 => true,
+ 4 => false,
+ },
+ }
+ })
+
+ Cti::CallerId.rebuild
+ end
+
+ describe 'request handling' do
+
+ it 'does token check' do
+ params = 'event=IncomingCall&from=01114100300&to=030600000000&call_id=4991155921769858278-1'
+ post '/api/v1/placetel/not_existing_token', params: params
+ expect(response).to have_http_status(401)
+
+ error = nil
+ local_response = REXML::Document.new(response.body)
+ local_response.elements.each('Response/Error') do |element|
+ error = element.text
+ end
+ expect(error).to eq('Invalid token, please contact your admin!')
+ end
+
+ it 'does basic call' do
+ token = Setting.get('placetel_token')
+
+ # inbound - I
+ params = 'event=IncomingCall&from=01114100300&to=030600000000&call_id=4991155921769858278-1'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+
+ local_response = REXML::Document.new(response.body)
+ expect(local_response.elements.count).to eq(1)
+ expect(local_response.elements.first.to_s).to eq('')
+
+ # inbound - II - block caller
+ params = 'event=IncomingCall&from=491715000000&to=030600000000&call_id=4991155921769858278-2'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+
+ local_response = REXML::Document.new(response.body)
+ reason = nil
+ local_response.elements.each('Response/Reject') do |element|
+ reason = element.attributes['reason']
+ end
+ expect(reason).to eq('busy')
+
+ # outbound - I - set default_caller_id
+ params = 'event=newCall&direction=out&from=030600000000&to=01114100300&call_id=8621106404543334274-3'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+
+ caller_id = nil
+ number_to_dail = nil
+ lcoal_response = REXML::Document.new(response.body)
+ lcoal_response.elements.each('Response/Dial') do |element|
+ caller_id = element.attributes['callerId']
+ end
+ lcoal_response.elements.each('Response/Dial/Number') do |element|
+ number_to_dail = element.text
+ end
+ expect(caller_id).to eq('4930777000000')
+ expect(number_to_dail).to eq('01114100300')
+
+ # outbound - II - set caller_id based on routing_table by explicite number
+ params = 'event=newCall&direction=out&from=030600000000&to=491714000000&call_id=8621106404543334274-4'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+
+ caller_id = nil
+ number_to_dail = nil
+ lcoal_response = REXML::Document.new(response.body)
+ lcoal_response.elements.each('Response/Dial') do |element|
+ caller_id = element.attributes['callerId']
+ end
+ lcoal_response.elements.each('Response/Dial/Number') do |element|
+ number_to_dail = element.text
+ end
+ expect(caller_id).to eq('41715880339000')
+ expect(number_to_dail).to eq('491714000000')
+
+ # outbound - III - set caller_id based on routing_table by 41*
+ params = 'event=newCall&direction=out&from=030600000000&to=4147110000000&call_id=8621106404543334274-5'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+
+ caller_id = nil
+ number_to_dail = nil
+ lcoal_response = REXML::Document.new(response.body)
+ lcoal_response.elements.each('Response/Dial') do |element|
+ caller_id = element.attributes['callerId']
+ end
+ lcoal_response.elements.each('Response/Dial/Number') do |element|
+ number_to_dail = element.text
+ end
+ expect(caller_id).to eq('41715880339000')
+ expect(number_to_dail).to eq('4147110000000')
+
+ # no config
+ Setting.set('placetel_config', {})
+ params = 'event=IncomingCall&from=01114100300&to=030600000000&call_id=4991155921769858278-6'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(422)
+
+ error = nil
+ local_response = REXML::Document.new(response.body)
+ local_response.elements.each('Response/Error') do |element|
+ error = element.text
+ end
+ expect(error).to eq('Feature not configured, please contact your admin!')
+ end
+
+ it 'does log call' do
+ token = Setting.get('placetel_token')
+
+ # outbound - I - new call
+ params = 'event=newCall&direction=out&from=030600000000&to=01114100300&call_id=1234567890-1'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-1')
+ expect(log).to be_truthy
+ expect(log.from).to eq('4930777000000')
+ expect(log.to).to eq('01114100300')
+ expect(log.direction).to eq('out')
+ #expect(log.from_comment).to eq('user 1')
+ expect(log.to_comment).to eq('CallerId Customer1')
+ expect(log.comment).to be_nil
+ expect(log.state).to eq('newCall')
+ expect(log.done).to eq(true)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_nil
+ expect(log.end_at).to be_nil
+ expect(log.duration_waiting_time).to be_nil
+ expect(log.duration_talking_time).to be_nil
+
+ # outbound - I - hangup by agent
+ params = 'event=HungUp&call_id=1234567890-1&type=missed'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-1')
+ expect(log).to be_truthy
+ expect(log.from).to eq('4930777000000')
+ expect(log.to).to eq('01114100300')
+ expect(log.direction).to eq('out')
+ #expect(log.from_comment).to eq('user 1')
+ expect(log.to_comment).to eq('CallerId Customer1')
+ expect(log.comment).to eq('cancel')
+ expect(log.state).to eq('hangup')
+ expect(log.done).to eq(true)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_nil
+ expect(log.end_at).to be_truthy
+ expect(log.duration_waiting_time).to be_truthy
+ expect(log.duration_talking_time).to be_nil
+
+ # outbound - II - new call
+ params = 'event=newCall&direction=out&from=030600000000&to=01114100300&call_id=1234567890-2'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-2')
+ expect(log).to be_truthy
+ expect(log.from).to eq('4930777000000')
+ expect(log.to).to eq('01114100300')
+ expect(log.direction).to eq('out')
+ # expect(log.from_comment).to eq('user 1')
+ expect(log.to_comment).to eq('CallerId Customer1')
+ expect(log.comment).to be_nil
+ expect(log.state).to eq('newCall')
+ expect(log.done).to eq(true)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_nil
+ expect(log.end_at).to be_nil
+ expect(log.duration_waiting_time).to be_nil
+ expect(log.duration_talking_time).to be_nil
+
+ # outbound - II - answer by customer
+ params = 'event=CallAccepted&call_id=1234567890-2&from=030600000000&to=01114100300'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-2')
+ expect(log).to be_truthy
+ expect(log.from).to eq('4930777000000')
+ expect(log.to).to eq('01114100300')
+ expect(log.direction).to eq('out')
+ # expect(log.from_comment).to eq('user 1')
+ expect(log.to_comment).to eq('CallerId Customer1')
+ expect(log.comment).to be_nil
+ expect(log.state).to eq('answer')
+ expect(log.done).to eq(true)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_truthy
+ expect(log.end_at).to be_nil
+ expect(log.duration_waiting_time).to be_truthy
+ expect(log.duration_talking_time).to be_nil
+
+ # outbound - II - hangup by customer
+ params = 'event=HungUp&call_id=1234567890-2&type=accepted&from=030600000000&to=01114100300'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-2')
+ expect(log).to be_truthy
+ expect(log.from).to eq('4930777000000')
+ expect(log.to).to eq('01114100300')
+ expect(log.direction).to eq('out')
+ # expect(log.from_comment).to eq('user 1')
+ expect(log.to_comment).to eq('CallerId Customer1')
+ expect(log.comment).to eq('normalClearing')
+ expect(log.state).to eq('hangup')
+ expect(log.done).to eq(true)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_truthy
+ expect(log.end_at).to be_truthy
+ expect(log.duration_waiting_time).to be_truthy
+ expect(log.duration_talking_time).to be_truthy
+
+ # inbound - I - new call
+ params = 'event=IncomingCall&to=030600000000&from=01114100300&call_id=1234567890-3'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-3')
+ expect(log).to be_truthy
+ expect(log.to).to eq('030600000000')
+ expect(log.from).to eq('01114100300')
+ expect(log.direction).to eq('in')
+ #expect(log.to_comment).to eq('user 1')
+ expect(log.from_comment).to eq('CallerId Customer1')
+ expect(log.comment).to be_nil
+ expect(log.state).to eq('newCall')
+ expect(log.done).to eq(false)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_nil
+ expect(log.end_at).to be_nil
+ expect(log.duration_waiting_time).to be_nil
+ expect(log.duration_talking_time).to be_nil
+
+ # inbound - I - answer by customer
+ params = 'event=CallAccepted&call_id=1234567890-3&to=030600000000&from=01114100300'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-3')
+ expect(log).to be_truthy
+ expect(log.to).to eq('030600000000')
+ expect(log.from).to eq('01114100300')
+ expect(log.direction).to eq('in')
+ #expect(log.to_comment).to eq('user 1')
+ expect(log.from_comment).to eq('CallerId Customer1')
+ expect(log.comment).to be_nil
+ expect(log.state).to eq('answer')
+ expect(log.done).to eq(true)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_truthy
+ expect(log.end_at).to be_nil
+ expect(log.duration_waiting_time).to be_truthy
+ expect(log.duration_talking_time).to be_nil
+
+ # inbound - I - hangup by customer
+ params = 'event=HungUp&call_id=1234567890-3&type=accepted&to=030600000000&from=01114100300'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-3')
+ expect(log).to be_truthy
+ expect(log.to).to eq('030600000000')
+ expect(log.from).to eq('01114100300')
+ expect(log.direction).to eq('in')
+ #expect(log.to_comment).to eq('user 1')
+ expect(log.from_comment).to eq('CallerId Customer1')
+ expect(log.comment).to eq('normalClearing')
+ expect(log.state).to eq('hangup')
+ expect(log.done).to eq(true)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_truthy
+ expect(log.end_at).to be_truthy
+ expect(log.duration_waiting_time).to be_truthy
+ expect(log.duration_talking_time).to be_truthy
+
+ # inbound - II - new call
+ params = 'event=IncomingCall&to=030600000000&from=01114100300&call_id=1234567890-4'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-4')
+ expect(log).to be_truthy
+ expect(log.to).to eq('030600000000')
+ expect(log.from).to eq('01114100300')
+ expect(log.direction).to eq('in')
+ #expect(log.to_comment).to eq('user 1,user 2')
+ expect(log.from_comment).to eq('CallerId Customer1')
+ expect(log.comment).to be_nil
+ expect(log.state).to eq('newCall')
+ expect(log.done).to eq(false)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_nil
+ expect(log.end_at).to be_nil
+ expect(log.duration_waiting_time).to be_nil
+ expect(log.duration_talking_time).to be_nil
+
+ # inbound - II - answer by voicemail
+ params = 'event=CallAccepted&call_id=1234567890-4&to=030600000000&from=01114100300&user=voicemail'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-4')
+ expect(log).to be_truthy
+ expect(log.to).to eq('030600000000')
+ expect(log.from).to eq('01114100300')
+ expect(log.direction).to eq('in')
+ expect(log.to_comment).to eq('voicemail')
+ expect(log.from_comment).to eq('CallerId Customer1')
+ expect(log.comment).to be_nil
+ expect(log.state).to eq('answer')
+ expect(log.done).to eq(true)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_truthy
+ expect(log.end_at).to be_nil
+ expect(log.duration_waiting_time).to be_truthy
+ expect(log.duration_talking_time).to be_nil
+
+ # inbound - II - hangup by customer
+ params = 'event=HungUp&call_id=1234567890-4&type=accepted&to=030600000000&from=01114100300'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-4')
+ expect(log).to be_truthy
+ expect(log.to).to eq('030600000000')
+ expect(log.from).to eq('01114100300')
+ expect(log.direction).to eq('in')
+ expect(log.to_comment).to eq('voicemail')
+ expect(log.from_comment).to eq('CallerId Customer1')
+ expect(log.comment).to eq('normalClearing')
+ expect(log.state).to eq('hangup')
+ expect(log.done).to eq(false)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_truthy
+ expect(log.end_at).to be_truthy
+ expect(log.duration_waiting_time).to be_truthy
+ expect(log.duration_talking_time).to be_truthy
+
+ # inbound - III - new call
+ params = 'event=IncomingCall&to=030600000000&from=01114100300&call_id=1234567890-5'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-5')
+ expect(log).to be_truthy
+ expect(log.to).to eq('030600000000')
+ expect(log.from).to eq('01114100300')
+ expect(log.direction).to eq('in')
+ #expect(log.to_comment).to eq('user 1,user 2')
+ expect(log.from_comment).to eq('CallerId Customer1')
+ expect(log.comment).to be_nil
+ expect(log.state).to eq('newCall')
+ expect(log.done).to eq(false)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_nil
+ expect(log.end_at).to be_nil
+ expect(log.duration_waiting_time).to be_nil
+ expect(log.duration_talking_time).to be_nil
+
+ # inbound - III - hangup by customer
+ params = 'event=HungUp&call_id=1234567890-5&type=accepted&to=030600000000&from=01114100300'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-5')
+ expect(log).to be_truthy
+ expect(log.to).to eq('030600000000')
+ expect(log.from).to eq('01114100300')
+ expect(log.direction).to eq('in')
+ #expect(log.to_comment).to eq('user 1,user 2')
+ expect(log.from_comment).to eq('CallerId Customer1')
+ expect(log.comment).to eq('normalClearing')
+ expect(log.state).to eq('hangup')
+ expect(log.done).to eq(false)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_nil
+ expect(log.end_at).to be_truthy
+ expect(log.duration_waiting_time).to be_truthy
+ expect(log.duration_talking_time).to be_nil
+
+ # inbound - IV - new call
+ params = 'event=IncomingCall&to=030600000000&from=49999992222222&call_id=1234567890-6'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-6')
+ expect(log).to be_truthy
+ expect(log.to).to eq('030600000000')
+ expect(log.from).to eq('49999992222222')
+ expect(log.direction).to eq('in')
+ #expect(log.to_comment).to eq('user 1,user 2')
+ expect(log.from_comment).to eq('CallerId Customer3,CallerId Customer2')
+ expect(log.preferences['to']).to be_falsey
+ expect(log.preferences['from']).to be_truthy
+ expect(log.comment).to be_nil
+ expect(log.state).to eq('newCall')
+ expect(log.done).to eq(false)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_nil
+ expect(log.end_at).to be_nil
+ expect(log.duration_waiting_time).to be_nil
+ expect(log.duration_talking_time).to be_nil
+
+ # inbound - IV - new call
+ params = 'event=IncomingCall&to=030600000000&from=anonymous&call_id=1234567890-7'
+ post "/api/v1/placetel/#{token}", params: params
+ expect(response).to have_http_status(200)
+ log = Cti::Log.find_by(call_id: '1234567890-7')
+ expect(log).to be_truthy
+ expect(log.to).to eq('030600000000')
+ expect(log.from).to eq('anonymous')
+ expect(log.direction).to eq('in')
+ #expect(log.to_comment).to eq('user 1,user 2')
+ expect(log.from_comment).to be_nil
+ expect(log.preferences['to']).to be_falsey
+ expect(log.preferences['from']).to be_falsey
+ expect(log.comment).to be_nil
+ expect(log.state).to eq('newCall')
+ expect(log.done).to eq(false)
+ expect(log.initialized_at).to be_truthy
+ expect(log.start_at).to be_nil
+ expect(log.end_at).to be_nil
+ expect(log.duration_waiting_time).to be_nil
+ expect(log.duration_talking_time).to be_nil
+
+ # get caller list
+ get '/api/v1/cti/log'
+ expect(response).to have_http_status(401)
+
+ authenticated_as(agent_user)
+ get '/api/v1/cti/log', as: :json
+ expect(response).to have_http_status(200)
+ expect(json_response['list']).to be_a_kind_of(Array)
+ expect(json_response['list'].count).to eq(7)
+ expect(json_response['assets']).to be_truthy
+ expect(json_response['assets']['User']).to be_truthy
+ expect(json_response['assets']['User'][customer_user2.id.to_s]).to be_truthy
+ expect(json_response['assets']['User'][customer_user3.id.to_s]).to be_truthy
+ expect(json_response['list'][0]['call_id']).to eq('1234567890-7')
+ expect(json_response['list'][1]['call_id']).to eq('1234567890-6')
+ expect(json_response['list'][2]['call_id']).to eq('1234567890-5')
+ expect(json_response['list'][3]['call_id']).to eq('1234567890-4')
+ expect(json_response['list'][4]['call_id']).to eq('1234567890-3')
+ expect(json_response['list'][5]['call_id']).to eq('1234567890-2')
+ expect(json_response['list'][5]['state']).to eq('hangup')
+ expect(json_response['list'][5]['from']).to eq('4930777000000')
+ #expect(json_response['list'][5]['from_comment']).to eq('user 1')
+ expect(json_response['list'][5]['to']).to eq('01114100300')
+ expect(json_response['list'][5]['to_comment']).to eq('CallerId Customer1')
+ expect(json_response['list'][5]['comment']).to eq('normalClearing')
+ expect(json_response['list'][5]['state']).to eq('hangup')
+ expect(json_response['list'][6]['call_id']).to eq('1234567890-1')
+ end
+ end
+end
|