FactuGES_ERP/docs/companies/company-requirements.md
david e0ba5ef229 feat: add proforma duplicator service and related tests
- 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.
2026-08-26 13:03:39 +02:00

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 (active o disabled);
  • 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

  • identity es propietario de Account y CompanyMembership.
  • companies es propietario de Company y de su ficha operativa.
  • El access token solo identifica la cuenta; no contiene companyId, companySlug, roles ni permisos.
  • identity resuelve que IDs de empresa son accesibles para una cuenta.
  • companies resuelve las fichas completas de esas empresas y valida que una empresa este activa.
  • No se deben crear GET /identity/companies ni GET /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 null limpia 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 status autorizados 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.