From 2538b8c069f23816c7ff7a9558ccb59d0e74eb2d Mon Sep 17 00:00:00 2001 From: "i.navrotskyj" Date: Fri, 24 May 2024 14:26:42 +0300 Subject: [PATCH 1/2] WTEL-4577 --- store/sqlstore/member_store.go | 6 +- .../sqlstore/migration/24.04/24.02-24.04.sql | 130 ++++++++++++++++++ 2 files changed, 134 insertions(+), 2 deletions(-) diff --git a/store/sqlstore/member_store.go b/store/sqlstore/member_store.go index 25ded87b..f8ab70dd 100644 --- a/store/sqlstore/member_store.go +++ b/store/sqlstore/member_store.go @@ -748,11 +748,13 @@ into call_center.cc_member_attempt_history (id, domain_id, queue_id, member_id, agent_id, bucket_id, destination, display, description, list_communication_id, joined_at, leaving_at, agent_call_id, member_call_id, offering_at, reporting_at, bridged_at, channel, seq, resource_group_id, answered_at, team_id, - transferred_at, transferred_agent_id, transferred_attempt_id, parent_id, node_id, form_fields, import_id) + transferred_at, transferred_agent_id, transferred_attempt_id, parent_id, node_id, form_fields, + import_id, variables) select a.id, a.domain_id, a.queue_id, a.member_id, a.weight, a.resource_id, a.result, a.agent_id, a.bucket_id, a.destination, a.display, a.description, a.list_communication_id, a.joined_at, a.leaving_at, a.agent_call_id, a.member_call_id, a.offering_at, a.reporting_at, a.bridged_at, a.channel, a.seq, a.resource_group_id, a.answered_at, a.team_id, - a.transferred_at, a.transferred_agent_id, a.transferred_attempt_id, a.parent_id, a.node_id, a.form_fields, a.import_id + a.transferred_at, a.transferred_agent_id, a.transferred_attempt_id, a.parent_id, a.node_id, a.form_fields, + a.import_id, a.variables from del a returning id, result`) diff --git a/store/sqlstore/migration/24.04/24.02-24.04.sql b/store/sqlstore/migration/24.04/24.02-24.04.sql index 6e1c0c9c..297ff9d2 100644 --- a/store/sqlstore/migration/24.04/24.02-24.04.sql +++ b/store/sqlstore/migration/24.04/24.02-24.04.sql @@ -8,6 +8,8 @@ alter table call_center.cc_calls add column if not exists contact_id bigint; alter table call_center.cc_calls_history add column if not exists contact_id bigint; alter table call_center.cc_member_attempt add column if not exists queue_params jsonb; +alter table call_center.cc_member_attempt add column if not exists variables jsonb; +alter table call_center.cc_member_attempt_history add column if not exists variables jsonb; alter table call_center.cc_calls add column if not exists heartbeat timestamp with time zone; @@ -1496,3 +1498,131 @@ CREATE UNIQUE INDEX cc_team_trigger_team_id_name_uindex ON call_center.cc_team_t CREATE UNIQUE INDEX cc_team_trigger_team_id_schema_id_uindex ON call_center.cc_team_trigger USING btree (team_id, schema_id); + + +-- +-- Name: cc_attempt_end_reporting(bigint, character varying, character varying, timestamp with time zone, timestamp with time zone, integer, jsonb, integer, integer, boolean, boolean); Type: FUNCTION; Schema: call_center; Owner: - +-- + +CREATE or replace FUNCTION call_center.cc_attempt_end_reporting(attempt_id_ bigint, status_ character varying, description_ character varying DEFAULT NULL::character varying, expire_at_ timestamp with time zone DEFAULT NULL::timestamp with time zone, next_offering_at_ timestamp with time zone DEFAULT NULL::timestamp with time zone, sticky_agent_id_ integer DEFAULT NULL::integer, variables_ jsonb DEFAULT NULL::jsonb, max_attempts_ integer DEFAULT 0, wait_between_retries_ integer DEFAULT 60, exclude_dest boolean DEFAULT NULL::boolean, _per_number boolean DEFAULT false) RETURNS record + LANGUAGE plpgsql +AS $$ +declare + attempt call_center.cc_member_attempt%rowtype; + agent_timeout_ timestamptz; + time_ int8 = extract(EPOCH from now()) * 1000; + user_id_ int8 = null; + domain_id_ int8; + wrap_time_ int; + other_cnt_ int; + stop_cause_ varchar; + agent_channel_ varchar; +begin + + if next_offering_at_ notnull and not attempt.result in ('success', 'cancel') and next_offering_at_ < now() then + -- todo move to application + raise exception 'bad parameter: next distribute at'; + end if; + + + update call_center.cc_member_attempt + set state = 'leaving', + reporting_at = now(), + leaving_at = case when leaving_at isnull then now() else leaving_at end, + result = status_, + variables = case when variables_ notnull then coalesce(variables::jsonb, '{}') || variables_ else variables end, + description = description_ + where id = attempt_id_ and state != 'leaving' + returning * into attempt; + + if attempt.id isnull then + return null; +-- raise exception 'not found %', attempt_id_; + end if; + + if attempt.member_id notnull then + update call_center.cc_member m + set last_hangup_at = time_, + variables = case when variables_ notnull then coalesce(m.variables::jsonb, '{}') || variables_ else m.variables end, + expire_at = case when expire_at_ isnull then m.expire_at else expire_at_ end, + agent_id = case when sticky_agent_id_ isnull then m.agent_id else sticky_agent_id_ end, + + stop_at = case when next_offering_at_ notnull or + m.stop_at notnull or + (not attempt.result in ('success', 'cancel') and + case when _per_number is true then (attempt.waiting_other_numbers > 0 or (max_attempts_ > 0 and coalesce((m.communications#>(format('{%s,attempts}', attempt.communication_idx::int)::text[]))::int, 0) + 1 < max_attempts_)) else (max_attempts_ > 0 and (m.attempts + 1 < max_attempts_)) end + ) + then m.stop_at else attempt.leaving_at end, + stop_cause = case when next_offering_at_ notnull or + m.stop_at notnull or + (not attempt.result in ('success', 'cancel') and + case when _per_number is true then (attempt.waiting_other_numbers > 0 or (max_attempts_ > 0 and coalesce((m.communications#>(format('{%s,attempts}', attempt.communication_idx::int)::text[]))::int, 0) + 1 < max_attempts_)) else (max_attempts_ > 0 and (m.attempts + 1 < max_attempts_)) end + ) + then m.stop_cause else attempt.result end, + + ready_at = case when next_offering_at_ notnull then next_offering_at_ at time zone tz.names[1] + else now() + (wait_between_retries_ || ' sec')::interval end, + + last_agent = coalesce(attempt.agent_id, m.last_agent), + communications = jsonb_set(m.communications, (array[attempt.communication_idx::int])::text[], m.communications->(attempt.communication_idx::int) || + jsonb_build_object('last_activity_at', case when next_offering_at_ notnull then '0'::text::jsonb else time_::text::jsonb end) || + jsonb_build_object('attempt_id', attempt_id_) || + jsonb_build_object('attempts', coalesce((m.communications#>(format('{%s,attempts}', attempt.communication_idx::int)::text[]))::int, 0) + 1) || + case when exclude_dest or + (_per_number is true and coalesce((m.communications#>(format('{%s,attempts}', attempt.communication_idx::int)::text[]))::int, 0) + 1 >= max_attempts_) then jsonb_build_object('stop_at', time_) else '{}'::jsonb end + ), + attempts = m.attempts + 1 --TODO + from call_center.cc_member m2 + left join flow.calendar_timezone_offsets tz on tz.id = m2.sys_offset_id + where m.id = attempt.member_id and m.id = m2.id + returning m.stop_cause into stop_cause_; + end if; + + if attempt.agent_id notnull then + select a.user_id, a.domain_id, case when a.on_demand then null else coalesce(tm.wrap_up_time, 0) end, + case when attempt.channel = 'chat' then (select count(1) + from call_center.cc_member_attempt aa + where aa.agent_id = attempt.agent_id and aa.id != attempt.id and aa.state != 'leaving') else 0 end as other + into user_id_, domain_id_, wrap_time_, other_cnt_ + from call_center.cc_agent a + left join call_center.cc_team tm on tm.id = attempt.team_id + where a.id = attempt.agent_id; + + if other_cnt_ > 0 then + update call_center.cc_agent_channel c + set last_bucket_id = coalesce(attempt.bucket_id, last_bucket_id) + where (c.agent_id, c.channel) = (attempt.agent_id, attempt.channel) + returning null, channel into agent_timeout_, agent_channel_; + elseif wrap_time_ > 0 or wrap_time_ isnull then + update call_center.cc_agent_channel c + set state = 'wrap_time', + joined_at = now(), + timeout = case when wrap_time_ > 0 then now() + (wrap_time_ || ' sec')::interval end, + last_bucket_id = coalesce(attempt.bucket_id, last_bucket_id) + where (c.agent_id, c.channel) = (attempt.agent_id, attempt.channel) + returning timeout, channel into agent_timeout_, agent_channel_; + else + update call_center.cc_agent_channel c + set state = 'waiting', + joined_at = now(), + timeout = null, + last_bucket_id = coalesce(attempt.bucket_id, last_bucket_id), + queue_id = null + where (c.agent_id, c.channel) = (attempt.agent_id, attempt.channel) + returning timeout, channel into agent_timeout_, agent_channel_; + end if; + end if; + + return row(call_center.cc_view_timestamp(now()), + attempt.channel, + attempt.queue_id, + attempt.agent_call_id, + attempt.agent_id, + user_id_, + domain_id_, + call_center.cc_view_timestamp(agent_timeout_), + stop_cause_, + attempt.member_id + ); +end; +$$; \ No newline at end of file From 7a1ea5fb179bf91373681670040f72ce9839f90f Mon Sep 17 00:00:00 2001 From: "i.navrotskyj" Date: Fri, 24 May 2024 14:32:02 +0300 Subject: [PATCH 2/2] WTEL-4577 --- store/sqlstore/call_center-schema.sql | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/store/sqlstore/call_center-schema.sql b/store/sqlstore/call_center-schema.sql index 2ea7cb20..0785fc89 100644 --- a/store/sqlstore/call_center-schema.sql +++ b/store/sqlstore/call_center-schema.sql @@ -536,6 +536,7 @@ begin reporting_at = now(), leaving_at = case when leaving_at isnull then now() else leaving_at end, result = status_, + variables = case when variables_ notnull then coalesce(variables::jsonb, '{}') || variables_ else variables end, description = description_ where id = attempt_id_ and state != 'leaving' returning * into attempt; @@ -4032,7 +4033,8 @@ CREATE TABLE call_center.cc_member_attempt_history ( transferred_attempt_id bigint, parent_id bigint, form_fields jsonb, - import_id character varying(120) + import_id character varying(120), + variables jsonb ); @@ -4627,7 +4629,8 @@ CREATE UNLOGGED TABLE call_center.cc_member_attempt ( form_view jsonb, import_id character varying(120), schema_processing boolean DEFAULT false, - queue_params jsonb + queue_params jsonb, + variables jsonb ) WITH (fillfactor='20', log_autovacuum_min_duration='0', autovacuum_analyze_scale_factor='0.05', autovacuum_enabled='1', autovacuum_vacuum_cost_delay='20', autovacuum_vacuum_threshold='100', autovacuum_vacuum_scale_factor='0.01');