[EPIC-001-T1.4] feat: Add @ManyToOne relations for FK constraints

Added 17 TypeORM relations to align entities with conditional FK constraints:
- Inventory: AlmacenProyecto, RequisicionObra, RequisicionLinea, ConsumoObra
- Purchase: SupplierConstruction, ComparativoCotizaciones, ComparativoProveedor, ComparativoProducto
- HSE: EppInventario, EppMovimiento
- Documents: AccessLog, DocumentShare

Relations to Warehouse, Partner, Product, Uom, AlmacenTemporal, User.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Adrian Flores Cortes 2026-02-04 00:10:31 -06:00
parent 3722355360
commit 1ad1604fa9
12 changed files with 90 additions and 0 deletions

View File

@ -15,6 +15,7 @@ import {
} from 'typeorm';
import { Document } from './document.entity';
import { DocumentVersion } from './document-version.entity';
import { User } from '../../core/entities/user.entity';
@Entity('access_logs', { schema: 'documents' })
@Index(['tenantId'])
@ -73,4 +74,9 @@ export class AccessLog {
// Timestamp
@Column({ name: 'accessed_at', type: 'timestamptz', default: () => 'NOW()' })
accessedAt!: Date;
// FK a auth.users (ERP-Core) - usuario que accedió
@ManyToOne(() => User, { nullable: true })
@JoinColumn({ name: 'user_id' })
user?: User;
}

View File

@ -16,6 +16,7 @@ import {
} from 'typeorm';
import { Document } from './document.entity';
import { DocumentVersion } from './document-version.entity';
import { User } from '../../core/entities/user.entity';
@Entity('document_shares', { schema: 'documents' })
@Index(['tenantId'])
@ -107,4 +108,14 @@ export class DocumentShare {
@Column({ name: 'last_accessed_at', type: 'timestamptz', nullable: true })
lastAccessedAt?: Date;
// FK a auth.users (ERP-Core) - usuario que compartió
@ManyToOne(() => User, { nullable: false })
@JoinColumn({ name: 'shared_by_id' })
sharedBy!: User;
// FK a auth.users (ERP-Core) - usuario que revocó (si aplica)
@ManyToOne(() => User, { nullable: true })
@JoinColumn({ name: 'revoked_by_id' })
revokedBy?: User;
}

View File

