bmc_hub/app/modules/telefoni/backend/service.py
Christian 0831715d3a feat: add SMS service and frontend integration
- Implement SmsService class for sending SMS via CPSMS API.
- Add SMS sending functionality in the frontend with validation and user feedback.
- Create database migrations for SMS message storage and telephony features.
- Introduce telephony settings and user-specific configurations for click-to-call functionality.
- Enhance user experience with toast notifications for incoming calls and actions.
2026-02-14 02:26:29 +01:00

112 lines
3.7 KiB
Python

import logging
from datetime import datetime
from typing import Any, Optional
from app.core.database import execute_query, execute_query_single
logger = logging.getLogger(__name__)
class TelefoniService:
@staticmethod
def find_user_by_extension(extension: Optional[str]) -> Optional[int]:
if not extension:
return None
row = execute_query_single(
"SELECT user_id FROM users WHERE telefoni_aktiv = TRUE AND telefoni_extension = %s LIMIT 1",
(extension,),
)
return int(row["user_id"]) if row and row.get("user_id") is not None else None
@staticmethod
def find_contact_by_phone_suffix(suffix8: Optional[str]) -> Optional[dict]:
if not suffix8:
return None
query = """
SELECT
c.id,
c.first_name,
c.last_name,
(
SELECT cu.name
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
FROM contacts c
WHERE RIGHT(regexp_replace(COALESCE(c.phone, ''), '\\D', '', 'g'), 8) = %s
OR RIGHT(regexp_replace(COALESCE(c.mobile, ''), '\\D', '', 'g'), 8) = %s
ORDER BY c.id ASC
LIMIT 1
"""
row = execute_query_single(query, (suffix8, suffix8))
if not row:
return None
return {
"id": row["id"],
"name": f"{(row.get('first_name') or '').strip()} {(row.get('last_name') or '').strip()}".strip(),
"company": row.get("company"),
}
@staticmethod
def upsert_call(
*,
callid: str,
user_id: Optional[int],
direction: str,
ekstern_nummer: Optional[str],
intern_extension: Optional[str],
kontakt_id: Optional[int],
raw_payload: Any,
started_at: datetime,
) -> dict:
query = """
INSERT INTO telefoni_opkald
(callid, bruger_id, direction, ekstern_nummer, intern_extension, kontakt_id, started_at, raw_payload)
VALUES
(%s, %s, %s, %s, %s, %s, %s, %s::jsonb)
ON CONFLICT (callid)
DO UPDATE SET
raw_payload = EXCLUDED.raw_payload,
direction = EXCLUDED.direction,
intern_extension = COALESCE(telefoni_opkald.intern_extension, EXCLUDED.intern_extension),
ekstern_nummer = COALESCE(telefoni_opkald.ekstern_nummer, EXCLUDED.ekstern_nummer),
bruger_id = COALESCE(telefoni_opkald.bruger_id, EXCLUDED.bruger_id),
kontakt_id = COALESCE(telefoni_opkald.kontakt_id, EXCLUDED.kontakt_id),
started_at = LEAST(telefoni_opkald.started_at, EXCLUDED.started_at)
RETURNING *
"""
rows = execute_query(
query,
(
callid,
user_id,
direction,
ekstern_nummer,
intern_extension,
kontakt_id,
started_at,
raw_payload,
),
)
return rows[0] if rows else {}
@staticmethod
def terminate_call(callid: str, duration_sec: Optional[int]) -> bool:
if not callid:
return False
rows = execute_query(
"""
UPDATE telefoni_opkald
SET ended_at = NOW(),
duration_sec = %s
WHERE callid = %s
RETURNING id
""",
(duration_sec, callid),
)
return bool(rows)