190 lines
4.7 KiB
TypeScript
190 lines
4.7 KiB
TypeScript
/**
|
|
* 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<string, any>;
|
|
|
|
// Datos originales del banco
|
|
@Column({ name: 'raw_data', type: 'jsonb', nullable: true })
|
|
rawData?: Record<string, any>;
|
|
|
|
// 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;
|
|
}
|