11 KiB
11 KiB
DOMAIN MODEL: Finance Context
Version: 1.0.0 Fecha: 2025-12-05 Modulos: MAE-014
Descripcion
El contexto de Finance gestiona toda la contabilidad y control financiero integrado con proyectos de construccion. Incluye libro mayor, cuentas por pagar/cobrar, flujo de efectivo y conciliacion bancaria.
Agregados
1. Accounting Aggregate
AccountingEntry (Aggregate Root)
|
+-- EntryLine (Entity)
| +-- Account (Reference)
| +-- CostCenter (Reference)
|
+-- EntryStatus (Value Object)
AccountingEntry (Root)
interface AccountingEntry {
id: UUID;
tenantId: UUID;
entryNumber: string;
entryType: EntryType;
entryDate: Date;
description: string;
reference?: string;
// Source
sourceModule?: string; // purchases, estimations, payroll
sourceId?: UUID;
sourceReference?: string;
// Project link
projectId?: UUID;
costCenterId?: UUID;
// Totals
totalDebit: Money;
totalCredit: Money;
isBalanced: boolean;
// Status
status: EntryStatus;
postedAt?: Timestamp;
postedBy?: UUID;
// Period
fiscalYear: number;
fiscalPeriod: number;
lines: EntryLine[];
}
enum EntryType {
INCOME = 'income',
EXPENSE = 'expense',
JOURNAL = 'journal',
TRANSFER = 'transfer',
ADJUSTMENT = 'adjustment',
OPENING = 'opening',
CLOSING = 'closing'
}
enum EntryStatus {
DRAFT = 'draft',
PENDING = 'pending',
POSTED = 'posted',
CANCELLED = 'cancelled'
}
EntryLine (Entity)
interface EntryLine {
id: UUID;
entryId: UUID;
lineNumber: number;
// Account
accountId: UUID;
accountCode: string;
description?: string;
// Amounts
debitAmount: Money;
creditAmount: Money;
// Attribution
costCenterId?: UUID;
projectId?: UUID;
// Partner
partnerId?: UUID;
partnerName?: string;
}
2. AccountsPayable Aggregate
AccountPayable (Aggregate Root)
|
+-- APPayment (Entity)
|
+-- PaymentSchedule (Value Object)
AccountPayable (Root)
interface AccountPayable {
id: UUID;
tenantId: UUID;
documentNumber: string;
documentType: DocumentType;
// Supplier
supplierId: UUID;
supplierName: string;
supplierRfc?: string;
// Source
purchaseOrderId?: UUID;
contractId?: UUID;
// Amounts
subtotal: Money;
taxAmount: Money;
retentionAmount: Money;
totalAmount: Money;
paidAmount: Money;
balance: Money; // totalAmount - paidAmount
// Dates
documentDate: Date;
dueDate: Date;
receivedDate?: Date;
// Project
projectId?: UUID;
costCenterId?: UUID;
// Status
status: PaymentStatus;
// Linked entry
accountingEntryId?: UUID;
payments: APPayment[];
}
enum PaymentStatus {
PENDING = 'pending',
PARTIAL = 'partial',
PAID = 'paid',
OVERDUE = 'overdue',
CANCELLED = 'cancelled'
}
APPayment (Entity)
interface APPayment {
id: UUID;
payableId: UUID;
paymentNumber: string;
paymentDate: Date;
amount: Money;
paymentMethod: PaymentMethod;
bankAccountId?: UUID;
reference?: string;
status: string;
accountingEntryId?: UUID;
}
enum PaymentMethod {
CASH = 'cash',
CHECK = 'check',
TRANSFER = 'transfer',
CARD = 'card',
DEPOSIT = 'deposit',
OTHER = 'other'
}
3. AccountsReceivable Aggregate
AccountReceivable (Aggregate Root)
|
+-- ARCollection (Entity)
|
+-- CollectionReminder (Value Object)
AccountReceivable (Root)
interface AccountReceivable {
id: UUID;
tenantId: UUID;
documentNumber: string;
documentType: string;
// Customer
customerId: UUID;
customerName: string;
customerRfc?: string;
// Source
estimationId?: UUID;
saleOrderId?: UUID;
contractId?: UUID;
// Amounts
subtotal: Money;
taxAmount: Money;
retentionAmount: Money;
totalAmount: Money;
collectedAmount: Money;
balance: Money; // totalAmount - collectedAmount
// Dates
documentDate: Date;
dueDate: Date;
// Project
projectId?: UUID;
// Status
status: PaymentStatus;
accountingEntryId?: UUID;
collections: ARCollection[];
}
ARCollection (Entity)
interface ARCollection {
id: UUID;
receivableId: UUID;
collectionNumber: string;
collectionDate: Date;
amount: Money;
paymentMethod: PaymentMethod;
bankAccountId?: UUID;
reference?: string;
status: string;
accountingEntryId?: UUID;
}
4. CashFlow Aggregate
CashFlowProjection (Aggregate Root)
|
+-- CashFlowItem (Entity)
|
+-- Variance (Value Object)
CashFlowProjection (Root)
interface CashFlowProjection {
id: UUID;
tenantId: UUID;
projectId?: UUID;
periodDate: Date;
periodType: PeriodType;
// Projected Income
projectedIncome: Money;
projectedCollections: Money;
// Projected Expenses
projectedExpenses: Money;
projectedPayments: Money;
// Actual
actualIncome: Money;
actualExpenses: Money;
// Balances
openingBalance: Money;
projectedClosing: Money;
actualClosing?: Money;
cashFlowType: CashFlowType;
items: CashFlowItem[];
}
enum PeriodType {
DAILY = 'daily',
WEEKLY = 'weekly',
MONTHLY = 'monthly'
}
enum CashFlowType {
OPERATING = 'operating',
INVESTING = 'investing',
FINANCING = 'financing'
}
CashFlowItem (Entity)
interface CashFlowItem {
id: UUID;
projectionId: UUID;
itemType: 'income' | 'expense';
category?: string;
description: string;
sourceType?: string; // estimation, purchase_order, contract, payroll
sourceId?: UUID;
projectedAmount: Money;
actualAmount?: Money;
expectedDate?: Date;
actualDate?: Date;
}
5. BankReconciliation Aggregate
BankAccount (Aggregate Root)
|
+-- BankMovement (Entity)
|
+-- BankReconciliation (Entity)
BankAccount (Root)
interface BankAccount {
id: UUID;
tenantId: UUID;
accountNumber: string;
clabe?: string;
name: string;
bankName: string;
bankCode?: string;
accountType?: string; // checking, savings, credit
currency: string;
currentBalance: Money;
availableBalance: Money;
lastReconciledBalance?: Money;
lastReconciledDate?: Date;
ledgerAccountId?: UUID;
projectId?: UUID;
isActive: boolean;
movements: BankMovement[];
}
BankMovement (Entity)
interface BankMovement {
id: UUID;
bankAccountId: UUID;
movementDate: Date;
valueDate?: Date;
reference?: string;
description?: string;
debitAmount: Money;
creditAmount: Money;
balanceAfter?: Money;
// Bank source
bankReference?: string;
importBatchId?: UUID;
// Reconciliation
reconciliationStatus: ReconciliationStatus;
reconciledWithId?: UUID;
reconciledWithType?: string; // ap_payment, ar_collection, entry_line
reconciledAt?: Timestamp;
reconciledBy?: UUID;
}
enum ReconciliationStatus {
PENDING = 'pending',
MATCHED = 'matched',
PARTIAL = 'partial',
UNMATCHED = 'unmatched'
}
Value Objects
Money
interface Money {
amount: number;
currency: string;
}
class Money {
static add(a: Money, b: Money): Money;
static subtract(a: Money, b: Money): Money;
static multiply(a: Money, factor: number): Money;
static isPositive(m: Money): boolean;
static isNegative(m: Money): boolean;
static equals(a: Money, b: Money): boolean;
}
AccountCode
interface AccountCode {
code: string;
type: AccountType;
nature: AccountNature;
level: number;
}
enum AccountType {
ASSET = 'asset',
LIABILITY = 'liability',
EQUITY = 'equity',
INCOME = 'income',
EXPENSE = 'expense'
}
enum AccountNature {
DEBIT = 'debit',
CREDIT = 'credit'
}
FiscalPeriod
interface FiscalPeriod {
year: number;
period: number; // 1-12 for monthly
isClosed: boolean;
}
Domain Events
Accounting Events
interface EntryPosted {
entryId: UUID;
entryNumber: string;
entryType: EntryType;
totalAmount: Money;
postedBy: UUID;
timestamp: Timestamp;
}
interface PeriodClosed {
fiscalYear: number;
fiscalPeriod: number;
closedBy: UUID;
timestamp: Timestamp;
}
AP/AR Events
interface PayableCreated {
payableId: UUID;
supplierId: UUID;
totalAmount: Money;
dueDate: Date;
timestamp: Timestamp;
}
interface PaymentMade {
paymentId: UUID;
payableId: UUID;
amount: Money;
remainingBalance: Money;
timestamp: Timestamp;
}
interface CollectionReceived {
collectionId: UUID;
receivableId: UUID;
amount: Money;
remainingBalance: Money;
timestamp: Timestamp;
}
Bank Events
interface MovementsImported {
bankAccountId: UUID;
batchId: UUID;
movementsCount: number;
totalDebits: Money;
totalCredits: Money;
timestamp: Timestamp;
}
interface ReconciliationCompleted {
reconciliationId: UUID;
bankAccountId: UUID;
periodEnd: Date;
isBalanced: boolean;
difference: Money;
timestamp: Timestamp;
}
Business Rules
Accounting Rules
- Toda poliza debe estar balanceada (debitos = creditos)
- No se puede modificar una poliza en status 'posted'
- Los periodos cerrados no permiten nuevas polizas
- Las cuentas de nivel 1 no permiten movimientos directos
AP/AR Rules
- El saldo no puede ser negativo
- Un pago no puede exceder el saldo pendiente
- Las CxP vencidas deben generar alertas automaticas
- Los pagos parciales cambian status a 'partial'
Cash Flow Rules
- La proyeccion debe coincidir con CxP/CxC pendientes
- Varianza > 10% requiere justificacion
- Proyecciones semanales son obligatorias
Bank Rules
- Solo movimientos conciliados afectan el libro
- La conciliacion requiere diferencia = 0
- Importacion de estados de cuenta es idempotente
Invariantes
Entry.totalDebit = Entry.totalCredit(siempre)AccountPayable.balance = totalAmount - paidAmountAccountReceivable.balance = totalAmount - collectedAmountBankAccount.currentBalance = SUM(movements.credits) - SUM(movements.debits)CashFlow.projectedClosing = openingBalance + income - expenses
Integraciones
Con Project Context
- Estimaciones aprobadas -> CxC
- Ordenes de compra -> CxP
- Costos de proyecto -> Polizas
Con Assets Context
- Depreciacion -> Polizas automaticas
- Mantenimiento -> CxP
Con Documents Context
- Facturas digitales almacenadas
- Polizas exportadas a PDF
Con ERP Externos
- SAP: Sincronizacion de polizas via RFC
- CONTPAQi: Export XML de polizas
- ASPEL: Export archivo plano
Referencias
Ultima actualizacion: 2025-12-05