/** * BankMovement Entity - Movimientos Bancarios * * Registro de movimientos importados de estados de cuenta. * * @module Finance */ import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn, Index, } from 'typeorm'; import { BankAccount } from './bank-account.entity'; export type MovementType = 'debit' | 'credit'; export type MovementStatus = 'pending' | 'matched' | 'reconciled' | 'unreconciled' | 'ignored'; export type MovementSource = 'manual' | 'import_file' | 'api' | 'system'; @Entity('bank_movements', { schema: 'finance' }) @Index(['tenantId', 'bankAccountId']) @Index(['tenantId', 'movementDate']) @Index(['tenantId', 'status']) export class BankMovement { @PrimaryGeneratedColumn('uuid') id!: string; @Column({ name: 'tenant_id', type: 'uuid' }) @Index() tenantId!: string; // Cuenta bancaria @Column({ name: 'bank_account_id', type: 'uuid' }) bankAccountId!: string; @ManyToOne(() => BankAccount) @JoinColumn({ name: 'bank_account_id' }) bankAccount?: BankAccount; // Referencia del movimiento @Column({ name: 'movement_reference', length: 100, nullable: true }) movementReference?: string; @Column({ name: 'bank_reference', length: 100, nullable: true }) bankReference?: string; // Tipo y fecha @Column({ name: 'movement_type', type: 'enum', enum: ['debit', 'credit'], enumName: 'bank_movement_type', }) movementType!: MovementType; @Column({ name: 'movement_date', type: 'date' }) movementDate!: Date; @Column({ name: 'value_date', type: 'date', nullable: true }) valueDate?: Date; // Descripción del banco @Column({ type: 'text' }) description!: string; @Column({ name: 'bank_description', type: 'text', nullable: true }) bankDescription?: string; // Monto @Column({ type: 'decimal', precision: 18, scale: 2, }) amount!: number; @Column({ length: 3, default: 'MXN' }) currency!: string; // Saldo después del movimiento @Column({ name: 'balance_after', type: 'decimal', precision: 18, scale: 2, nullable: true, }) balanceAfter?: number; // Estado de conciliación @Column({ type: 'enum', enum: ['pending', 'matched', 'reconciled', 'unreconciled', 'ignored'], enumName: 'bank_movement_status', default: 'pending', }) status!: MovementStatus; // Origen del movimiento @Column({ type: 'enum', enum: ['manual', 'import_file', 'api', 'system'], enumName: 'bank_movement_source', default: 'manual', }) source!: MovementSource; @Column({ name: 'import_batch_id', type: 'uuid', nullable: true }) importBatchId?: string; // Coincidencia automática @Column({ name: 'matched_payment_id', type: 'uuid', nullable: true }) matchedPaymentId?: string; @Column({ name: 'matched_collection_id', type: 'uuid', nullable: true }) matchedCollectionId?: string; @Column({ name: 'matched_entry_id', type: 'uuid', nullable: true }) matchedEntryId?: string; @Column({ name: 'match_confidence', type: 'decimal', precision: 5, scale: 2, nullable: true, }) matchConfidence?: number; // Conciliación @Column({ name: 'reconciliation_id', type: 'uuid', nullable: true }) reconciliationId?: string; @Column({ name: 'reconciled_at', type: 'timestamptz', nullable: true }) reconciledAt?: Date; @Column({ name: 'reconciled_by_id', type: 'uuid', nullable: true }) reconciledById?: string; // Categorización @Column({ name: 'category', length: 100, nullable: true }) category?: string; @Column({ name: 'subcategory', length: 100, nullable: true }) subcategory?: string; // Tercero identificado @Column({ name: 'partner_id', type: 'uuid', nullable: true }) partnerId?: string; @Column({ name: 'partner_name', length: 255, nullable: true }) partnerName?: string; // Flags @Column({ name: 'is_duplicate', type: 'boolean', default: false }) isDuplicate!: boolean; @Column({ name: 'requires_review', type: 'boolean', default: false }) requiresReview!: boolean; // Notas y metadatos @Column({ type: 'text', nullable: true }) notes?: string; @Column({ type: 'jsonb', nullable: true }) metadata?: Record; // Datos originales del banco @Column({ name: 'raw_data', type: 'jsonb', nullable: true }) rawData?: Record; // Auditoría @Column({ name: 'created_by', type: 'uuid', nullable: true }) createdBy?: string; @Column({ name: 'updated_by', type: 'uuid', nullable: true }) updatedBy?: string; @CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) createdAt!: Date; @UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' }) updatedAt!: Date; }