- Implemented ProformaDuplicator service for duplicating proforma documents. - Added tests for duplicating proformas, including scenarios for successful duplication, audit failure propagation, and payment term adaptations. - Created ProformaStatusChanger service to handle status changes of proformas with corresponding tests. - Developed ProformaArchiver service for unarchiving proformas and added tests to verify functionality. - Introduced a test fixture for creating proforma instances for testing purposes.
8.0 KiB
Requisitos de companies
Estado documental: CURRENT
Fecha de actualizacion: 2026-08-26
Proposito y fuente de verdad
companies es el bounded context y la fuente de verdad de la ficha operativa
de cada empresa tenant del ERP. Este documento define el contrato funcional
vigente del contexto.
La autenticacion, las cuentas y las memberships no pertenecen a companies.
Esas responsabilidades corresponden a identity. Para las decisiones de
integracion entre ambos contextos, prevalece
identity-and-companies.md. Para
la resolucion del tenant, prevalece
tenant-context.md.
Alcance actual
El contexto debe gestionar:
- la ficha legal y operativa basica de
Company; - el identificador funcional
slug; - el estado operativo de la empresa (
activeodisabled); - el plazo de pago por defecto de la empresa;
- la consulta de empresas disponibles para una cuenta autenticada;
- la consulta y actualizacion de la empresa activa.
El contexto no debe gestionar:
- autenticacion, sesiones, refresh tokens o cuentas;
CompanyMembership, roles o permisos por cuenta;- datos de la empresa dentro de
identity; - clientes como representacion de la empresa tenant;
- fiscalidad avanzada, perfiles VeriFactu, series documentales, medios de pago, direccion, branding, bancos, idiomas, divisas o zona horaria.
Los requisitos de VeriFactu empresarial viven en customer-invoices y no
amplian por si mismos el aggregate Company.
Modelo funcional
Una empresa se identifica por un UUID y contiene los siguientes datos:
| Campo | Regla vigente |
|---|---|
legal_name |
Obligatorio. Nombre legal de la empresa. |
trade_name |
Opcional y nullable. Nombre comercial. |
tin |
Opcional y nullable. Identificador fiscal. |
slug |
Obligatorio, unico, normalizado a minusculas; solo letras, numeros y guiones, de 2 a 100 caracteres. |
email |
Opcional y nullable; debe tener formato valido. |
phone |
Opcional y nullable. |
website |
Opcional y nullable; debe tener formato URL valido. |
default_payment_term_id |
Opcional y nullable; referencia viva a un plazo de pago activo de la misma empresa. |
status |
active o disabled. |
La persistencia de companies debe conservar tambien created_at y
updated_at. slug es unico; deben existir indices para status y tin.
Separacion con identity
identityes propietario deAccountyCompanyMembership.companieses propietario deCompanyy de su ficha operativa.- El access token solo identifica la cuenta; no contiene
companyId,companySlug, roles ni permisos. identityresuelve que IDs de empresa son accesibles para una cuenta.companiesresuelve las fichas completas de esas empresas y valida que una empresa este activa.- No se deben crear
GET /identity/companiesniGET /account/companies. - No se debe crear una dependencia
identity -> companies.
Contexto tenant y autorizacion V1
Las rutas tenant-scoped deben recibir:
Authorization: Bearer <access_token>
X-Company-Id: <uuid-company>
El contexto tenant es valido solo si la cuenta esta autenticada, el header es
un UUID valido, existe una membership active para esa empresa y la empresa
tiene estado active. La empresa destino se toma de ese contexto, nunca de un
companyId libre en body, query o ruta cuando se trate de la API actual de
empresa activa.
En la V1, cualquier miembro activo de una empresa activa puede actualizar los
datos generales de esa empresa mediante PATCH /companies/current. No existe
todavia enforcement runtime de RBAC ni un permiso granular efectivo como
identity:companies:update.
Una empresa deshabilitada no puede actualizarse. Los endpoints legacy con
:company_id deben exigir que dicho ID coincida exactamente con la empresa
resuelta en el contexto tenant.
Contratos HTTP vigentes
Alta y seleccion de empresa
POST /companies
GET /companies/available
POST /companies crea una empresa activa. Recibe id, legal_name y slug
como datos obligatorios; el resto de datos de ficha son opcionales. Al crearla,
default_payment_term_id queda vacio y el estado es active.
GET /companies/available requiere autenticacion, pero no X-Company-Id.
Debe devolver solo las empresas que cumplan simultaneamente:
membership activa de la cuenta
+
empresa activa
La respuesta no debe modificar la sesion ni el access token.
Empresa activa
GET /companies/current
PATCH /companies/current
Estas son las rutas canonicamente usadas por Settings para
/settings/company/details. Requieren contexto tenant valido y operan siempre
sobre la empresa resuelta mediante X-Company-Id.
PATCH /companies/current admite exclusivamente:
legal_name
trade_name
tin
email
phone
website
default_payment_term_id
No admite modificar slug ni status. La semantica es PATCH real:
- un campo omitido conserva su valor;
- un campo nullable presente con
nulllimpia su valor; - un campo presente con valor valido actualiza su valor;
- la respuesta del servidor es el estado autoritativo de la ficha.
Rutas legacy por ID
GET /companies/:company_id
PATCH /companies/:company_id
POST /companies/:company_id/enable
POST /companies/:company_id/disable
Estas rutas siguen expuestas por compatibilidad. Requieren contexto tenant
valido y el :company_id debe ser la misma empresa activa del header. En la
actualizacion legacy se permite adicionalmente modificar slug; su unicidad
debe validarse antes de persistir.
Plazo de pago por defecto
default_payment_term_id es una referencia nullable y company-scoped hacia
catalogs. Su contrato es:
- omitido: conservar la asociacion actual;
null: desvincular el plazo de pago;- UUID: asociar solo si identifica un plazo activo de la misma empresa.
Una referencia inexistente, de otra empresa o inactiva debe responder 422 con
el mensaje opaco Default payment term is not assignable to the active company.
No se debe revelar cual de esas causas se produjo. La validacion y la
actualizacion deben formar una unica transaccion: si falla la referencia, no se
persisten otros cambios del mismo PATCH.
Respuesta de empresa
Las consultas y mutaciones de ficha devuelven:
type CompanyResponseDTO = {
id: string;
legal_name: string;
trade_name: string | null;
tin: string | null;
slug: string;
email: string | null;
phone: string | null;
website: string | null;
default_payment_term_id: string | null;
status: "active" | "disabled";
};
La lista de GET /companies/available devuelve el mismo subconjunto de ficha
necesario para seleccionar empresa, sin default_payment_term_id, y con
status: "active".
Errores esperados
| Situacion | Respuesta |
|---|---|
| Sin autenticacion, token invalido o cuenta no autenticable | 401 |
| UUID tenant mal formado o body invalido | 400 |
Sin X-Company-Id, membership no activa, empresa no accesible, deshabilitada o destino distinto al tenant |
403 |
Colision de slug |
409 |
| Campo con regla de dominio invalida o plazo de pago no asignable | 422 |
| Error no controlado | 500 |
Auditoria y consistencia
Las operaciones de alta y actualizacion de empresa deben registrar sus eventos de auditoria. Las mutaciones deben ser transaccionales para no dejar la ficha y el registro de auditoria en estados divergentes.
Fuera de alcance y evolucion futura
No se deben inferir como requisitos actuales:
- RBAC granular o administracion global de empresas;
- cambios de
statusautorizados por un rol administrativo real; - direccion, pais, idioma, moneda, zona horaria o branding;
- cuentas bancarias, logo, medios de pago o
defaultPaymentMethodId; - fiscalidad avanzada, configuracion VeriFactu o series documentales.
Estas capacidades requieren un contrato propio antes de incorporarse a
companies. Hasta entonces, los documentos de otros bounded contexts deben
enlazar esta especificacion al describir la ficha de empresa, sin duplicar ni
reasignar su ownership.