@ -18,6 +18,7 @@ import {
} from 'typeorm';
import { Tenant } from '../../core/entities/tenant.entity';
import { EppCatalogo } from './epp-catalogo.entity';
import { AlmacenTemporal } from './almacen-temporal.entity';
@Entity({ schema: 'hse', name: 'epp_inventario' })
export class EppInventario {
@ -59,4 +60,9 @@ export class EppInventario {
@ManyToOne(() => EppCatalogo)
@JoinColumn({ name: 'epp_id' })
epp: EppCatalogo;
// FK a hse.almacen_temporal - ubicación del inventario de EPP
@ManyToOne(() => AlmacenTemporal, { nullable: true })
@JoinColumn({ name: 'almacen_id' })
almacen: AlmacenTemporal;
}

View File

@ -19,6 +19,7 @@ import {
import { Tenant } from '../../core/entities/tenant.entity';
import { EppCatalogo } from './epp-catalogo.entity';
import { User } from '../../core/entities/user.entity';
import { AlmacenTemporal } from './almacen-temporal.entity';
export type TipoMovimientoEpp = 'entrada' | 'salida' | 'transferencia' | 'ajuste';
@ -72,4 +73,14 @@ export class EppMovimiento {
@ManyToOne(() => User)
@JoinColumn({ name: 'created_by' })
createdBy: User;
// FK a hse.almacen_temporal - almacén origen (para transferencias y salidas)
@ManyToOne(() => AlmacenTemporal, { nullable: true })
@JoinColumn({ name: 'almacen_origen_id' })
almacenOrigen: AlmacenTemporal;
// FK a hse.almacen_temporal - almacén destino (para transferencias y entradas)
@ManyToOne(() => AlmacenTemporal, { nullable: true })
@JoinColumn({ name: 'almacen_destino_id' })
almacenDestino: AlmacenTemporal;
}

View File

@ -20,6 +20,7 @@ import {
import { Tenant } from '../../core/entities/tenant.entity';
import { User } from '../../core/entities/user.entity';
import { Fraccionamiento } from '../../construction/entities/fraccionamiento.entity';
import { Warehouse } from '../../warehouses/entities/warehouse.entity';
export type WarehouseTypeConstruction = 'central' | 'obra' | 'temporal' | 'transito';
@ -89,4 +90,9 @@ export class AlmacenProyecto {
@ManyToOne(() => User)
@JoinColumn({ name: 'created_by' })
createdBy: User;
// FK a inventory.warehouses (ERP-Core)
@ManyToOne(() => Warehouse, { nullable: false })
@JoinColumn({ name: 'warehouse_id' })
warehouse: Warehouse;
}

View File

@ -21,6 +21,7 @@ import { User } from '../../core/entities/user.entity';
import { Fraccionamiento } from '../../construction/entities/fraccionamiento.entity';
import { Lote } from '../../construction/entities/lote.entity';
import { Concepto } from '../../budgets/entities/concepto.entity';
import { Product } from '../../products/entities/product.entity';
@Entity({ schema: 'inventory', name: 'consumos_obra' })
export class ConsumoObra {
@ -110,4 +111,11 @@ export class ConsumoObra {
@ManyToOne(() => User)
@JoinColumn({ name: 'created_by' })
createdBy: User;
// FK a products.products (ERP-Core)
@ManyToOne(() => Product, { nullable: false })
@JoinColumn({ name: 'product_id' })
product: Product;
// NOTA: stockMoveId no tiene relación aún - StockMove entity pendiente de crear
}

View File

@ -21,6 +21,8 @@ import { User } from '../../core/entities/user.entity';
import { RequisicionObra } from './requisicion-obra.entity';
import { Concepto } from '../../budgets/entities/concepto.entity';
import { Lote } from '../../construction/entities/lote.entity';
import { Product } from '../../products/entities/product.entity';
import { Uom } from '../../core/entities/uom.entity';
@Entity({ schema: 'inventory', name: 'requisicion_lineas' })
export class RequisicionLinea {
@ -112,4 +114,14 @@ export class RequisicionLinea {
@ManyToOne(() => User)
@JoinColumn({ name: 'created_by' })
createdBy: User;
// FK a products.products (ERP-Core)
@ManyToOne(() => Product, { nullable: false })
@JoinColumn({ name: 'product_id' })
product: Product;
// FK a core.uom (ERP-Core)
@ManyToOne(() => Uom, { nullable: true })
@JoinColumn({ name: 'unit_id' })
unit: Uom;
}

View File

@ -22,6 +22,7 @@ import { Tenant } from '../../core/entities/tenant.entity';
import { User } from '../../core/entities/user.entity';
import { Fraccionamiento } from '../../construction/entities/fraccionamiento.entity';
import { RequisicionLinea } from './requisicion-linea.entity';
import { Warehouse } from '../../warehouses/entities/warehouse.entity';
export type RequisitionStatus = 'draft' | 'submitted' | 'approved' | 'partially_served' | 'served' | 'cancelled';
@ -114,4 +115,9 @@ export class RequisicionObra {
@OneToMany(() => RequisicionLinea, (linea) => linea.requisicion)
lineas: RequisicionLinea[];
// FK a inventory.warehouses (ERP-Core) - destino de la requisición
@ManyToOne(() => Warehouse, { nullable: true })
@JoinColumn({ name: 'destination_warehouse_id' })
destinationWarehouse: Warehouse;
}

View File

@ -22,6 +22,7 @@ import { Tenant } from '../../core/entities/tenant.entity';
import { User } from '../../core/entities/user.entity';
import { RequisicionObra } from '../../inventory/entities/requisicion-obra.entity';
import { ComparativoProveedor } from './comparativo-proveedor.entity';
import { Partner } from '../../partners/entities/partner.entity';
export type ComparativoStatus = 'draft' | 'in_evaluation' | 'approved' | 'cancelled';
@ -98,4 +99,9 @@ export class ComparativoCotizaciones {
@OneToMany(() => ComparativoProveedor, (cp) => cp.comparativo)
proveedores: ComparativoProveedor[];
// FK a partners.partners (ERP-Core) - proveedor ganador
@ManyToOne(() => Partner, { nullable: true })
@JoinColumn({ name: 'winner_supplier_id' })
winnerSupplier: Partner;
}

View File

@ -19,6 +19,7 @@ import {
import { Tenant } from '../../core/entities/tenant.entity';
import { User } from '../../core/entities/user.entity';
import { ComparativoProveedor } from './comparativo-proveedor.entity';
import { Product } from '../../products/entities/product.entity';
@Entity({ schema: 'purchase', name: 'comparativo_productos' })
export class ComparativoProducto {
@ -72,4 +73,9 @@ export class ComparativoProducto {
@ManyToOne(() => User)
@JoinColumn({ name: 'created_by' })
createdBy: User;
// FK a products.products (ERP-Core)
@ManyToOne(() => Product, { nullable: false })
@JoinColumn({ name: 'product_id' })
product: Product;
}

View File

@ -21,6 +21,7 @@ import { Tenant } from '../../core/entities/tenant.entity';
import { User } from '../../core/entities/user.entity';
import { ComparativoCotizaciones } from './comparativo-cotizaciones.entity';
import { ComparativoProducto } from './comparativo-producto.entity';
import { Partner } from '../../partners/entities/partner.entity';
@Entity({ schema: 'purchase', name: 'comparativo_proveedores' })
export class ComparativoProveedor {
@ -84,4 +85,9 @@ export class ComparativoProveedor {
@OneToMany(() => ComparativoProducto, (cp) => cp.comparativoProveedor)
productos: ComparativoProducto[];
// FK a partners.partners (ERP-Core) - proveedor participante
@ManyToOne(() => Partner, { nullable: false })
@JoinColumn({ name: 'supplier_id' })
supplier: Partner;
}

View File

@ -19,6 +19,7 @@ import {
} from 'typeorm';
import { Tenant } from '../../core/entities/tenant.entity';
import { User } from '../../core/entities/user.entity';
import { Partner } from '../../partners/entities/partner.entity';
@Entity({ schema: 'purchase', name: 'supplier_construction' })
@Index(['tenantId'])
@ -127,4 +128,9 @@ export class SupplierConstruction {
if (ratings.length === 0) return 0;
return ratings.reduce((sum, r) => sum + Number(r), 0) / ratings.length;
}
// FK a partners.partners (ERP-Core) - el proveedor como partner
@ManyToOne(() => Partner, { nullable: false })
@JoinColumn({ name: 'supplier_id' })
supplier: Partner;
}