erp-core-backend-v2/src/modules/cfdi/entities/cfdi-cancellation.entity.ts
Adrian Flores Cortes 6a12ff0844 [TASK-2026-02-05-EJECUCION-REMEDIATION-ERP-CORE] feat: Complete Sprint 0-4 data modeling remediation
Sprint 0: Updated inventories (MASTER/BACKEND/DATABASE) with verified baseline
Sprint 1: Fixed 8 P0 blockers - CFDI entities (schema cfdi→fiscal), auth base DDL,
  billing duplication (→operations), 5 project entities, PaymentInvoiceAllocation,
  core.companies DDL, recreate-database.sh array
Sprint 2: 4 new auth entities, session/role/permission DDL reconciliation,
  CFDI PAC+StampQueue, partner address+contact alignment
Sprint 3: CFDI service+controller+routes, mobile service+controller+routes,
  inventory extended DDL (7 tables)
Sprint 4: timestamp→timestamptz (40 files), field divergences, token/roles/permissions
  service alignment with new DDL-aligned entities

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 21:51:55 -06:00

142 lines
4.3 KiB
TypeScript

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<string, any> | 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;
}