- Create 11 entities matching DDL: - DocumentCategory: Hierarchical categories - Document: Main document registry - DocumentVersion: Version control with files - DocumentPermission: Granular permissions - ApprovalWorkflow: Workflow definitions - ApprovalInstance: Active workflow instances - ApprovalStep: Steps per instance - ApprovalActionEntity: Actions taken - Annotation: Comments and markups - AccessLog: Access history - DocumentShare: External sharing links - Create DocumentService with full CRUD - Create DocumentVersionService for version management - All entities follow ERP-Construction patterns Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
235 lines
6.1 KiB
TypeScript
235 lines
6.1 KiB
TypeScript
/**
|
|
* Document Entity - Registro Principal de Documentos
|
|
* Sistema de gestion documental.
|
|
*
|
|
* @module Documents (MAE-016)
|
|
*/
|
|
|
|
import {
|
|
Entity,
|
|
PrimaryGeneratedColumn,
|
|
Column,
|
|
CreateDateColumn,
|
|
UpdateDateColumn,
|
|
ManyToOne,
|
|
OneToMany,
|
|
JoinColumn,
|
|
Index,
|
|
} from 'typeorm';
|
|
import { DocumentCategory, AccessLevel } from './document-category.entity';
|
|
import { DocumentVersion } from './document-version.entity';
|
|
import { Annotation } from './annotation.entity';
|
|
|
|
export type DocumentType =
|
|
| 'plan'
|
|
| 'specification'
|
|
| 'contract'
|
|
| 'permit'
|
|
| 'report'
|
|
| 'photograph'
|
|
| 'drawing'
|
|
| 'manual'
|
|
| 'procedure'
|
|
| 'form'
|
|
| 'correspondence'
|
|
| 'invoice'
|
|
| 'estimate'
|
|
| 'other';
|
|
|
|
export type DocumentStatus =
|
|
| 'draft'
|
|
| 'pending_review'
|
|
| 'in_review'
|
|
| 'approved'
|
|
| 'rejected'
|
|
| 'obsolete'
|
|
| 'archived';
|
|
|
|
@Entity('documents', { schema: 'documents' })
|
|
@Index(['tenantId', 'documentCode'], { unique: true })
|
|
@Index(['tenantId', 'categoryId'])
|
|
@Index(['tenantId', 'documentType'])
|
|
@Index(['tenantId', 'status'])
|
|
@Index(['tenantId', 'projectId'])
|
|
export class Document {
|
|
@PrimaryGeneratedColumn('uuid')
|
|
id!: string;
|
|
|
|
@Column({ name: 'tenant_id', type: 'uuid' })
|
|
@Index()
|
|
tenantId!: string;
|
|
|
|
// Identificacion
|
|
@Column({ name: 'document_code', length: 100 })
|
|
documentCode!: string;
|
|
|
|
@Column({ length: 500 })
|
|
title!: string;
|
|
|
|
@Column({ type: 'text', nullable: true })
|
|
description?: string;
|
|
|
|
// Clasificacion
|
|
@Column({ name: 'category_id', type: 'uuid', nullable: true })
|
|
categoryId?: string;
|
|
|
|
@ManyToOne(() => DocumentCategory, { nullable: true })
|
|
@JoinColumn({ name: 'category_id' })
|
|
category?: DocumentCategory;
|
|
|
|
@Column({
|
|
name: 'document_type',
|
|
type: 'enum',
|
|
enum: ['plan', 'specification', 'contract', 'permit', 'report', 'photograph', 'drawing', 'manual', 'procedure', 'form', 'correspondence', 'invoice', 'estimate', 'other'],
|
|
enumName: 'document_type',
|
|
})
|
|
documentType!: DocumentType;
|
|
|
|
@Column({
|
|
type: 'enum',
|
|
enum: ['draft', 'pending_review', 'in_review', 'approved', 'rejected', 'obsolete', 'archived'],
|
|
enumName: 'document_status',
|
|
default: 'draft',
|
|
})
|
|
status!: DocumentStatus;
|
|
|
|
@Column({
|
|
name: 'access_level',
|
|
type: 'enum',
|
|
enum: ['public', 'internal', 'confidential', 'restricted'],
|
|
enumName: 'access_level',
|
|
default: 'internal',
|
|
})
|
|
accessLevel!: AccessLevel;
|
|
|
|
// Version actual
|
|
@Column({ name: 'current_version_id', type: 'uuid', nullable: true })
|
|
currentVersionId?: string;
|
|
|
|
@Column({ name: 'current_version_number', length: 20, default: '1.0' })
|
|
currentVersionNumber!: string;
|
|
|
|
// Proyecto/Contexto
|
|
@Column({ name: 'project_id', type: 'uuid', nullable: true })
|
|
projectId?: string;
|
|
|
|
@Column({ name: 'project_code', length: 50, nullable: true })
|
|
projectCode?: string;
|
|
|
|
@Column({ name: 'project_name', length: 255, nullable: true })
|
|
projectName?: string;
|
|
|
|
// Metadatos del documento
|
|
@Column({ length: 255, nullable: true })
|
|
author?: string;
|
|
|
|
@Column({ type: 'varchar', array: true, nullable: true })
|
|
keywords?: string[];
|
|
|
|
@Column({ type: 'varchar', array: true, nullable: true })
|
|
tags?: string[];
|
|
|
|
// Fechas importantes
|
|
@Column({ name: 'document_date', type: 'date', nullable: true })
|
|
documentDate?: Date;
|
|
|
|
@Column({ name: 'effective_date', type: 'date', nullable: true })
|
|
effectiveDate?: Date;
|
|
|
|
@Column({ name: 'expiry_date', type: 'date', nullable: true })
|
|
expiryDate?: Date;
|
|
|
|
@Column({ name: 'review_date', type: 'date', nullable: true })
|
|
reviewDate?: Date;
|
|
|
|
// Origen
|
|
@Column({ length: 100, nullable: true })
|
|
source?: string;
|
|
|
|
@Column({ name: 'external_reference', length: 255, nullable: true })
|
|
externalReference?: string;
|
|
|
|
@Column({ name: 'original_filename', length: 500, nullable: true })
|
|
originalFilename?: string;
|
|
|
|
// Relaciones de documentos
|
|
@Column({ name: 'parent_document_id', type: 'uuid', nullable: true })
|
|
parentDocumentId?: string;
|
|
|
|
@ManyToOne(() => Document, { nullable: true })
|
|
@JoinColumn({ name: 'parent_document_id' })
|
|
parentDocument?: Document;
|
|
|
|
@Column({ name: 'related_documents', type: 'uuid', array: true, nullable: true })
|
|
relatedDocuments?: string[];
|
|
|
|
// Flujo de aprobacion
|
|
@Column({ name: 'requires_approval', type: 'boolean', default: false })
|
|
requiresApproval!: boolean;
|
|
|
|
@Column({ name: 'current_workflow_id', type: 'uuid', nullable: true })
|
|
currentWorkflowId?: string;
|
|
|
|
@Column({ name: 'approved_by_id', type: 'uuid', nullable: true })
|
|
approvedById?: string;
|
|
|
|
@Column({ name: 'approved_at', type: 'timestamptz', nullable: true })
|
|
approvedAt?: Date;
|
|
|
|
// Estadisticas
|
|
@Column({ name: 'view_count', type: 'int', default: 0 })
|
|
viewCount!: number;
|
|
|
|
@Column({ name: 'download_count', type: 'int', default: 0 })
|
|
downloadCount!: number;
|
|
|
|
@Column({ name: 'last_accessed_at', type: 'timestamptz', nullable: true })
|
|
lastAccessedAt?: Date;
|
|
|
|
// Flags
|
|
@Column({ name: 'is_template', type: 'boolean', default: false })
|
|
isTemplate!: boolean;
|
|
|
|
@Column({ name: 'is_locked', type: 'boolean', default: false })
|
|
isLocked!: boolean;
|
|
|
|
@Column({ name: 'locked_by_id', type: 'uuid', nullable: true })
|
|
lockedById?: string;
|
|
|
|
@Column({ name: 'locked_at', type: 'timestamptz', nullable: true })
|
|
lockedAt?: Date;
|
|
|
|
// Notas y metadatos
|
|
@Column({ type: 'text', nullable: true })
|
|
notes?: string;
|
|
|
|
@Column({ name: 'custom_fields', type: 'jsonb', nullable: true })
|
|
customFields?: Record<string, any>;
|
|
|
|
@Column({ type: 'jsonb', nullable: true })
|
|
metadata?: Record<string, any>;
|
|
|
|
// Relaciones
|
|
@OneToMany(() => DocumentVersion, (version) => version.document)
|
|
versions?: DocumentVersion[];
|
|
|
|
@OneToMany(() => Annotation, (annotation) => annotation.document)
|
|
annotations?: Annotation[];
|
|
|
|
// Auditoria
|
|
@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;
|
|
|
|
@Column({ name: 'deleted_at', type: 'timestamptz', nullable: true })
|
|
deletedAt?: Date;
|
|
}
|