OperationsService
Orchestrator Services
Compras-VentasOrchestratorServicio
Propósito
Section titled “Propósito”OperationsService coordina la generacion de detalle contable para documentos SII de ventas, compras y boletas. Toma documentos normalizados desde el esquema operaciones_sii, los clasifica por concepto contable y persiste lineas en operaciones_sii.compras_ventas_detalle.
El servicio tambien permite consultar documentos fuente, revisar el estado de contabilizacion por periodo, contabilizar ingresos netos de ventas o boletas y reversar esa contabilizacion cuando corresponde.
Esta pagina describe el flujo tecnico actual de forma publica. No incluye rutas locales, credenciales, nombres de bases de datos de clientes ni detalles operativos que dependan de un entorno privado.
Responsabilidades del Servicio
Section titled “Responsabilidades del Servicio”El servicio concentra cinco responsabilidades:
- generar detalle contable automatico para
VENTA,COMPRAoBOLETA; - impedir reprocesos accidentales cuando ya existen detalles para el periodo solicitado;
- clasificar cada documento en conceptos activos de
operaciones_sii.conceptos_operaciones; - marcar ingresos netos de ventas o boletas como contabilizados cuando el llamador lo solicita;
- exponer consultas de documentos fuente y resumen de estado por tipo documental.
La generacion no registra asientos definitivos en el libro mayor. Produce detalle operacional auditable, con estado inicial PENDIENTE, que otros flujos pueden contabilizar, pagar, anular o consumir como base de declaraciones.
Dependencias Conceptuales
Section titled “Dependencias Conceptuales”DirectoryOrchestrator
- OperacionesService
- OperacionesRepository
- ventasContabilizables
DirectoryMother
- operaciones_sii.ventas
- operaciones_sii.compras
- operaciones_sii.boletas
- operaciones_sii.compras_otros_impuestos
- operaciones_sii.conceptos_operaciones
- operaciones_sii.compras_ventas_detalle
Flujo de Generación
Section titled “Flujo de Generación”Los fragmentos siguientes muestran el flujo publico del metodo generate. Los nombres de repositorio y campos corresponden al dominio actual; los identificadores reales se expresan como parametros o placeholders.
-
Recibir el contexto de servicio y validar que el tipo documental venga informado.
async generate(ctx: ServiceContext,params: OperationsGenerateParams,): Promise<ServiceResult<{ message: string; count: number }>> {this.validateRequired(params, ['tipo_documento']);} -
Validar que
contabilizar_ingresossolo se use para ventas o boletas.if (params.contabilizar_ingresos &&!['VENTA', 'BOLETA'].includes(params.tipo_documento)) {throw new ValidationError('contabilizar_ingresos solo aplica a VENTA o BOLETA',);} -
Abrir una transaccion y resolver si corresponde reprocesar o bloquear.
return this.withTransaction(ctx, async (client, outbox) => {if (params.forzar_reproceso) {await OperacionesRepository.deleteDetails(client,params.tipo_documento,params.periodo_desde,params.periodo_hasta,);} else {const existingDetails =await OperacionesRepository.countExistingDetails(client,params.tipo_documento,params.periodo_desde,params.periodo_hasta,);}}); -
Cargar conceptos activos y construir el mapa
codigo -> id.const concepts = await OperacionesRepository.fetchConcepts(client);const conceptMap = new Map<string, number>();concepts.forEach((c) => conceptMap.set(c.codigo, c.id));const getConceptId = (code: string) => {const id = conceptMap.get(code);if (!id) throw new Error(`Concepto no encontrado: ${code}`);return id;}; -
Delegar el procesamiento segun
tipo_documento.if (params.tipo_documento === 'VENTA') {await this.processVentas(client, params, getConceptId, results, ctx.userId);} else if (params.tipo_documento === 'COMPRA') {await this.processCompras(client, params, getConceptId, results, ctx.userId);} else if (params.tipo_documento === 'BOLETA') {await this.processBoletas(client, params, getConceptId, results, ctx.userId);} -
Persistir el detalle generado en
compras_ventas_detalle.await OperacionesRepository.createBulkDetails(client, results); -
Si el llamador pidio contabilizar ingresos, marcar lineas netas de ventas o boletas y publicar eventos.
if (params.contabilizar_ingresos) {const contabilizacion =await OperacionesRepository.contabilizarIngresosNetos(client,params.tipo_documento as 'VENTA' | 'BOLETA',params.periodo_desde,params.periodo_hasta,ctx.userId,);for (const eventPayload of contabilizacion.eventos) {outbox.queue('venta:contabilizada', eventPayload);}}
Clasificación de Ventas
Section titled “Clasificación de Ventas”processVentas lee documentos desde operaciones_sii.ventas y genera hasta dos lineas por documento: neto e IVA. La clasificacion depende del tipo de documento y de los montos informados.
| Caso | Concepto neto | Concepto IVA | Tratamiento |
|---|---|---|---|
| Venta afecta | VENTA-PRD-NET | VENTA-PRD-IVA | Reconoce neto e IVA debito. |
| Venta exenta | VENTA-EXE-NET | No aplica | Usa monto_exento cuando no hay neto afecto. |
| Nota de credito de venta | NC-VENTA-NET | NC-VENTA-IVA | Invierte neto e IVA con signo negativo. |
| Nota de debito de venta | ND-VENTA-NET | ND-VENTA-IVA | Registra neto e IVA con signo positivo. |
| Factura de compra recibida como venta | FACT-COMP-NET | FACT-COMP-IVA-RET | Usa el RUT cliente como emisor y calcula IVA no retenido. |
Para facturas de compra registradas en el libro de ventas, el IVA neto se calcula restando IVA retenido total y parcial al IVA informado.
const montoIva = Number(v.monto_iva || 0);const ivaRetenido = Number(v.iva_retenido_total || 0) + Number(v.iva_retenido_parcial || 0);
return Math.max(0, montoIva - ivaRetenido);Clasificación de Compras
Section titled “Clasificación de Compras”processCompras lee documentos desde operaciones_sii.compras y agrega otros_impuestos desde operaciones_sii.compras_otros_impuestos mediante LEFT JOIN y json_agg. El procesamiento genera lineas para neto, IVA recuperable, IVA no recuperable, otros impuestos y diferencias de redondeo.
| Caso | Concepto neto | Concepto IVA | Tratamiento |
|---|---|---|---|
| Compra afecta | COMP-MER-NET | COMP-MER-IVA | Reconoce neto de compra e IVA credito fiscal. |
| Nota de credito de compra | NC-COMPRA-NET | NC-COMPRA-IVA | Invierte neto e IVA recuperable con signo negativo. |
| Nota de debito de compra | ND-COMPRA-NET | ND-COMPRA-IVA | Registra neto e IVA recuperable con signo positivo. |
| IVA no recuperable | ID fijo 30 | No aplica | Registra gasto por IVA no recuperable. |
| Otros impuestos | COMP-OI-{codigo} o COMP-OI | No aplica | Usa concepto especifico por codigo y cae a generico si existe. |
| Redondeo | COMP-RDO | No aplica | Registra diferencias de uno o dos pesos. |
El IVA no recuperable se trata como gasto separado y respeta el signo de las notas de credito.
const montoIvaNoRecuperable = Number(c.monto_iva_no_recuperable || 0);if (montoIvaNoRecuperable === 0) return;
const monto = esNC ? -Math.abs(montoIvaNoRecuperable) : Math.abs(montoIvaNoRecuperable);Los otros impuestos de compra buscan primero un concepto especifico por codigo SII, por ejemplo COMP-OI-27, y luego el concepto generico COMP-OI. Si ninguno existe en el tenant, la linea se omite.
La diferencia de redondeo compara el total del documento contra la suma de neto, IVA recuperable, IVA no recuperable, activo fijo, exento y otros impuestos. Solo se genera COMP-RDO cuando la diferencia absoluta es de uno o dos pesos.
Clasificación de Boletas
Section titled “Clasificación de Boletas”processBoletas lee documentos desde operaciones_sii.boletas y genera dos lineas por boleta.
| Linea | Concepto | Monto |
|---|---|---|
| Neto | VENTA-BOL-NET | neto |
| IVA | VENTA-BOL-IVA | iva |
Cuando tipo_doc viene nulo desde base de datos, el servicio usa 39 como tipo DTE por defecto. La razon social se normaliza como Consumidor Final.
Contabilización de Ingresos
Section titled “Contabilización de Ingresos”La opcion contabilizar_ingresos no genera nuevas lineas; marca como contabilizadas lineas netas ya insertadas en compras_ventas_detalle. Solo aplica a VENTA y BOLETA.
Los conceptos considerados contabilizables son:
[ 'VENTA-PRD-NET', 'VENTA-BOL-NET', 'VENTA-EXE-NET', 'NC-VENTA-NET', 'ND-VENTA-NET', 'FACT-COMP-NET',]La marca actualiza las lineas pendientes con:
| Campo | Valor aplicado |
|---|---|
estado | CONTABILIZADO |
referencia | EXISTENCIAS |
fecha_contabilizacion | fecha_documento |
updated_by | Usuario ejecutor |
updated_at | Fecha actual |
Por cada documento afectado, el repositorio recupera un payload y el servicio publica venta:contabilizada en el outbox. Para ventas, el payload se obtiene desde operaciones_sii.ventas; para boletas, desde operaciones_sii.boletas.
Reversa de Ingresos
Section titled “Reversa de Ingresos”reversarContabilizacionIngresos revierte solo ingresos netos de VENTA o BOLETA que hayan sido marcados por este flujo.
-
Validar que
tipo_documentoseaVENTAoBOLETA.this.validateRequired(params, ['tipo_documento']);if (!['VENTA', 'BOLETA'].includes(params.tipo_documento)) {throw new ValidationError('reversar contabilización de ingresos solo aplica a VENTA o BOLETA',);} -
Buscar lineas en estado
CONTABILIZADOoPAGADO, conreferencia = 'EXISTENCIAS'. -
Volver las lineas a
PENDIENTEy limpiarreferenciayfecha_contabilizacion.SET estado = 'PENDIENTE',referencia = NULL,fecha_contabilizacion = NULL,updated_by = $user,updated_at = CURRENT_TIMESTAMP
La reversa no aplica a compras, porque las compras no usan contabilizar_ingresos y pueden derivar hacia flujos distintos, como activo fijo, existencias, gastos o impuestos.
Entradas
Section titled “Entradas”| Entrada | Descripcion |
|---|---|
ctx | Contexto de servicio con base tenant y usuario ejecutor. |
tipo_documento | COMPRA, VENTA o BOLETA. |
periodo_desde | Periodo inicial opcional en formato YYYY-MM. |
periodo_hasta | Periodo final opcional en formato YYYY-MM. |
forzar_reproceso | Si es verdadero, borra detalles previos del tipo y periodo antes de regenerar. |
contabilizar_ingresos | Si es verdadero, contabiliza ingresos netos generados para ventas o boletas. |
Los identificadores reales deben tratarse como datos de entorno. En documentacion publica, usar placeholders como $TENANT_ID, $PERIODO_DESDE o $PERIODO_HASTA.
Persistencia
Section titled “Persistencia”operaciones_sii.conceptos_operaciones
Section titled “operaciones_sii.conceptos_operaciones”Catalogo de conceptos activos que traduce codigos de dominio a identificadores numericos.
| Campo conceptual | Uso |
|---|---|
id | Identificador usado en compras_ventas_detalle.concepto_id. |
codigo | Codigo semantico usado por el servicio, como COMP-MER-NET o VENTA-PRD-IVA. |
activo | Solo los conceptos activos participan en la generacion. |
operaciones_sii.compras_ventas_detalle
Section titled “operaciones_sii.compras_ventas_detalle”Tabla operacional donde se persiste el resultado de la generacion.
| Campo conceptual | Uso |
|---|---|
tipo_documento | Tipo origen: VENTA, COMPRA o BOLETA. |
documento_id | Identificador del documento fuente. |
tipo_dte | Tipo DTE informado por SII o valor normalizado. |
folio | Folio del documento. |
fecha_documento | Fecha del documento SII. |
rut_emisor | RUT emisor o proveedor, segun tipo documental. |
rut_receptor | RUT receptor o cliente, segun tipo documental. |
razon_social | Nombre asociado al documento. |
año, mes | Periodo contable usado para filtros y resumen. |
concepto_id | Concepto operacional resuelto desde el catalogo. |
monto | Monto de la linea operacional, con signo segun documento. |
glosa | Descripcion generada por el servicio. |
origen | Actualmente AUTOMATICO. |
estado | Estado operacional de la linea. |
referencia | Marca usada por flujos posteriores, por ejemplo EXISTENCIAS. |
Tablas Fuente
Section titled “Tablas Fuente”| Tabla | Uso en el servicio |
|---|---|
operaciones_sii.ventas | Fuente de documentos de venta, notas y facturas de compra en libro de ventas. |
operaciones_sii.compras | Fuente de compras, notas, IVA recuperable/no recuperable y montos de activo fijo. |
operaciones_sii.compras_otros_impuestos | Detalle de impuestos adicionales asociados a compras. |
operaciones_sii.boletas | Fuente de boletas con neto, IVA y total. |
Consultas
Section titled “Consultas”Documentos fuente
Section titled “Documentos fuente”getDetails usa OperacionesRepository.findDocuments para devolver documentos fuente normalizados. El filtro puede usar periodo, o bien periodo_desde y periodo_hasta.
| Tipo | Fuente | Normalizacion principal |
|---|---|---|
VENTA | fetchVentas | fecha_documento, documento_tipo, rut_emisor, razon_social_emisor. |
COMPRA | fetchCompras | monto_iva se expone desde monto_iva_recuperable. |
BOLETA | fetchBoletas | documento_tipo queda como Boleta y razon_social_emisor como Cliente Boleta. |
Estado de contabilizacion
Section titled “Estado de contabilizacion”estadoContabilizacion compara documentos fuente contra documentos con detalle para cada tipo: VENTA, COMPRA y BOLETA.
| Estado general | Condicion |
|---|---|
VACIO | No hay documentos fuente ni detalle generado. |
INCONSISTENTE | Hay faltantes o sobrantes entre origen y detalle. |
PENDIENTE | Hay documentos fuente, pero no hay detalle generado. |
PAGADO | Todos los documentos estan pagados. |
CONTABILIZADO | Todos los documentos estan contabilizados o pagados. |
VALIDADO | Todos los documentos tienen detalle en estado pendiente. |
PARCIAL | Existe mezcla de estados o avance incompleto. |
El resumen tambien expone total_origen, total_detalle, validados, contabilizados, pagados, anulados, faltantes, sobrantes, procesados y pendientes.
Estados Operacionales
Section titled “Estados Operacionales”| Operacion | Estado esperado | Resultado |
|---|---|---|
generate sin detalle previo | Sin filas del tipo y periodo | Inserta detalle con origen automatico. |
generate con detalle previo | forzar_reproceso = false | Rechaza para evitar duplicidad. |
generate con reproceso | forzar_reproceso = true | Borra detalle del tipo y periodo, luego regenera. |
contabilizar_ingresos | Lineas netas PENDIENTE de venta o boleta | Marca CONTABILIZADO y publica eventos. |
reversarContabilizacionIngresos | Lineas CONTABILIZADO o PAGADO con referencia EXISTENCIAS | Vuelve a PENDIENTE y limpia la referencia. |
Reglas de Diseño
Section titled “Reglas de Diseño”| Regla | Motivo |
|---|---|
| Resolver conceptos por codigo y no por ID salvo IVA no recuperable | Permite que el catalogo sea legible y configurable por tenant. |
Bloquear reprocesos sin forzar_reproceso | Evita duplicar detalle operacional para el mismo periodo. |
Usar año * 100 + mes para rangos de periodo en resumen y detalle | Permite comparar rangos mensuales sin depender de fechas del documento. |
| Mantener compras, ventas y boletas en una tabla de detalle comun | Simplifica reportes operacionales y conciliacion por periodo. |
| Generar eventos solo al contabilizar ingresos netos | Separa la preparacion del detalle de la señal contable hacia otros dominios. |
| Omitir otros impuestos sin concepto configurado | Evita fallar el procesamiento completo por configuraciones incompletas de conceptos opcionales. |
| Registrar redondeos solo hasta dos pesos | Distingue ajustes menores de diferencias materiales que requieren revision. |
Consideraciones Públicas
Section titled “Consideraciones Públicas”Esta documentacion nombra servicios, schemas, tablas, estados y conceptos porque forman parte del contrato tecnico del sistema. No publica rutas locales de desarrollo, credenciales, endpoints internos protegidos ni datos reales de empresas.
Cuando se requiera un ejemplo operativo, usar placeholders:
{ "tenantId": "$TENANT_ID", "tipo_documento": "COMPRA", "periodo_desde": "$PERIODO_DESDE", "periodo_hasta": "$PERIODO_HASTA"}