import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, Index, ManyToOne, JoinColumn, } from 'typeorm'; import { CancellationReason } from '../enums/cancellation-reason.enum.js'; import { CfdiInvoice } from './cfdi-invoice.entity.js'; /** * Cancellation request status aligned with DDL fiscal.cancellation_request_status */ export enum CancellationRequestStatus { PENDING = 'pending', SUBMITTED = 'submitted', ACCEPTED = 'accepted', REJECTED = 'rejected', IN_PROCESS = 'in_process', EXPIRED = 'expired', CANCELLED = 'cancelled', ERROR = 'error', } /** * CFDI Cancellation Request Entity * Aligned with DDL: fiscal.cfdi_cancellation_requests */ @Entity({ schema: 'fiscal', name: 'cfdi_cancellation_requests' }) @Index('idx_cfdi_cancellation_requests_tenant', ['tenantId']) @Index('idx_cfdi_cancellation_requests_cfdi', ['cfdiInvoiceId']) @Index('idx_cfdi_cancellation_requests_uuid', ['cfdiUuid']) @Index('idx_cfdi_cancellation_requests_status', ['status']) @Index('idx_cfdi_cancellation_requests_created', ['createdAt']) export class CfdiCancellation { @PrimaryGeneratedColumn('uuid') id: string; @Column({ type: 'uuid', nullable: false, name: 'tenant_id' }) tenantId: string; @Column({ type: 'uuid', nullable: false, name: 'cfdi_invoice_id' }) cfdiInvoiceId: string; @Column({ type: 'varchar', length: 36, nullable: false, name: 'cfdi_uuid' }) cfdiUuid: string; @Column({ type: 'enum', enum: CancellationReason, nullable: false, name: 'cancellation_reason', }) cancellationReason: CancellationReason; @Column({ type: 'varchar', length: 36, nullable: true, name: 'substitute_uuid' }) substituteUuid: string | null; @Column({ type: 'uuid', nullable: true, name: 'substitute_cfdi_id' }) substituteCfdiId: string | null; @Column({ type: 'enum', enum: CancellationRequestStatus, default: CancellationRequestStatus.PENDING, nullable: false, }) status: CancellationRequestStatus; @Column({ type: 'text', nullable: true, name: 'sat_ack_xml' }) satAckXml: string | null; @Column({ type: 'timestamptz', nullable: true, name: 'completed_at' }) completedAt: Date | null; @Column({ type: 'text', nullable: true, name: 'error_message' }) errorMessage: string | null; @Column({ type: 'varchar', length: 50, nullable: true, name: 'error_code' }) errorCode: string | null; @Column({ type: 'jsonb', nullable: true, name: 'error_details' }) errorDetails: Record | null; @Column({ type: 'varchar', length: 10, nullable: true, name: 'sat_response_code' }) satResponseCode: string | null; @Column({ type: 'text', nullable: true, name: 'sat_response_message' }) satResponseMessage: string | null; @Column({ type: 'text', nullable: true, name: 'receiver_response_reason' }) receiverResponseReason: string | null; @Column({ type: 'varchar', length: 20, nullable: true, name: 'receiver_response' }) receiverResponse: string | null; @Column({ type: 'timestamptz', nullable: true, name: 'receiver_response_at' }) receiverResponseAt: Date | null; @Column({ type: 'timestamptz', nullable: true, name: 'expires_at' }) expiresAt: Date | null; @Column({ type: 'timestamptz', nullable: true, name: 'requested_at' }) requestedAt: Date | null; @Column({ type: 'timestamptz', nullable: true, name: 'submitted_at' }) submittedAt: Date | null; @Column({ type: 'timestamptz', nullable: true, name: 'response_at' }) responseAt: Date | null; @Column({ type: 'text', nullable: true, name: 'reason_notes' }) reasonNotes: string | null; @Column({ type: 'text', nullable: true, name: 'internal_notes' }) internalNotes: string | null; @Column({ type: 'integer', default: 0, nullable: false, name: 'retry_count' }) retryCount: number; // Relation @ManyToOne(() => CfdiInvoice, (invoice) => invoice.cancellations) @JoinColumn({ name: 'cfdi_invoice_id' }) cfdiInvoice: CfdiInvoice; // Audit fields @CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) createdAt: Date; @Column({ type: 'uuid', nullable: true, name: 'created_by' }) createdBy: string | null; @UpdateDateColumn({ name: 'updated_at', type: 'timestamptz', nullable: true }) updatedAt: Date | null; @Column({ type: 'uuid', nullable: true, name: 'updated_by' }) updatedBy: string | null; }