import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany, Index, } from 'typeorm'; import { CashCount } from './cash-count.entity'; export enum ClosingStatus { IN_PROGRESS = 'in_progress', PENDING_REVIEW = 'pending_review', APPROVED = 'approved', REJECTED = 'rejected', RECONCILED = 'reconciled', } export enum ClosingType { SHIFT = 'shift', DAILY = 'daily', WEEKLY = 'weekly', MONTHLY = 'monthly', } @Entity('cash_closings', { schema: 'retail' }) @Index(['tenantId', 'branchId', 'closingDate']) @Index(['tenantId', 'status']) @Index(['tenantId', 'sessionId']) export class CashClosing { @PrimaryGeneratedColumn('uuid') id: string; @Column({ name: 'tenant_id', type: 'uuid' }) @Index() tenantId: string; @Column({ name: 'branch_id', type: 'uuid' }) branchId: string; @Column({ name: 'register_id', type: 'uuid', nullable: true }) registerId: string; @Column({ name: 'session_id', type: 'uuid', nullable: true }) sessionId: string; @Column({ length: 30, unique: true }) number: string; @Column({ type: 'enum', enum: ClosingType, default: ClosingType.SHIFT, }) type: ClosingType; @Column({ type: 'enum', enum: ClosingStatus, default: ClosingStatus.IN_PROGRESS, }) status: ClosingStatus; @Column({ name: 'closing_date', type: 'date' }) closingDate: Date; @Column({ name: 'period_start', type: 'timestamp with time zone' }) periodStart: Date; @Column({ name: 'period_end', type: 'timestamp with time zone' }) periodEnd: Date; // Opening balance @Column({ name: 'opening_balance', type: 'decimal', precision: 15, scale: 2, default: 0 }) openingBalance: number; // Expected amounts by payment method @Column({ name: 'expected_cash', type: 'decimal', precision: 15, scale: 2, default: 0 }) expectedCash: number; @Column({ name: 'expected_card', type: 'decimal', precision: 15, scale: 2, default: 0 }) expectedCard: number; @Column({ name: 'expected_transfer', type: 'decimal', precision: 15, scale: 2, default: 0 }) expectedTransfer: number; @Column({ name: 'expected_other', type: 'decimal', precision: 15, scale: 2, default: 0 }) expectedOther: number; @Column({ name: 'expected_total', type: 'decimal', precision: 15, scale: 2, default: 0 }) expectedTotal: number; // Counted amounts @Column({ name: 'counted_cash', type: 'decimal', precision: 15, scale: 2, nullable: true }) countedCash: number; @Column({ name: 'counted_card', type: 'decimal', precision: 15, scale: 2, nullable: true }) countedCard: number; @Column({ name: 'counted_transfer', type: 'decimal', precision: 15, scale: 2, nullable: true }) countedTransfer: number; @Column({ name: 'counted_other', type: 'decimal', precision: 15, scale: 2, nullable: true }) countedOther: number; @Column({ name: 'counted_total', type: 'decimal', precision: 15, scale: 2, nullable: true }) countedTotal: number; // Differences @Column({ name: 'cash_difference', type: 'decimal', precision: 15, scale: 2, nullable: true }) cashDifference: number; @Column({ name: 'card_difference', type: 'decimal', precision: 15, scale: 2, nullable: true }) cardDifference: number; @Column({ name: 'total_difference', type: 'decimal', precision: 15, scale: 2, nullable: true }) totalDifference: number; // Transaction summary @Column({ name: 'total_sales', type: 'decimal', precision: 15, scale: 2, default: 0 }) totalSales: number; @Column({ name: 'total_refunds', type: 'decimal', precision: 15, scale: 2, default: 0 }) totalRefunds: number; @Column({ name: 'total_discounts', type: 'decimal', precision: 15, scale: 2, default: 0 }) totalDiscounts: number; @Column({ name: 'net_sales', type: 'decimal', precision: 15, scale: 2, default: 0 }) netSales: number; @Column({ name: 'orders_count', type: 'int', default: 0 }) ordersCount: number; @Column({ name: 'refunds_count', type: 'int', default: 0 }) refundsCount: number; @Column({ name: 'voided_count', type: 'int', default: 0 }) voidedCount: number; // Cash movements @Column({ name: 'cash_in_total', type: 'decimal', precision: 15, scale: 2, default: 0 }) cashInTotal: number; @Column({ name: 'cash_out_total', type: 'decimal', precision: 15, scale: 2, default: 0 }) cashOutTotal: number; // Deposit info @Column({ name: 'deposit_amount', type: 'decimal', precision: 15, scale: 2, nullable: true }) depositAmount: number; @Column({ name: 'deposit_reference', length: 100, nullable: true }) depositReference: string; @Column({ name: 'deposit_date', type: 'date', nullable: true }) depositDate: Date; // User info @Column({ name: 'closed_by', type: 'uuid' }) closedBy: string; @Column({ name: 'reviewed_by', type: 'uuid', nullable: true }) reviewedBy: string; @Column({ name: 'reviewed_at', type: 'timestamp with time zone', nullable: true }) reviewedAt: Date; @Column({ name: 'approved_by', type: 'uuid', nullable: true }) approvedBy: string; @Column({ name: 'approved_at', type: 'timestamp with time zone', nullable: true }) approvedAt: Date; // Notes @Column({ name: 'closing_notes', type: 'text', nullable: true }) closingNotes: string; @Column({ name: 'review_notes', type: 'text', nullable: true }) reviewNotes: string; // Detailed breakdown by payment method @Column({ name: 'payment_breakdown', type: 'jsonb', nullable: true }) paymentBreakdown: { method: string; expected: number; counted: number; difference: number; transactionCount: number; }[]; // Metadata @Column({ type: 'jsonb', nullable: true }) metadata: Record; @CreateDateColumn({ name: 'created_at' }) createdAt: Date; @UpdateDateColumn({ name: 'updated_at' }) updatedAt: Date; // Relations @OneToMany(() => CashCount, (count) => count.closing) cashCounts: CashCount[]; }