Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DevCarlosRodriguez/Documentacion-Arccnova-2.0/llms.txt

Use this file to discover all available pages before exploring further.

El módulo Collections es la traducción operativa del ciclo financiero: ejecuta la cobranza de las ventas, registra cada pago (en caja o en línea), genera las cuotas conforme se cobran, aplica el reparto interés/capital definido por Financing, calcula y cobra la mora por atraso, maneja pagos parciales y cuotas equivalentes, y liquida la venta cuando todos los saldos llegan a cero. Es la interfaz entre el dinero real que entra y el estado contable de cada plan de Sales.
Collections ejecuta el cobro; Financing calcula la matemática. Estos dos módulos son independientes. Los webhooks de pago en línea (Stripe) desembocan en el mismo motor de cuotas que el cobro en caja — las reglas son idénticas en ambos canales.

Modelo de dominio

EntidadSignificadoCampos clave
Collection (Cobro)El acto de cobrar: total esperado y total recibido.Folio, FinancingTypeId, SaleId, ClientId, AmountReceived, TotalToPay, Change, Arrears_Amount, CollectionStatusId, IsMultiplePayment, PaymentDate
MultipleInstallments (Cuota)La cuota generada de un plan.InstallmentNumber, SaleId, FinancingTypeId, PaymentAmount, IsPaymentCompleted, LastRemainingAmout, InterestPayment, PricipalPayment, ExtraPrincipalPayment, MissingPayment, RealInterestPayment, RealPrincipalPayment, LastRemainingInterest, BalanceWithInterest, NextPaymentDate, GracePeriodDueDate
CollectionInstallmentTabla puente cobro ↔ cuota: cuánto de un cobro fue a una cuota.Amount, InterestPaid, PrincipalPaid, ExtraPrincipal
ConceptCollectionConceptos cobrados junto a la cuota; la mora es un concepto.ConceptId, Amount, IsCharged, EquivelentCharge, IsDelinquentPayer
MultiplePaymentUn cobro puede cubrirse con varias formas de pago.Método, monto, tipo de cambio, referencia
VoucherImageComprobantes adjuntos del cobro.Referencia al almacenamiento en nube (Files)
Lectura del modelo: un Collection agrupa las formas de pago (MultiplePayment) y los conceptos (ConceptCollection, incluida la mora). La cuota (MultipleInstallments) vive por plan de la venta. La tabla puente CollectionInstallment registra exactamente cuánto de ese cobro fue a interés, a capital y a abono extra de cada cuota.

Los 10 invariantes del motor

Estas reglas son inviolables y se validan en código en cada operación de cobranza:
#Invariante
1Las cuotas nunca se crean anticipadas. La cuota N nace al cobrarse; la N+1 se genera cuando se cobra la N. Las 81 cuotas de un plan no existen hasta pagarse.
2Sin brincos. Si la cuota actual no está liquidada (incluida su mora), no se avanza a la siguiente.
3Solo se puede eliminar la última cuota generada. Nunca una cuota que tenga cuotas posteriores.
4De una cuota pagada solo se puede actualizar el método de pago, validando que no exista cuota posterior.
5Los comprobantes adjuntos sí se pueden actualizar (subir o eliminar) en cualquier momento.
6No se cobra una venta liquidada. IsSettled = true o estado Liquidado = error.
7No se aplica abono extra a capital al cubrir dos cuotas en el mismo cobro. El extra solo aplica cuando InstallmentEquivalent = 1.
8No se pagan parcialidades en un cobro de cuota equivalente a dos. Si InstallmentEquivalent > 1 y el monto recibido es menor al total, el sistema devuelve error.
9Pago incompleto = parcialidad. La cuota queda IsPaymentCompleted = false y no avanza hasta cubrir el faltante más su mora.
10Solo se cobra sobre ventas en estado Conforme.
La regla #2 (sin brincos) implica que si un cliente tiene mora pendiente sobre su cuota actual, esa mora debe cobrarse antes de registrar cualquier nuevo pago a capital. El sistema bloquea el avance automáticamente.

Flujos

Calcular el próximo cobro — ValidateNextCollection

Antes de registrar un pago, el sistema determina qué cobrar:
1

Cargar el plan

Se identifica el plan por venta y tipo de financiamiento. Si IsSettled = true, error: la venta ya está liquidada.
2

Determinar la cuota actual

  • No existe ninguna cuota → cuota número 1; fecha base = PaymentFirstDate (o su gracia si aplica).
  • Existe cuota completa → próxima es N+1; monto = saldo + interés remanente, con tope al PaymentByPeriod (así la última cuota cobra el saldo exacto sin superar el importe periódico).
  • Existe cuota incompleta → sigue en N; monto = MissingPayment.
3

Calcular mora (si aplica)

