fix(core): crear compañía real en a76.company por tenant (arregla FK y desbloqueo)

my-companies usaba company_id = tenant_id, pero user_tenants.company_id tiene FK a
a76.company (entidad real heredada de Anexo76). Con el tenant real (aduanasoft=11)
no existía fila de compañía → ForeignKeyViolation → sin compañía → todo bloqueado.

Ahora my-companies lista las compañías del tenant desde a76.company y, si no hay
ninguna, crea una por defecto (nombre = el del tenant) en el primer acceso, usando
su id real; luego asegura el vínculo usuario↔compañía. Base para el módulo de
gestión de compañías.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ernesto Herrera
2026-07-17 10:31:59 -06:00
parent 29170f7c8c
commit 0b6848bbdd

View File

@@ -431,32 +431,61 @@ async def get_my_companies(
_ensure_user_tenant_for_company,
)
from api.v1.modules.core.tenants.models import Tenant
from sqlalchemy import text
import logging as _logging
_log = _logging.getLogger(__name__)
tenant_id = resolve_effective_tenant_id_from_user(current_user)
if not tenant_id:
# Usuario sin tenant (p. ej. hub_admin global): no hay compañía que resolver.
return []
tenant_id = int(tenant_id)
tenant = db.query(Tenant).filter(Tenant.id == int(tenant_id)).first()
name = (
(tenant.name if tenant else None)
or current_user.get("tenant_slug")
or "Mi empresa"
)
# La compañía es una entidad REAL del CRM (a76.company, heredada de Anexo76).
# Se listan las compañías del tenant; si no hay ninguna, se crea una por defecto
# en el primer acceso (nombre = el del tenant).
rows = db.execute(
text("SELECT id, name, rfc, logo FROM a76.company WHERE tenant_id = :tid ORDER BY id"),
{"tid": tenant_id},
).fetchall()
# Garantizar el vínculo usuario↔tenant↔company (company_id = tenant_id).
if not rows:
tenant = db.query(Tenant).filter(Tenant.id == tenant_id).first()
default_name = (
(tenant.name if tenant else None)
or current_user.get("tenant_slug")
or "Mi empresa"
)
created = db.execute(
text(
"INSERT INTO a76.company (tenant_id, name) VALUES (:tid, :name) "
"RETURNING id, name, rfc, logo"
),
{"tid": tenant_id, "name": default_name},
).fetchone()
# Alinear la secuencia por si hubo inserts con id explícito (seed dev).
db.execute(text("SELECT setval('a76.company_id_seq', (SELECT MAX(id) FROM a76.company))"))
db.commit()
rows = [created]
_log.info("Compañía por defecto creada para tenant=%s: id=%s", tenant_id, created[0])
# Asegurar el vínculo usuario↔compañía por cada compañía del tenant.
user_id = current_user.get("sub") or current_user.get("id")
if user_id:
try:
_ensure_user_tenant_for_company(db, str(user_id), int(tenant_id), int(tenant_id))
except Exception as exc:
logger = __import__("logging").getLogger(__name__)
logger.warning("no se pudo asegurar user_tenant (no bloquea): %s", exc)
return [{
"id": int(tenant_id),
"name": name,
"tenant_id": int(tenant_id),
"rfc": None,
"logo": None,
"is_active": True,
}]
companies = []
for r in rows:
cid = int(r[0])
if user_id:
try:
_ensure_user_tenant_for_company(db, str(user_id), tenant_id, cid)
except Exception as exc:
_log.warning("no se pudo asegurar user_tenant (no bloquea): %s", exc)
companies.append({
"id": cid,
"name": r[1] or "Mi empresa",
"tenant_id": tenant_id,
"rfc": r[2],
"logo": r[3],
"is_active": True,
})
return companies