Projeto do Agent Contas ORACLE
This commit is contained in:
169
app/domain/contas/protocol_triplets.py
Normal file
169
app/domain/contas/protocol_triplets.py
Normal file
@@ -0,0 +1,169 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from functools import lru_cache
|
||||
from typing import Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_TRIPLETS_ENV_VAR = "TIM_PROTOCOL_TRIPLETS_JSON"
|
||||
_STAGES = ("open", "close")
|
||||
_FIELDS = ("reason1", "reason2", "reason3")
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class ProtocolTriplet:
|
||||
reason1: str
|
||||
reason2: str
|
||||
reason3: str
|
||||
|
||||
|
||||
_DEFAULT_CATALOG: dict[str, dict[str, ProtocolTriplet]] = {
|
||||
"atendimento_geral": {
|
||||
"open": ProtocolTriplet("Informação", "Conta", "Valor"),
|
||||
"close": ProtocolTriplet("Informação", "Conta", "Serviço"),
|
||||
},
|
||||
"cancelamento_vas_avulso": {
|
||||
"open": ProtocolTriplet(
|
||||
"Solicitação", "Serviço VAS", "Ativação/Desativação"
|
||||
),
|
||||
"close": ProtocolTriplet(
|
||||
"Solicitação", "Serviço VAS", "Ativação/Desativação"
|
||||
),
|
||||
},
|
||||
"contestacao": {
|
||||
"open": ProtocolTriplet("Informação", "Conta", "Serviço"),
|
||||
"close": ProtocolTriplet("Reclamação", "Conta", "Valor"),
|
||||
},
|
||||
"vas_estrategico": {
|
||||
"open": ProtocolTriplet("Informação", "Conta", "Serviço"),
|
||||
"close": ProtocolTriplet("Informação", "Conta", "Serviço"),
|
||||
},
|
||||
"invoice_explanation_aceite_fechado": {
|
||||
"open": ProtocolTriplet("Informação", "Conta", "Serviço"),
|
||||
"close": ProtocolTriplet("Informação", "Conta", "Serviço"),
|
||||
},
|
||||
"finalizacao_informacional_fechada": {
|
||||
"open": ProtocolTriplet("Informação", "Conta", "Serviço"),
|
||||
"close": ProtocolTriplet("Informação", "Conta", "Esclarecimento"),
|
||||
},
|
||||
"valor_divergente": {
|
||||
"open": ProtocolTriplet("Informação", "Conta", "Valor"),
|
||||
"close": ProtocolTriplet("Informação", "Conta", "Valor"),
|
||||
},
|
||||
"pro_rata": {
|
||||
"open": ProtocolTriplet("Informação", "Conta", "Valor"),
|
||||
"close": ProtocolTriplet("Informação", "Conta", "Valor"),
|
||||
},
|
||||
"pro_rata_mensalidade": {
|
||||
"open": ProtocolTriplet("Informação", "Conta", "Mensalidade"),
|
||||
"close": ProtocolTriplet("Informação", "Conta", "Mensalidade"),
|
||||
},
|
||||
"pro_rata_reclamacao": {
|
||||
"open": ProtocolTriplet("Reclamação", "Conta", "Valor"),
|
||||
"close": ProtocolTriplet("Reclamação", "Conta", "Valor"),
|
||||
},
|
||||
"termino_desconto": {
|
||||
"open": ProtocolTriplet("Informação", "Conta", "Serviço"),
|
||||
"close": ProtocolTriplet("Informação", "Conta", "Serviço"),
|
||||
},
|
||||
"conta_certa_manual": {
|
||||
"open": ProtocolTriplet(
|
||||
"Processo Interno", "Conta", "Conta Certa - Venc {dia_vencimento}"
|
||||
),
|
||||
"close": ProtocolTriplet(
|
||||
"Processo Interno", "Conta", "Conta Certa - Venc {dia_vencimento}"
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class _SafeFormatDict(dict[str, Any]):
|
||||
def __missing__(self, key: str) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def _normalize_text(value: Any) -> str:
|
||||
return str(value or "").strip()
|
||||
|
||||
|
||||
def _override_triplet(base: ProtocolTriplet, override: dict[str, Any]) -> ProtocolTriplet:
|
||||
return ProtocolTriplet(
|
||||
reason1=_normalize_text(override.get("reason1")) or base.reason1,
|
||||
reason2=_normalize_text(override.get("reason2")) or base.reason2,
|
||||
reason3=_normalize_text(override.get("reason3")) or base.reason3,
|
||||
)
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _catalog_with_overrides() -> dict[str, dict[str, ProtocolTriplet]]:
|
||||
catalog = {
|
||||
scenario: dict(stages)
|
||||
for scenario, stages in _DEFAULT_CATALOG.items()
|
||||
}
|
||||
raw = os.getenv(_TRIPLETS_ENV_VAR, "").strip()
|
||||
if not raw:
|
||||
return catalog
|
||||
try:
|
||||
payload = json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("triplets.override.invalid_json env=%s", _TRIPLETS_ENV_VAR)
|
||||
return catalog
|
||||
if not isinstance(payload, dict):
|
||||
logger.warning("triplets.override.invalid_root env=%s", _TRIPLETS_ENV_VAR)
|
||||
return catalog
|
||||
|
||||
for scenario, stage_payload in payload.items():
|
||||
scenario_key = _normalize_text(scenario).lower()
|
||||
if not scenario_key or not isinstance(stage_payload, dict):
|
||||
continue
|
||||
current = catalog.get(scenario_key, {})
|
||||
for stage in _STAGES:
|
||||
override = stage_payload.get(stage)
|
||||
if not isinstance(override, dict):
|
||||
continue
|
||||
if stage in current:
|
||||
current[stage] = _override_triplet(current[stage], override)
|
||||
continue
|
||||
if any(_normalize_text(override.get(field)) for field in _FIELDS):
|
||||
current[stage] = ProtocolTriplet(
|
||||
reason1=_normalize_text(override.get("reason1")),
|
||||
reason2=_normalize_text(override.get("reason2")),
|
||||
reason3=_normalize_text(override.get("reason3")),
|
||||
)
|
||||
if current:
|
||||
catalog[scenario_key] = current
|
||||
return catalog
|
||||
|
||||
|
||||
def resolve_protocol_triplet(
|
||||
scenario: str,
|
||||
*,
|
||||
stage: str,
|
||||
context: dict[str, Any] | None = None,
|
||||
fallback_scenario: str = "atendimento_geral",
|
||||
) -> ProtocolTriplet:
|
||||
stage_key = _normalize_text(stage).lower()
|
||||
if stage_key not in _STAGES:
|
||||
stage_key = "open"
|
||||
scenario_key = _normalize_text(scenario).lower() or fallback_scenario
|
||||
fallback_key = _normalize_text(fallback_scenario).lower() or "atendimento_geral"
|
||||
|
||||
catalog = _catalog_with_overrides()
|
||||
stages = catalog.get(scenario_key) or catalog.get(fallback_key) or {}
|
||||
raw_triplet = stages.get(stage_key)
|
||||
if raw_triplet is None:
|
||||
fallback_stages = catalog.get("atendimento_geral", {})
|
||||
raw_triplet = fallback_stages.get(stage_key) or ProtocolTriplet("", "", "")
|
||||
|
||||
fmt_values = _SafeFormatDict(
|
||||
{key: _normalize_text(value) for key, value in (context or {}).items()}
|
||||
)
|
||||
return ProtocolTriplet(
|
||||
reason1=raw_triplet.reason1.format_map(fmt_values).strip(),
|
||||
reason2=raw_triplet.reason2.format_map(fmt_values).strip(),
|
||||
reason3=raw_triplet.reason3.format_map(fmt_values).strip(),
|
||||
)
|
||||
Reference in New Issue
Block a user