Si la fecha actual supera el último día permitido para pagar y el plan tiene porcentaje de mora > 0:
  1. Se calculan los periodos vencidos (sección Mora más abajo).
  2. Se restan los periodos ya cobrados (IsDelinquentPayer / EquivelentCharge) para no duplicar.
  3. Se agrega el concepto de mora al cobro propuesto.
4

Salida

Número de cuota, monto a pagar, mora a cobrar (si hay) y fechas de vencimiento.

Registrar un cobro — SaveCollectionBySale

1

Inicio de transacción

Todo ocurre dentro de una sola transacción de base de datos.
2

Folio de recibo

Si el cobro es identificado, se incrementa el correlativo del tipo de recibo (ReceiptType.Correlative++). Este folio es único por proyecto y tipo de recibo.
3

Insertar el cobro

Se graba el Collection con TotalToPay, AmountReceived, cambio (Change) y mora (Arrears_Amount).
4

Procesar formas de pago y conceptos

Se insertan o actualizan los registros de MultiplePayment y ConceptCollection (incluida la mora si corresponde).Ajuste del monto al financiamiento:
PaymentByPeriod_efectivo = AmountReceived − total_de_conceptos
Si ApplyExcessAsChange:
    PaymentByPeriod_efectivo −= ChangeAmount
5

