Skip to content

Plataforma técnica · Orchestrator

Company Service

Orchestrator Administración Empresas

CompanyService gestiona los datos corporativos del tenant — la identidad legal y tributaria de la empresa. Es un singleton: una sola fila con activa = true por tenant.

Cada tenant es una empresa. No tiene sentido modelar “varias empresas dentro de un tenant” — eso sería un nuevo tenant. La tabla administracion.configuracion_empresa puede tener histórico (filas con activa = false), pero CompanyService solo expone la vigente.

CompanyConfig:

CampoTipoNotas
idUUID
rutstringFormato 12345678-9 o 12345678-K.
razon_socialstringIdentidad legal.
nombre_fantasiastring?
girostring?Descripción libre.
giro_codigostring[]?Códigos SII (multi-actividad permitida).
direccion / comuna / regionstring?
telefono / email / sitio_webstring?Email validado por regex en update.
logo_urlstring?Usado en PDFs.
regimen_idnumber?FK a régimen tributario (14A, 14D N°3, etc.).
usar_ppm_estrategicobooleanSi usa cálculo PPM estratégico.
dep_aceleradabooleanSi aplica depreciación acelerada.
tasa_ppm_estrategicanumeric?Tasa cuando usar_ppm_estrategico = true.
ingresos_brutos_año_anterior_ufnumeric?Para clasificación PYME.
año_inicio_actividadesstring?
activabooleanFiltro singleton.
created_at / updated_attimestamp
created_by / updated_byUUID?

Devuelve la configuración vigente (WHERE activa = true LIMIT 1). Lanza Error("Company configuration not found") si no hay ninguna — escenario esperado solo durante setup de un tenant nuevo antes del seed.

Valida (si los campos están presentes):

  • RUT: ^\d{7,8}-[\dkK]$ — formato chileno con dígito verificador (mayúscula o minúscula).
  • Email: ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$.

Construye SET dinámico con los campos que vienen en updates (excluyendo id, created_at, updated_at, updated_by). Si updates no trae ningún campo válido, el repository lanza Error("No fields to update").

Corre dentro de withTransaction — el resto del flujo del request comparte la TX (no se emite hook ni se invalida cache porque no hay).

sequenceDiagram
  autonumber
  participant H as Handler PUT
  participant S as CompanyService
  participant R as CompanyRepository
  participant DB as administracion.configuracion_empresa

  H->>S: update(ctx, updates)
  alt updates.rut presente
    S->>S: validar regex RUT
  end
  alt updates.email presente
    S->>S: validar regex email
  end
  S->>S: withTransaction(BEGIN)
  S->>R: update(client, updates, userId)
  R->>DB: UPDATE ... WHERE activa = true RETURNING *
  alt 0 filas
    R-->>S: null
    S->>DB: ROLLBACK
    S--xH: Error('Company configuration not found')
  else 1 fila
    R-->>S: CompanyConfig
    S->>DB: COMMIT
    S-->>H: ServiceResult { data: CompanyConfig }
  end

Por diseño:

  • create lo hace el bootstrap del tenant (script de provisioning o seed inicial). No es una operación HTTP — se inserta junto con el resto del esquema cuando se crea la base.
  • delete no aplica — eliminar la empresa equivale a eliminar el tenant, y eso vive en el dominio Command › Tenants.

Si se quiere “resetear” la configuración de empresa, se hace update sobreescribiendo a valores nulos/default.

El regex es formato, no checksum del dígito verificador. Un RUT 99999999-9 pasa aunque el dígito real sea otro. Si necesitas validar el checksum:

  1. Agregar validateRutDv(rut: string): boolean en domain/common/utils.
  2. Llamarlo desde CompanyService.update antes del regex.

No está implementado para evitar bloquear correcciones de RUTs históricos mal cargados.

regimen_id apunta a una tabla de regímenes en parametros (commonPool). El frontend resuelve el nombre legible (14A, 14D N°3, 14D N°8, etc.); el service solo persiste el id.

usar_ppm_estrategico, tasa_ppm_estrategica, dep_acelerada y año_inicio_actividades son flags y parámetros que otros servicios (PPM, depreciación, F29) consultan para personalizar cálculos.

Documentados en Administración API. Resumen:

MétodoRutaService call
GET/api/admin/companyget(ctx)
PUT/api/admin/companyupdate(ctx, body)

Notar que PUT no requiere :id — el singleton se resuelve por activa = true.