Skip to content

Plataforma técnica · Orchestrator

Cargo Service

Remuneraciones Cargos Catalogo

CargoService administra el catálogo de cargos del tenant. Es deliberadamente delgado: las decisiones contables (banda salarial, jerarquía, cuenta de gasto asociada) se materializan al asociar el cargo al contrato, no acá. Este service sólo mantiene el catálogo coherente.

El cargo aporta tres controles al ciclo de remuneraciones: clasificación funcional para reportería, banda salarial referencial para detectar desviaciones, y nivel jerárquico para flujos de aprobación.

  • Directoryorchestrator/src/domain/cargos/
    • CargoService.ts
    • CargoRepository.ts

Tabla: remuneraciones.cargos.

MétodoFirmaResultado
findAll(ctx) => Promise<Cargo[]>Catálogo ordenado por nivel_jerarquico, nombre. Cap a 500 filas.
findById(ctx, id) => Promise<Cargo | null>Cargo completo o null.
create(ctx, data: Cargo) => Promise<ServiceResult<string>>Inserta y devuelve el id generado.
update(ctx, id, data: Partial<Cargo>) => Promise<ServiceResult<number>>Filas afectadas; lanza Error("Cargo no encontrado") si 0.
delete(ctx, id) => Promise<ServiceResult<number>>Filas borradas; lanza Error("Cargo no encontrado") si 0.
interface Cargo {
id?: string;
codigo: string; // único, normalizado uppercase + trim
nombre: string; // trim
descripcion?: string;
nivel_jerarquico?: number; // default 1
salario_minimo?: number; // default 0
salario_maximo?: number; // default 0
requiere_titulo_profesional?: boolean; // default false
requiere_experiencia_anos?: number; // default 0
activo?: boolean; // default true
}
CampoRegla
codigo, nombreObligatorios. validateRequired los exige.
codigoSe transforma a data.codigo.toUpperCase().trim() antes de persistir → garantiza unicidad case-insensitive.
nombreSe transforma a data.nombre.trim().
DefaultsEl repository completa nivel_jerarquico=1, salario_minimo=0, salario_maximo=0, requiere_titulo_profesional=false, requiere_experiencia_anos=0, activo=true cuando vienen null/undefined.

El repository filtra el payload antes de armar el UPDATE:

const dataToUpdate = Object.fromEntries(
Object.entries(data).filter(([key, value]) =>
key !== "id" && key !== "created_by" && key !== "created_at" &&
key !== "updated_by" && key !== "updated_at" &&
value !== undefined && value !== null
)
);

Si después del filtrado no quedan campos, ejecuta sólo SET updated_by = $2, updated_at = NOW() — útil para “tocar” el cargo y refrescar trazabilidad.

OrigenMensajeCuándo
Validación previa"<Campo> es requerido" (de validateRequired)Crear sin codigo o sin nombre.
Service"Cargo no encontrado"update o delete con id que no afecta filas.
Base de datosunique_violation (23505)codigo duplicado tras normalización.
Base de datosforeign_key_violation (23503)delete con contratos vigentes que referencian el cargo.
  1. Endpoint llama a CargoService.create(ctx, data).

  2. validateRequired confirma codigo y nombre.

  3. Service normaliza: codigo.toUpperCase().trim() y nombre.trim().

  4. CargoRepository.create(pool, normalized, userId) inserta con buildInsert y RETURNING id.

  5. Devuelve ServiceResult<string> con el id recién creado.

Service / VistaCómo consume
ContractServicecargo_id opcional en el contrato; valida que exista al persistir.
v_empleados_activosJoin contra cargos para exponer cargo_nombre y nivel_jerarquico al frontend.
PayrollServiceNo consume cargo directamente; lo recibe vía contrato cuando arma contexto.