From 9713a47bc66861e6d75660c0bd078961af031ea7 Mon Sep 17 00:00:00 2001 From: Igor Navrotskyj Date: Mon, 4 Mar 2024 17:49:52 +0200 Subject: [PATCH] 24.02 --- store/sqlstore/call_center-schema.sql | 64 +++-- .../sqlstore/migration/24.02/23.12-24.02.sql | 245 ++++++++++++++++++ 2 files changed, 285 insertions(+), 24 deletions(-) diff --git a/store/sqlstore/call_center-schema.sql b/store/sqlstore/call_center-schema.sql index 1c572933..2c69ffe3 100644 --- a/store/sqlstore/call_center-schema.sql +++ b/store/sqlstore/call_center-schema.sql @@ -1062,6 +1062,17 @@ end; $$; +-- +-- Name: cc_bridged_id(uuid); Type: FUNCTION; Schema: call_center; Owner: - +-- + +CREATE FUNCTION call_center.cc_bridged_id(uuid) RETURNS uuid + LANGUAGE sql IMMUTABLE + AS $_$ +select lega.bridged_id from call_center.cc_calls_history lega where lega.id = $1 +$_$; + + -- -- Name: cc_call_active_numbers(); Type: FUNCTION; Schema: call_center; Owner: - -- @@ -4931,7 +4942,7 @@ CREATE VIEW call_center.cc_calls_history_list AS c.parent_id, c.transfer_from, CASE - WHEN ((c.parent_id IS NOT NULL) AND (c.transfer_to IS NULL) AND ((c.id)::text <> (lega.bridged_id)::text)) THEN lega.bridged_id + WHEN ((c.parent_id IS NOT NULL) AND (c.transfer_to IS NULL) AND (c.id <> call_center.cc_bridged_id(c.parent_id))) THEN call_center.cc_bridged_id(c.parent_id) ELSE c.transfer_to END AS transfer_to, call_center.cc_get_lookup(u.id, (COALESCE(u.name, (u.username)::text))::character varying) AS "user", @@ -4964,7 +4975,20 @@ CREATE VIEW call_center.cc_calls_history_list AS ELSE (0)::bigint END AS bill_sec, c.sip_code, - f.files, + ( SELECT json_agg(jsonb_build_object('id', f_1.id, 'name', f_1.name, 'size', f_1.size, 'mime_type', f_1.mime_type, 'start_at', ((c.params -> 'record_start'::text))::bigint, 'stop_at', ((c.params -> 'record_stop'::text))::bigint)) AS files + FROM ( SELECT f1.id, + f1.size, + f1.mime_type, + f1.name + FROM storage.files f1 + WHERE ((f1.domain_id = c.domain_id) AND (NOT (f1.removed IS TRUE)) AND ((f1.uuid)::text = (c.id)::text)) + UNION ALL + SELECT f1.id, + f1.size, + f1.mime_type, + f1.name + FROM storage.files f1 + WHERE ((f1.domain_id = c.domain_id) AND (NOT (f1.removed IS TRUE)) AND ((f1.uuid)::text = (c.parent_id)::text))) f_1) AS files, call_center.cc_get_lookup((cq.id)::bigint, cq.name) AS queue, call_center.cc_get_lookup(c.member_id, cm.name) AS member, call_center.cc_get_lookup(ct.id, ct.name) AS team, @@ -4997,13 +5021,13 @@ CREATE VIEW call_center.cc_calls_history_list AS cma.display, (EXISTS ( SELECT 1 FROM call_center.cc_calls_history hp - WHERE ((c.parent_id IS NULL) AND (hp.parent_id = c.id)))) AS has_children, + WHERE ((c.parent_id IS NULL) AND (hp.parent_id = c.id) AND (hp.created_at > (c.created_at)::date)))) AS has_children, (COALESCE(regexp_replace((cma.description)::text, '^[\r\n\t ]*|[\r\n\t ]*$'::text, ''::text, 'g'::text), (''::character varying)::text))::character varying AS agent_description, c.grantee_id, ( SELECT jsonb_agg(x.hi ORDER BY (x.hi -> 'start'::text)) AS res FROM ( SELECT jsonb_array_elements(chh.hold) AS hi FROM call_center.cc_calls_history chh - WHERE ((chh.parent_id = c.id) AND (chh.hold IS NOT NULL)) + WHERE ((chh.parent_id = c.id) AND (chh.created_at > (c.created_at)::date) AND (chh.hold IS NOT NULL)) UNION SELECT jsonb_array_elements(c.hold) AS jsonb_array_elements) x WHERE (x.hi IS NOT NULL)) AS hold, @@ -5048,7 +5072,14 @@ CREATE VIEW call_center.cc_calls_history_list AS c.blind_transfer, ( SELECT jsonb_agg(json_build_object('id', j.id, 'created_at', call_center.cc_view_timestamp(j.created_at), 'action', j.action, 'file_id', j.file_id, 'state', j.state, 'error', j.error, 'updated_at', call_center.cc_view_timestamp(j.updated_at))) AS jsonb_agg FROM storage.file_jobs j - WHERE (j.file_id = ANY (f.file_ids))) AS files_job, + WHERE (j.file_id IN ( SELECT f_1.id + FROM ( SELECT f1.id + FROM storage.files f1 + WHERE ((f1.domain_id = c.domain_id) AND (NOT (f1.removed IS TRUE)) AND ((f1.uuid)::text = (c.id)::text)) + UNION + SELECT f1.id + FROM storage.files f1 + WHERE ((f1.domain_id = c.domain_id) AND (NOT (f1.removed IS TRUE)) AND ((f1.uuid)::text = (c.parent_id)::text))) f_1))) AS files_job, ( SELECT json_agg(json_build_object('id', tr.id, 'locale', tr.locale, 'file_id', tr.file_id, 'file', call_center.cc_get_lookup(ff.id, ff.name))) AS data FROM (storage.file_transcript tr LEFT JOIN storage.files ff ON ((ff.id = tr.file_id))) @@ -5072,22 +5103,7 @@ CREATE VIEW call_center.cc_calls_history_list AS c.hide_missed, c.redial_id, (lega.bridged_id IS NOT NULL) AS parent_bridged - FROM (((((((((((((((call_center.cc_calls_history c - LEFT JOIN LATERAL ( SELECT array_agg(f_1.id) AS file_ids, - json_agg(jsonb_build_object('id', f_1.id, 'name', f_1.name, 'size', f_1.size, 'mime_type', f_1.mime_type, 'start_at', ((c.params -> 'record_start'::text))::bigint, 'stop_at', ((c.params -> 'record_stop'::text))::bigint)) AS files - FROM ( SELECT f1.id, - f1.size, - f1.mime_type, - f1.name - FROM storage.files f1 - WHERE ((f1.domain_id = c.domain_id) AND (NOT (f1.removed IS TRUE)) AND ((f1.uuid)::text = (c.id)::text)) - UNION ALL - SELECT f1.id, - f1.size, - f1.mime_type, - f1.name - FROM storage.files f1 - WHERE ((f1.domain_id = c.domain_id) AND (NOT (f1.removed IS TRUE)) AND ((f1.uuid)::text = (c.parent_id)::text))) f_1) f ON (((c.answered_at IS NOT NULL) OR (c.bridged_at IS NOT NULL)))) + FROM ((((((((((((((call_center.cc_calls_history c LEFT JOIN call_center.cc_queue cq ON ((c.queue_id = cq.id))) LEFT JOIN call_center.cc_team ct ON ((c.team_id = ct.id))) LEFT JOIN call_center.cc_member cm ON ((c.member_id = cm.id))) @@ -5097,10 +5113,10 @@ CREATE VIEW call_center.cc_calls_history_list AS LEFT JOIN directory.wbt_user u ON ((u.id = c.user_id))) LEFT JOIN directory.sip_gateway gw ON ((gw.id = c.gateway_id))) LEFT JOIN directory.wbt_auth au ON ((au.id = c.grantee_id))) - LEFT JOIN call_center.cc_calls_history lega ON (((c.parent_id IS NOT NULL) AND (lega.id = c.parent_id)))) LEFT JOIN call_center.cc_audit_rate ar ON (((ar.call_id)::text = (c.id)::text))) - LEFT JOIN directory.wbt_user aru ON (((ar.* IS NOT NULL) AND (aru.id = ar.rated_user_id)))) - LEFT JOIN directory.wbt_user arub ON (((ar.* IS NOT NULL) AND (arub.id = ar.created_by)))) + LEFT JOIN directory.wbt_user aru ON ((aru.id = ar.rated_user_id))) + LEFT JOIN directory.wbt_user arub ON ((arub.id = ar.created_by))) + LEFT JOIN call_center.cc_calls_history lega ON ((lega.id = c.parent_id))) LEFT JOIN contacts.contact cc ON ((cc.id = c.contact_id))); diff --git a/store/sqlstore/migration/24.02/23.12-24.02.sql b/store/sqlstore/migration/24.02/23.12-24.02.sql index 6be5bd26..95f23e59 100644 --- a/store/sqlstore/migration/24.02/23.12-24.02.sql +++ b/store/sqlstore/migration/24.02/23.12-24.02.sql @@ -955,3 +955,248 @@ ALTER TABLE ONLY call_center.cc_team_events ALTER TABLE ONLY call_center.cc_team_events ADD CONSTRAINT cc_team_events_wbt_user_id_fk FOREIGN KEY (updated_by) REFERENCES directory.wbt_user(id) ON DELETE SET NULL; + + + +create function call_center.cc_bridged_id(uuid) returns uuid + immutable + language sql +as +$$ +select lega.bridged_id from call_center.cc_calls_history lega where lega.id = $1 +$$; + + +drop view call_center.cc_calls_history_list; +create view call_center.cc_calls_history_list +as +SELECT c.id, + c.app_id, + 'call'::character varying AS type, + c.parent_id, + c.transfer_from, + CASE + WHEN c.parent_id IS NOT NULL AND c.transfer_to IS NULL AND c.id <> call_center.cc_bridged_id(c.parent_id) + THEN call_center.cc_bridged_id(c.parent_id) + ELSE c.transfer_to + END AS transfer_to, + call_center.cc_get_lookup(u.id, + COALESCE(u.name, u.username::text)::character varying) AS "user", + CASE + WHEN cq.type = ANY (ARRAY [4, 5]) THEN cag.extension + ELSE u.extension + END AS extension, + call_center.cc_get_lookup(gw.id, gw.name) AS gateway, + c.direction, + c.destination, + json_build_object('type', COALESCE(c.from_type, ''::character varying), 'number', + COALESCE(c.from_number, ''::character varying), 'id', + COALESCE(c.from_id, ''::character varying), 'name', + COALESCE(c.from_name, ''::character varying)) AS "from", + json_build_object('type', COALESCE(c.to_type, ''::character varying), 'number', + COALESCE(c.to_number, ''::character varying), 'id', COALESCE(c.to_id, ''::character varying), + 'name', + COALESCE(c.to_name, ''::character varying)) AS "to", + c.payload AS variables, + c.created_at, + c.answered_at, + c.bridged_at, + c.hangup_at, + c.stored_at, + COALESCE(c.hangup_by, ''::character varying) AS hangup_by, + c.cause, + date_part('epoch'::text, c.hangup_at - c.created_at)::bigint AS duration, + COALESCE(c.hold_sec, 0) AS hold_sec, + COALESCE( + CASE + WHEN c.answered_at IS NOT NULL THEN date_part('epoch'::text, c.answered_at - c.created_at)::bigint + ELSE date_part('epoch'::text, c.hangup_at - c.created_at)::bigint + END, + 0::bigint) AS wait_sec, + CASE + WHEN c.answered_at IS NOT NULL THEN date_part('epoch'::text, c.hangup_at - c.answered_at)::bigint + ELSE 0::bigint + END AS bill_sec, + c.sip_code, + (SELECT json_agg(jsonb_build_object('id', f_1.id, 'name', f_1.name, 'size', f_1.size, 'mime_type', f_1.mime_type, + 'start_at', (c.params -> 'record_start'::text)::bigint, 'stop_at', + (c.params -> 'record_stop'::text)::bigint)) AS files + FROM (SELECT f1.id, + f1.size, + f1.mime_type, + f1.name + FROM storage.files f1 + WHERE f1.domain_id = c.domain_id + AND NOT f1.removed IS TRUE + AND f1.uuid::text = c.id::text + UNION ALL + SELECT f1.id, + f1.size, + f1.mime_type, + f1.name + FROM storage.files f1 + WHERE f1.domain_id = c.domain_id + AND NOT f1.removed IS TRUE + AND f1.uuid::text = c.parent_id::text) f_1) AS files, + call_center.cc_get_lookup(cq.id::bigint, cq.name) AS queue, + call_center.cc_get_lookup(c.member_id, cm.name) AS member, + call_center.cc_get_lookup(ct.id, ct.name) AS team, + call_center.cc_get_lookup(aa.id::bigint, + COALESCE(cag.username, cag.name::name)::character varying) AS agent, + cma.joined_at, + cma.leaving_at, + cma.reporting_at, + cma.bridged_at AS queue_bridged_at, + CASE + WHEN cma.bridged_at IS NOT NULL THEN date_part('epoch'::text, cma.bridged_at - cma.joined_at)::integer + ELSE date_part('epoch'::text, cma.leaving_at - cma.joined_at)::integer + END AS queue_wait_sec, + date_part('epoch'::text, cma.leaving_at - cma.joined_at)::integer AS queue_duration_sec, + cma.result, + CASE + WHEN cma.reporting_at IS NOT NULL THEN date_part('epoch'::text, cma.reporting_at - cma.leaving_at)::integer + ELSE 0 + END AS reporting_sec, + c.agent_id, + c.team_id, + c.user_id, + c.queue_id, + c.member_id, + c.attempt_id, + c.domain_id, + c.gateway_id, + c.from_number, + c.to_number, + c.tags, + cma.display, + (EXISTS(SELECT 1 + FROM call_center.cc_calls_history hp + WHERE c.parent_id IS NULL + AND hp.parent_id = c.id + AND hp.created_at > c.created_at::date)) AS has_children, + COALESCE(regexp_replace(cma.description::text, '^[\r\n\t ]*|[\r\n\t ]*$'::text, ''::text, 'g'::text), + ''::character varying::text)::character varying AS agent_description, + c.grantee_id, + (SELECT jsonb_agg(x.hi ORDER BY (x.hi -> 'start'::text)) AS res + FROM (SELECT jsonb_array_elements(chh.hold) AS hi + FROM call_center.cc_calls_history chh + WHERE chh.parent_id = c.id + AND chh.created_at > c.created_at::date + AND chh.hold IS NOT NULL + UNION + SELECT jsonb_array_elements(c.hold) AS jsonb_array_elements) x + WHERE x.hi IS NOT NULL) AS hold, + c.gateway_ids, + c.user_ids, + c.agent_ids, + c.queue_ids, + c.team_ids, + (SELECT json_agg(row_to_json(annotations.*)) AS json_agg + FROM (SELECT a.id, + a.call_id, + a.created_at, + call_center.cc_get_lookup(cc_1.id, + COALESCE(cc_1.name, cc_1.username::text)::character varying) AS created_by, + a.updated_at, + call_center.cc_get_lookup(uc.id, + COALESCE(uc.name, uc.username::text)::character varying) AS updated_by, + a.note, + a.start_sec, + a.end_sec + FROM call_center.cc_calls_annotation a + LEFT JOIN directory.wbt_user cc_1 ON cc_1.id = a.created_by + LEFT JOIN directory.wbt_user uc ON uc.id = a.updated_by + WHERE a.call_id::text = c.id::text + ORDER BY a.created_at DESC) annotations) AS annotations, + COALESCE(c.amd_result, c.amd_ai_result) AS amd_result, + c.amd_duration, + c.amd_ai_result, + c.amd_ai_logs, + c.amd_ai_positive, + cq.type AS queue_type, + CASE + WHEN c.parent_id IS NOT NULL THEN ''::text + WHEN c.cause::text = ANY (ARRAY ['USER_BUSY'::character varying::text, 'NO_ANSWER'::character varying::text]) + THEN 'not_answered'::text + WHEN c.cause::text = 'ORIGINATOR_CANCEL'::text OR c.cause::text = 'LOSE_RACE'::text AND cq.type = 4 + THEN 'cancelled'::text + WHEN c.hangup_by::text = 'F'::text THEN 'ended'::text + WHEN c.cause::text = 'NORMAL_CLEARING'::text THEN + CASE + WHEN c.cause::text = 'NORMAL_CLEARING'::text AND c.direction::text = 'outbound'::text AND + c.hangup_by::text = 'A'::text AND c.user_id IS NOT NULL OR + c.direction::text = 'inbound'::text AND c.hangup_by::text = 'B'::text AND + c.bridged_at IS NOT NULL OR + c.direction::text = 'outbound'::text AND c.hangup_by::text = 'B'::text AND + (cq.type = ANY (ARRAY [4, 5, 1])) AND c.bridged_at IS NOT NULL THEN 'agent_dropped'::text + ELSE 'client_dropped'::text + END + ELSE 'error'::text + END AS hangup_disposition, + c.blind_transfer, + (SELECT jsonb_agg(json_build_object('id', j.id, 'created_at', call_center.cc_view_timestamp(j.created_at), + 'action', j.action, 'file_id', j.file_id, 'state', j.state, 'error', j.error, + 'updated_at', call_center.cc_view_timestamp(j.updated_at))) AS jsonb_agg + FROM storage.file_jobs j + WHERE (j.file_id IN (SELECT f_1.id + FROM (SELECT f1.id + FROM storage.files f1 + WHERE f1.domain_id = c.domain_id + AND NOT f1.removed IS TRUE + AND f1.uuid::text = c.id::text + UNION + SELECT f1.id + FROM storage.files f1 + WHERE f1.domain_id = c.domain_id + AND NOT f1.removed IS TRUE + AND f1.uuid::text = c.parent_id::text) f_1))) AS files_job, + (SELECT json_agg(json_build_object('id', tr.id, 'locale', tr.locale, 'file_id', tr.file_id, 'file', + call_center.cc_get_lookup(ff.id, ff.name))) AS data + FROM storage.file_transcript tr + LEFT JOIN storage.files ff ON ff.id = tr.file_id + WHERE tr.uuid::text = c.id::text + GROUP BY (tr.uuid::text)) AS transcripts, + c.talk_sec, + call_center.cc_get_lookup(au.id, au.name::character varying) AS grantee, + ar.id AS rate_id, + call_center.cc_get_lookup(aru.id, COALESCE(aru.name::character varying, + aru.username::character varying)) AS rated_user, + call_center.cc_get_lookup(arub.id, COALESCE(arub.name::character varying, + arub.username::character varying)) AS rated_by, + ar.score_optional, + ar.score_required, + (EXISTS(SELECT 1 + FROM call_center.cc_calls_history cr + WHERE cr.id = c.bridged_id + AND c.bridged_id IS NOT NULL + AND c.blind_transfer IS NULL + AND cr.blind_transfer IS NULL + AND c.transfer_to IS NULL + AND cr.transfer_to IS NULL + AND c.transfer_from IS NULL + AND cr.transfer_from IS NULL + AND COALESCE(cr.user_id, c.user_id) IS NOT NULL)) AS allow_evaluation, + cma.form_fields, + c.bridged_id, + call_center.cc_get_lookup(cc.id, + cc.common_name::character varying) AS contact, + c.contact_id, + c.search_number, + c.hide_missed, + c.redial_id, + (lega.bridged_id IS NOT NULL) AS parent_bridged +FROM call_center.cc_calls_history c + LEFT JOIN call_center.cc_queue cq ON c.queue_id = cq.id + LEFT JOIN call_center.cc_team ct ON c.team_id = ct.id + LEFT JOIN call_center.cc_member cm ON c.member_id = cm.id + LEFT JOIN call_center.cc_member_attempt_history cma ON cma.id = c.attempt_id + LEFT JOIN call_center.cc_agent aa ON cma.agent_id = aa.id + LEFT JOIN directory.wbt_user cag ON cag.id = aa.user_id + LEFT JOIN directory.wbt_user u ON u.id = c.user_id + LEFT JOIN directory.sip_gateway gw ON gw.id = c.gateway_id + LEFT JOIN directory.wbt_auth au ON au.id = c.grantee_id + LEFT JOIN call_center.cc_audit_rate ar ON ar.call_id::text = c.id::text + LEFT JOIN directory.wbt_user aru ON aru.id = ar.rated_user_id + LEFT JOIN directory.wbt_user arub ON arub.id = ar.created_by + LEFT JOIN call_center.cc_calls_history lega ON lega.id = c.parent_id + LEFT JOIN contacts.contact cc ON cc.id = c.contact_id; \ No newline at end of file