feat: integración completa con API TNS v2
- api_client: agrega get_tns_token() — login en /v2/Acceso/Login y retorna JWT - json_generator: campos en camelCase según swagger v2; agrega nomRegTri y email placeholder cuando el paciente no tiene correo - terceros/transaccion routes: obtienen token TNS antes de cada envío, usan endpoints /v2/tablas/Tercero/Crear y /v2/rda/RdaPaciente/Insertar - config: agrega tns_empresa, tns_usuario, tns_password Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
774ce7d728
commit
6d5a85c55f
@@ -17,6 +17,9 @@ DEFAULT_KEYS = [
|
|||||||
("api_timeout", "30"),
|
("api_timeout", "30"),
|
||||||
("api_version", "1"),
|
("api_version", "1"),
|
||||||
("api_sucursal", ""),
|
("api_sucursal", ""),
|
||||||
|
("tns_empresa", "9002787299"),
|
||||||
|
("tns_usuario", "DOCUXER"),
|
||||||
|
("tns_password", "Nicolas2796*+"),
|
||||||
("num_documento_obligado", ""),
|
("num_documento_obligado", ""),
|
||||||
("cod_prestador", ""),
|
("cod_prestador", ""),
|
||||||
]
|
]
|
||||||
|
|||||||
+10
-7
@@ -7,6 +7,7 @@ from app.database import get_connection
|
|||||||
from app.auth import get_current_user
|
from app.auth import get_current_user
|
||||||
from app.services.firebird_service import get_firebird_from_config
|
from app.services.firebird_service import get_firebird_from_config
|
||||||
from app.services.json_generator import generar_tercero_api
|
from app.services.json_generator import generar_tercero_api
|
||||||
|
from app.services.api_client import get_tns_token, TNS_BASE
|
||||||
|
|
||||||
router = APIRouter(prefix="/terceros", tags=["terceros"])
|
router = APIRouter(prefix="/terceros", tags=["terceros"])
|
||||||
|
|
||||||
@@ -137,14 +138,16 @@ async def send_terceros(
|
|||||||
|
|
||||||
tercero_json = generar_tercero_api(rows[0])
|
tercero_json = generar_tercero_api(rows[0])
|
||||||
|
|
||||||
api_url = configs.get("api_url", "")
|
token, token_err = await get_tns_token(
|
||||||
api_version = configs.get("api_version", "1")
|
configs.get("tns_empresa", ""),
|
||||||
api_key = configs.get("api_key", "")
|
configs.get("tns_usuario", ""),
|
||||||
headers = {"Content-Type": "application/json"}
|
configs.get("tns_password", ""),
|
||||||
if api_key:
|
)
|
||||||
headers["Authorization"] = f"Bearer {api_key}"
|
if not token:
|
||||||
|
return JSONResponse({"success": False, "message": f"Error login TNS: {token_err}"})
|
||||||
|
|
||||||
endpoint = f"{api_url}/v{api_version}/tablas/Tercero/Crear"
|
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"}
|
||||||
|
endpoint = f"{TNS_BASE}/v2/tablas/Tercero/Crear"
|
||||||
|
|
||||||
resp_ok = False
|
resp_ok = False
|
||||||
resp_text = ""
|
resp_text = ""
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from app.database import get_connection
|
|||||||
from app.auth import get_current_user
|
from app.auth import get_current_user
|
||||||
from app.services.firebird_service import get_firebird_from_config
|
from app.services.firebird_service import get_firebird_from_config
|
||||||
from app.services.json_generator import generar_rda_paciente, agrupar_por_recepcion
|
from app.services.json_generator import generar_rda_paciente, agrupar_por_recepcion
|
||||||
|
from app.services.api_client import get_tns_token, TNS_BASE
|
||||||
|
|
||||||
router = APIRouter(prefix="/transaccion", tags=["transaccion"])
|
router = APIRouter(prefix="/transaccion", tags=["transaccion"])
|
||||||
|
|
||||||
@@ -116,15 +117,18 @@ async def send_transaccion(
|
|||||||
return JSONResponse({"success": False, "message": "No se encontraron datos"})
|
return JSONResponse({"success": False, "message": "No se encontraron datos"})
|
||||||
|
|
||||||
grupos = agrupar_por_recepcion(rows)
|
grupos = agrupar_por_recepcion(rows)
|
||||||
api_url = configs.get("api_url", "")
|
|
||||||
api_version = configs.get("api_version", "1")
|
|
||||||
api_sucursal = configs.get("api_sucursal", "")
|
|
||||||
api_key = configs.get("api_key", "")
|
|
||||||
headers = {"Content-Type": "application/json"}
|
|
||||||
if api_key:
|
|
||||||
headers["Authorization"] = f"Bearer {api_key}"
|
|
||||||
|
|
||||||
endpoint = f"{api_url}/v{api_version}/rda/RdaPaciente/Insertar"
|
token, token_err = await get_tns_token(
|
||||||
|
configs.get("tns_empresa", ""),
|
||||||
|
configs.get("tns_usuario", ""),
|
||||||
|
configs.get("tns_password", ""),
|
||||||
|
)
|
||||||
|
if not token:
|
||||||
|
return JSONResponse({"success": False, "message": f"Error login TNS: {token_err}"})
|
||||||
|
|
||||||
|
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"}
|
||||||
|
api_sucursal = configs.get("api_sucursal", "")
|
||||||
|
endpoint = f"{TNS_BASE}/v2/rda/RdaPaciente/Insertar"
|
||||||
if api_sucursal:
|
if api_sucursal:
|
||||||
endpoint += f"?codigosucursal={api_sucursal}"
|
endpoint += f"?codigosucursal={api_sucursal}"
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,26 @@
|
|||||||
import httpx
|
import httpx
|
||||||
import json
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
TNS_BASE = "https://api.tns.co"
|
||||||
|
|
||||||
|
|
||||||
|
async def get_tns_token(empresa: str, usuario: str, password: str) -> tuple:
|
||||||
|
"""Hace login en TNS v2 y devuelve (token, error_msg)."""
|
||||||
|
try:
|
||||||
|
async with httpx.AsyncClient(timeout=30) as client:
|
||||||
|
resp = await client.post(
|
||||||
|
f"{TNS_BASE}/v2/Acceso/Login",
|
||||||
|
json={"codigoEmpresa": empresa, "nombreUsuario": usuario, "contrasenia": password},
|
||||||
|
)
|
||||||
|
body = resp.json()
|
||||||
|
if resp.is_success and body.get("status"):
|
||||||
|
return body["data"], None
|
||||||
|
return None, body.get("message") or f"HTTP {resp.status_code}"
|
||||||
|
except Exception as e:
|
||||||
|
return None, str(e)
|
||||||
|
|
||||||
|
|
||||||
async def send_json(
|
async def send_json(
|
||||||
url: str,
|
url: str,
|
||||||
json_data: dict,
|
json_data: dict,
|
||||||
|
|||||||
@@ -52,34 +52,35 @@ def generar_tercero_api(row: dict) -> dict:
|
|||||||
zona = _ZONA_MAP.get(str(row.get("TIPORES") or "U").strip(), "01")
|
zona = _ZONA_MAP.get(str(row.get("TIPORES") or "U").strip(), "01")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"Codigo": str(row.get("CODIGO") or "").strip(),
|
"codigo": str(row.get("CODIGO") or "").strip(),
|
||||||
"NatJuridica": "N",
|
"natJuridica": "N",
|
||||||
"TipoDocumento": tipo_doc,
|
"tipoDocumento": tipo_doc,
|
||||||
"Nit": str(row.get("DOCIDENT") or "").strip(),
|
"nit": str(row.get("DOCIDENT") or "").strip(),
|
||||||
"Nombre": nombre_completo,
|
"nombre": nombre_completo,
|
||||||
"Nombre1": nombres[0] if nombres else "",
|
"nombre1": nombres[0] if nombres else "",
|
||||||
"Nombre2": nombres[1] if len(nombres) > 1 else "",
|
"nombre2": nombres[1] if len(nombres) > 1 else "",
|
||||||
"Apellido1": apellidos[0] if apellidos else "",
|
"apellido1": apellidos[0] if apellidos else "",
|
||||||
"Apellido2": apellidos[1] if len(apellidos) > 1 else "",
|
"apellido2": apellidos[1] if len(apellidos) > 1 else "",
|
||||||
"Direccion": (row.get("DIRECCION") or "").strip(),
|
"direccion": (row.get("DIRECCION") or "").strip(),
|
||||||
"CodigoCiudad": str(row.get("COD_CIUDAD") or "00").strip(),
|
"codigoCiudad": str(row.get("COD_CIUDAD") or "00").strip(),
|
||||||
"NombreCiudad": (row.get("NOM_CIUDAD") or "SIN CIUDAD").strip().upper(),
|
"nombreCiudad": (row.get("NOM_CIUDAD") or "SIN CIUDAD").strip().upper(),
|
||||||
"Zona1": "00",
|
"zona1": "00",
|
||||||
"Clasificacion": "00",
|
"clasificacion": "00",
|
||||||
"Telefono": str(row.get("TELEFONOS") or "").strip(),
|
"nomRegTri": nombre_completo,
|
||||||
"Email": (row.get("EMAIL") or "").strip(),
|
"telefono": str(row.get("TELEFONOS") or "").strip(),
|
||||||
"Inactivo": False,
|
"email": (row.get("EMAIL") or "").strip() or f"{str(row.get('DOCIDENT') or 'paciente').strip()}@sinregistro.co",
|
||||||
"Privada": "N",
|
"inactivo": False,
|
||||||
"Mixta": "N",
|
"privada": "N",
|
||||||
"CodigoBarrio": "00",
|
"mixta": "N",
|
||||||
"Comision": 0,
|
"codigoBarrio": "00",
|
||||||
"FechaNacimiento": _fmt_fecha(row.get("F_NACIMIENTO")),
|
"comision": 0,
|
||||||
"Sexo": str(row.get("SEXO") or "M").strip(),
|
"fechaNacimiento": _fmt_fecha(row.get("F_NACIMIENTO")),
|
||||||
"Zona": zona,
|
"sexo": str(row.get("SEXO") or "M").strip(),
|
||||||
"Etnia": str(row.get("CODETNIA") or "99").strip(),
|
"zona": zona,
|
||||||
"Cliente": "S",
|
"etnia": str(row.get("CODETNIA") or "99").strip(),
|
||||||
"EnfermedadCronica": False,
|
"cliente": "S",
|
||||||
"NoEnviarMinSalud": False,
|
"enfermedadCronica": False,
|
||||||
|
"noEnviarMinSalud": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -109,15 +110,15 @@ def generar_rda_paciente(rows: list) -> dict:
|
|||||||
else h.get("FECHA_RECEPCION")
|
else h.get("FECHA_RECEPCION")
|
||||||
)
|
)
|
||||||
detalle_pedido.append({
|
detalle_pedido.append({
|
||||||
"CodigoMaterial": str(row.get("COD_EXAMEN") or "").strip(),
|
"codigoMaterial": str(row.get("COD_EXAMEN") or "").strip(),
|
||||||
"CodigoBodega": "00",
|
"codigoBodega": "00",
|
||||||
"Cantidad": 1,
|
"cantidad": 1,
|
||||||
"TipoUnidad": "D",
|
"tipoUnidad": "D",
|
||||||
"Valor": float(row.get("PRECIO") or 0),
|
"valor": float(row.get("PRECIO") or 0),
|
||||||
"Descuento": 0,
|
"descuento": 0,
|
||||||
"PorcentajeIva": 0,
|
"porcentajeIva": 0,
|
||||||
"ImpConsumo": 0,
|
"impConsumo": 0,
|
||||||
"Observacion": "",
|
"observacion": "",
|
||||||
"profesional": str(h.get("profesional") or "").strip(),
|
"profesional": str(h.get("profesional") or "").strip(),
|
||||||
"especialidad": str(row.get("COD_ESPECIALIDAD") or "").strip(),
|
"especialidad": str(row.get("COD_ESPECIALIDAD") or "").strip(),
|
||||||
"diagnosticoprincipal": str(h.get("DIAG_PPAL") or "").strip(),
|
"diagnosticoprincipal": str(h.get("DIAG_PPAL") or "").strip(),
|
||||||
@@ -127,14 +128,14 @@ def generar_rda_paciente(rows: list) -> dict:
|
|||||||
autorizacion = str(h.get("AUTORIZACION") or "").strip() or None
|
autorizacion = str(h.get("AUTORIZACION") or "").strip() or None
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"CodigoPrefijo": str(h.get("PREFIJO") or "00").strip(),
|
"codigoPrefijo": str(h.get("PREFIJO") or "00").strip(),
|
||||||
"Numero": "",
|
"numero": "",
|
||||||
"Fecha": fecha,
|
"fecha": fecha,
|
||||||
"CodTercero": str(h.get("COD_PACIENTE") or "").strip(),
|
"codTercero": str(h.get("COD_PACIENTE") or "").strip(),
|
||||||
"CodVendedor": "00",
|
"codVendedor": "00",
|
||||||
"CodFormaPago": "CO",
|
"codFormaPago": "CO",
|
||||||
"CodBanco": "00",
|
"codBanco": "00",
|
||||||
"CodigoCentroCosto": "00",
|
"codigoCentroCosto": "00",
|
||||||
"tipoIngreso": str(h.get("CLASEPROC") or "1").strip() or "1",
|
"tipoIngreso": str(h.get("CLASEPROC") or "1").strip() or "1",
|
||||||
"fechaHoraIngreso": ingreso,
|
"fechaHoraIngreso": ingreso,
|
||||||
"fechaHoraEgreso": egreso,
|
"fechaHoraEgreso": egreso,
|
||||||
@@ -146,12 +147,12 @@ def generar_rda_paciente(rows: list) -> dict:
|
|||||||
"esTerapia": False,
|
"esTerapia": False,
|
||||||
"esProcedimiento": False,
|
"esProcedimiento": False,
|
||||||
"numeroAutorizacion": autorizacion,
|
"numeroAutorizacion": autorizacion,
|
||||||
"DetallePedido": detalle_pedido,
|
"detallePedido": detalle_pedido,
|
||||||
"DetalleFormaPago": [{
|
"detalleFormaPago": [{
|
||||||
"CodigoFormaPago": "CO",
|
"codigoFormaPago": "CO",
|
||||||
"PlazoDias": "0",
|
"plazoDias": "0",
|
||||||
"FechaVencimiento": fecha,
|
"fechaVencimiento": fecha,
|
||||||
"Valor": str(int(float(h.get("VALORTOTAL") or 0))),
|
"valor": str(int(float(h.get("VALORTOTAL") or 0))),
|
||||||
}],
|
}],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user