fix: stabilize call->case prefill and migration status routing
This commit is contained in:
parent
9f563941e6
commit
5b24c5d978
@ -107,6 +107,21 @@ class MissionService:
|
|||||||
FROM contacts c
|
FROM contacts c
|
||||||
WHERE RIGHT(regexp_replace(COALESCE(c.phone, ''), '\\D', '', 'g'), 8) = RIGHT(regexp_replace(%s, '\\D', '', 'g'), 8)
|
WHERE RIGHT(regexp_replace(COALESCE(c.phone, ''), '\\D', '', 'g'), 8) = RIGHT(regexp_replace(%s, '\\D', '', 'g'), 8)
|
||||||
OR RIGHT(regexp_replace(COALESCE(c.mobile, ''), '\\D', '', 'g'), 8) = RIGHT(regexp_replace(%s, '\\D', '', 'g'), 8)
|
OR RIGHT(regexp_replace(COALESCE(c.mobile, ''), '\\D', '', 'g'), 8) = RIGHT(regexp_replace(%s, '\\D', '', 'g'), 8)
|
||||||
|
ORDER BY (
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM sag_kontakter sk
|
||||||
|
JOIN sag_sager s ON s.id = sk.sag_id
|
||||||
|
WHERE sk.contact_id = c.id
|
||||||
|
AND sk.deleted_at IS NULL
|
||||||
|
AND s.deleted_at IS NULL
|
||||||
|
AND LOWER(COALESCE(s.status, '')) <> 'lukket'
|
||||||
|
) DESC,
|
||||||
|
(
|
||||||
|
SELECT MAX(t.started_at)
|
||||||
|
FROM telefoni_opkald t
|
||||||
|
WHERE t.kontakt_id = c.id
|
||||||
|
) DESC NULLS LAST,
|
||||||
|
c.id ASC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
"""
|
"""
|
||||||
row = execute_query_single(query, (caller_number, caller_number))
|
row = execute_query_single(query, (caller_number, caller_number))
|
||||||
|
|||||||
@ -29,6 +29,14 @@ class TelefoniService:
|
|||||||
c.id,
|
c.id,
|
||||||
c.first_name,
|
c.first_name,
|
||||||
c.last_name,
|
c.last_name,
|
||||||
|
(
|
||||||
|
SELECT cu.id
|
||||||
|
FROM contact_companies cc
|
||||||
|
JOIN customers cu ON cu.id = cc.customer_id
|
||||||
|
WHERE cc.contact_id = c.id
|
||||||
|
ORDER BY cc.is_primary DESC NULLS LAST, cc.id ASC
|
||||||
|
LIMIT 1
|
||||||
|
) AS company_id,
|
||||||
(
|
(
|
||||||
SELECT cu.name
|
SELECT cu.name
|
||||||
FROM contact_companies cc
|
FROM contact_companies cc
|
||||||
@ -36,11 +44,25 @@ class TelefoniService:
|
|||||||
WHERE cc.contact_id = c.id
|
WHERE cc.contact_id = c.id
|
||||||
ORDER BY cc.is_primary DESC NULLS LAST, cc.id ASC
|
ORDER BY cc.is_primary DESC NULLS LAST, cc.id ASC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
) AS company
|
) AS company,
|
||||||
|
(
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM sag_kontakter sk
|
||||||
|
JOIN sag_sager s ON s.id = sk.sag_id
|
||||||
|
WHERE sk.contact_id = c.id
|
||||||
|
AND sk.deleted_at IS NULL
|
||||||
|
AND s.deleted_at IS NULL
|
||||||
|
AND LOWER(COALESCE(s.status, '')) <> 'lukket'
|
||||||
|
) AS open_case_count,
|
||||||
|
(
|
||||||
|
SELECT MAX(t.started_at)
|
||||||
|
FROM telefoni_opkald t
|
||||||
|
WHERE t.kontakt_id = c.id
|
||||||
|
) AS last_call_at
|
||||||
FROM contacts c
|
FROM contacts c
|
||||||
WHERE RIGHT(regexp_replace(COALESCE(c.phone, ''), '\\D', '', 'g'), 8) = %s
|
WHERE RIGHT(regexp_replace(COALESCE(c.phone, ''), '\\D', '', 'g'), 8) = %s
|
||||||
OR RIGHT(regexp_replace(COALESCE(c.mobile, ''), '\\D', '', 'g'), 8) = %s
|
OR RIGHT(regexp_replace(COALESCE(c.mobile, ''), '\\D', '', 'g'), 8) = %s
|
||||||
ORDER BY c.id ASC
|
ORDER BY open_case_count DESC, last_call_at DESC NULLS LAST, c.id ASC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
"""
|
"""
|
||||||
row = execute_query_single(query, (suffix8, suffix8))
|
row = execute_query_single(query, (suffix8, suffix8))
|
||||||
@ -49,6 +71,7 @@ class TelefoniService:
|
|||||||
return {
|
return {
|
||||||
"id": row["id"],
|
"id": row["id"],
|
||||||
"name": f"{(row.get('first_name') or '').strip()} {(row.get('last_name') or '').strip()}".strip(),
|
"name": f"{(row.get('first_name') or '').strip()} {(row.get('last_name') or '').strip()}".strip(),
|
||||||
|
"company_id": row.get("company_id"),
|
||||||
"company": row.get("company"),
|
"company": row.get("company"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -259,6 +259,14 @@ async def get_setting_categories():
|
|||||||
return [row['category'] for row in result] if result else []
|
return [row['category'] for row in result] if result else []
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/settings/migrations/status", tags=["Settings"])
|
||||||
|
async def get_migration_statuses_api():
|
||||||
|
"""Expose migration status via API router (served under /api/v1)."""
|
||||||
|
from app.settings.backend.views import migration_statuses
|
||||||
|
|
||||||
|
return migration_statuses()
|
||||||
|
|
||||||
|
|
||||||
@router.post("/settings/sync-from-env", tags=["Settings"])
|
@router.post("/settings/sync-from-env", tags=["Settings"])
|
||||||
async def sync_settings_from_env():
|
async def sync_settings_from_env():
|
||||||
"""Sync settings from .env file into database (only updates empty values)"""
|
"""Sync settings from .env file into database (only updates empty values)"""
|
||||||
|
|||||||
@ -281,12 +281,6 @@ def migration_statuses():
|
|||||||
release_db_connection(conn)
|
release_db_connection(conn)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/api/v1/settings/migrations/status", tags=["Frontend"])
|
|
||||||
def migration_statuses_api_v1_alias():
|
|
||||||
"""API-prefixed alias for environments/routes expecting /api/v1 prefix."""
|
|
||||||
return migration_statuses()
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/settings/migrations/execute", tags=["Frontend"])
|
@router.post("/settings/migrations/execute", tags=["Frontend"])
|
||||||
def execute_migration(payload: MigrationExecution):
|
def execute_migration(payload: MigrationExecution):
|
||||||
"""Execute a migration SQL file"""
|
"""Execute a migration SQL file"""
|
||||||
|
|||||||
@ -0,0 +1,57 @@
|
|||||||
|
-- Migration 151: Reconcile opportunity comment attachments schema with migration 019 expectations
|
||||||
|
-- Some environments already had pipeline_opportunity_comment_attachments with legacy columns,
|
||||||
|
-- so migration 019 (CREATE TABLE IF NOT EXISTS) did not add these fields.
|
||||||
|
|
||||||
|
ALTER TABLE IF EXISTS pipeline_opportunity_comment_attachments
|
||||||
|
ADD COLUMN IF NOT EXISTS content_type VARCHAR(100),
|
||||||
|
ADD COLUMN IF NOT EXISTS stored_name TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS uploaded_by_user_id INTEGER;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'pipeline_opportunity_comment_attachments'
|
||||||
|
AND column_name = 'file_path'
|
||||||
|
) THEN
|
||||||
|
UPDATE pipeline_opportunity_comment_attachments
|
||||||
|
SET stored_name = COALESCE(stored_name, file_path)
|
||||||
|
WHERE stored_name IS NULL;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'pipeline_opportunity_comment_attachments'
|
||||||
|
AND column_name = 'file_type'
|
||||||
|
) THEN
|
||||||
|
UPDATE pipeline_opportunity_comment_attachments
|
||||||
|
SET content_type = COALESCE(content_type, file_type)
|
||||||
|
WHERE content_type IS NULL;
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_constraint
|
||||||
|
WHERE conname = 'pipeline_opportunity_comment_attachments_uploaded_by_fkey'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE pipeline_opportunity_comment_attachments
|
||||||
|
ADD CONSTRAINT pipeline_opportunity_comment_attachments_uploaded_by_fkey
|
||||||
|
FOREIGN KEY (uploaded_by_user_id)
|
||||||
|
REFERENCES users(user_id)
|
||||||
|
ON DELETE SET NULL;
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- Keep existing rows valid while allowing future inserts to set explicit stored_name.
|
||||||
|
UPDATE pipeline_opportunity_comment_attachments
|
||||||
|
SET stored_name = COALESCE(stored_name, filename)
|
||||||
|
WHERE stored_name IS NULL;
|
||||||
@ -163,6 +163,7 @@
|
|||||||
if (action === 'create-case') {
|
if (action === 'create-case') {
|
||||||
const qs = new URLSearchParams();
|
const qs = new URLSearchParams();
|
||||||
if (contact?.id) qs.set('contact_id', String(contact.id));
|
if (contact?.id) qs.set('contact_id', String(contact.id));
|
||||||
|
if (contact?.company_id) qs.set('customer_id', String(contact.company_id));
|
||||||
qs.set('title', `Telefonsamtale – ${number}`);
|
qs.set('title', `Telefonsamtale – ${number}`);
|
||||||
qs.set('telefoni_opkald_id', String(callId));
|
qs.set('telefoni_opkald_id', String(callId));
|
||||||
window.location.href = `/sag/new?${qs.toString()}`;
|
window.location.href = `/sag/new?${qs.toString()}`;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user