Procesar la cuota por cada venta

  • Si InstallmentEquivalent > 1 y AmountReceived < TotalToPay → error (invariante #8).
  • Si existe cuota N incompleta → UpdateInstallmentsPartialPayment (pago parcial).
  • Si no existe cuota N → SaveInstallmentsPayment (genera nueva cuota).
6

Subir comprobantes

Los archivos adjuntos se suben al servicio de almacenamiento; en BD solo se guarda la referencia.
7

Commit y respuesta

La transacción se confirma. Se devuelve el CollectionId al front.

Pago parcial — UpdateInstallmentsPartialPayment

Se invoca cuando ya existe una cuota N incompleta y llega un pago adicional sobre ella:
  1. Solo sobre ventas Conforme.
  2. Si hay extra a capital y InstallmentEquivalent = 1: el extra reduce el saldo.
  3. Se acumula: PaymentAmount += PaymentByPeriod.
  4. MissingPayment = PaymentByPeriod_plan − PaymentAmount.
  5. Si MissingPayment = 0: la cuota se completa, NextPaymentDate avanza a la cuota N+1 y se calcula GracePeriodDueDate.
  6. Si MissingPayment > 0: la cuota sigue incompleta y no avanza.
  7. Se reparte interés/capital y, si el saldo llega a ≤ 0, se liquida el plan y se recalcula el estado de la venta (SettleSale).

Generar cuota N — SaveInstallmentsPayment

Validaciones previas:
  • Saldo > 0.
  • El número de cuota es exactamente el siguiente consecutivo.
  • La cuota N no existe ya.
  • La venta está en estado Conforme.
Para cada cuota equivalente (1 o 2):
EscenarioComportamiento
Pago completo (pago ≥ PaymentByPeriod)IsPaymentCompleted = true; se calcula NextPaymentDate (formula de Financing §4.4) y GracePeriodDueDate; el saldo nuevo se persiste.
Pago parcial (pago < PaymentByPeriod)Si pago < InterestPayment: todo va a interés, el capital queda en 0 y el saldo no cambia. Si pago ≥ InterestPayment: el resto va a capital. NextPaymentDate no avanza; la gracia queda la del plan.
Extra a capital (solo si Equivalent = 1)Si extra > saldo restante → error. El extra reduce el saldo y eventualmente el número de cuotas.
Saldo ≤ 0NextPaymentDate = null, GracePeriodDueDate = null, el plan se marca IsSettled = true. Se llama a SettleSale: si todos los planes están liquidados, la venta pasa a estado Liquidado y el asesor puede descargar la hoja de liquidación.
Orden de persistencia:
1. INSERT MultipleInstallments          (la cuota)
2. INSERT CollectionInstallment         (relación cobro ↔ cuota)
3. SettleSale                           (recalcular estado de venta)

Mora

El cálculo de mora sigue estas reglas canónicas (C23 segunda ronda):
1

Condición de mora

La mora se activa cuando hoy > fecha_límite. La fecha límite es la fecha de vencimiento de la cuota más los días de gracia (si el plan tiene GracePeriod > 0). Sin gracia, la fecha límite es la de vencimiento normal.
2

Penalidad por periodo

Penalidad = PaymentByPeriod × (PorcentajeDeMora / 100)
El porcentaje de mora se toma del plan de la venta (default = tasa de incumplimiento del proyecto).
3

Periodos vencidos

Al pasar la fecha límite hay 1 periodo vencido. Cada periodo completo adicional de la modalidad suma otro. Ejemplo: cuota vence el 11/05, hoy es 11/06 → 1 periodo (la siguiente cuota vence justo el 11/06); al pasar esa fecha → 2 periodos.
4

Cargo de mora

CargoMora = Penalidad × PeriodosVencidos − PeriodosYaCobrados
Los periodos ya cobrados se registran en ConceptCollection con IsDelinquentPayer = true y EquivelentCharge = n_periodos_cobrados, evitando duplicar mora.
5

Pagos parciales y mora

El cobro cubre primero la mora y el resto va a la cuota. Si transcurre otro periodo con la cuota incompleta, la nueva mora se calcula sobre el restante de la cuota. Ejemplo de la fuente:
Cuota = 3,000 | Mora 10% → cargo mora = 300
Pago  = 2,000 → 300 a mora, 1,700 a cuota; queda 1,300 pendiente

Pasa otro periodo → nueva mora = 1,300 × 10% = 130
Pago  = 1,430 → 130 a mora, 1,300 a cuota; cuota liquidada

La siguiente cuota, ya vencida, genera su propia mora

Días de gracia y festivos

Los días de gracia se cuentan en días hábiles de la inmobiliaria: lunes a sábado, saltando domingos y festivos (catálogo de días festivos del tenant). El sábado sí cuenta como día hábil. Ejemplo cerrado de la fuente:
Cuota vence sábado 15 → 3 días de gracia → lunes 17 es festivo →
Se saltan: domingo 16 y lunes 17 → cuentan: 18, 19, 20
Último día para pagar sin mora: día 20. La mora corre desde el día 21.

Cobros no identificados

Un cobro no identificado ocurre cuando llega un depósito (por ejemplo por WhatsApp) y la inmobiliaria no sabe a qué cliente corresponde:
  1. El pago se registra como cobro no identificado y aparece en la alerta de pendientes.
  2. La persona responsable lo identifica: selecciona el tipo de financiamiento, busca al cliente y distribuye el monto entre sus ventas/cuotas.
  3. El monto distribuido debe ser exactamente igual al monto recibido (faltante = 0).
  4. Al confirmar, el cobro cambia a estado Identificado y queda ligado a las cuotas, igual que si se hubiera capturado por el flujo normal.
El contador y la lista de cobros no identificados se actualizan en tiempo real mediante SSE sin recargar la página (decisión 19, RT-34). Este evento genera notificación por sistema y por correo electrónico (T05).

Eliminación autorizada de cobros

La eliminación de cobros es una acción protegida (C30, RT-09 a RT-11):
  • Requiere el permiso ELIMINAR COBROS más la contraseña de acción, o ser CEO / Admin.
  • Se debe ingresar un motivo de eliminación.
EscenarioComportamiento
Eliminar el pago de una cuotaSolo si no hay cuotas posteriores. Soft-delete de la cuota y la relación CollectionInstallment; se eliminan las formas de pago del cobro.
Eliminar un cobro completoPor cada cuota relacionada, valida que no exista N+1. Si la cuota había liquidado el plan, revierte la liquidación (la venta vuelve a Conforme). Si la cuota tiene más de un cobro, revierte los montos parciales y la cuota sigue viva. Si no, soft-delete de la cuota. Luego soft-delete de conceptos, pagos y cobro.

Liquidación

Cuando SettleSale detecta que todos los planes de la venta tienen IsSettled = true y LastRemainingAmout ≤ 0:
  1. La venta transiciona automáticamente a estado Liquidado.
  2. El asesor puede descargar la hoja de liquidación (documento legal generado en back, RT-30).
  3. A partir de este punto, Collections rechaza nuevos cobros sobre esa venta (invariante #6).

Matriz de permisos

RecursoAcciones estándarAcciones protegidas
CobrosLeer, Crear, ActualizarEliminar cobros (contraseña de acción)
CréditosLeer, Cambiar fecha de pago
Conceptos de moraEditar, Eliminar (C33)
Los permisos de cobros están en el grupo G. Comercial. Las acciones de eliminar cobros y editar/eliminar conceptos de mora requieren el overlay de permisos protegidos con contraseña de acción.

Puntos abiertos

  1. Tabla de cuotas materializada vs. bajo demanda — El v1 genera cada cuota al cobrarla. El v2 puede materializar la tabla completa al crear el plan. Las reglas de este módulo aplican igual en ambos diseños. Decide el arquitecto (Flag 2 del cierre).
  2. Cobro no identificado sin reclamar — La fuente indica que el pago “queda en la alerta” sin caducidad definida. Política de cierre o archivo de pagos huérfanos pendiente de definición (C29).
  3. Rescisión de contrato por impago — Es una decisión administrativa de la inmobiliaria, fuera del sistema. El sistema solo aporta la carta de cobranza extrajudicial (módulo Reports, C47).
  4. Autorización de EDITAR_CONCEPTO_POR_MORA / ELIMINAR_CONCEPTO_POR_MORA — Los casos exactos en que se solicita el código de autorización para operar sobre conceptos de mora están pendientes de confirmar (C33).

Build docs developers (and LLMs) love