EPIC-001: Complete Core Module - Add PaymentTerm entity with multi-line support (30/60/90 days, early payment discounts) - Add PaymentTerms service with calculateDueDate() functionality - Add DiscountRule entity with volume/time-based conditions - Add DiscountRules service with applyDiscounts() and rule combination logic - Add REST endpoints for payment-terms and discount-rules in core module - Register new entities in TypeORM configuration EPIC-002: Entity Consolidation - Add inventoryProductId FK to products.products for linking to inventory module - Consolidate Warehouse entity in warehouses module as canonical source - Add companyId and Location relation to canonical Warehouse - Update inventory module to re-export Warehouse from warehouses module - Remove deprecated warehouse.entity.ts from inventory module - Update inventory/warehouses.service.ts to use canonical Warehouse Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
146 lines
4.1 KiB
TypeScript
146 lines
4.1 KiB
TypeScript
import {
|
|
Entity,
|
|
PrimaryGeneratedColumn,
|
|
Column,
|
|
CreateDateColumn,
|
|
UpdateDateColumn,
|
|
DeleteDateColumn,
|
|
Index,
|
|
ManyToOne,
|
|
OneToMany,
|
|
JoinColumn,
|
|
} from 'typeorm';
|
|
import { Company } from '../../auth/entities/company.entity.js';
|
|
|
|
/**
|
|
* Warehouse Entity (schema: inventory.warehouses)
|
|
*
|
|
* This is the CANONICAL warehouse entity for the ERP system.
|
|
* All warehouse-related imports should use this entity.
|
|
*
|
|
* Note: The deprecated entity at inventory/entities/warehouse.entity.ts
|
|
* has been superseded by this one and should not be used for new code.
|
|
*/
|
|
@Entity({ name: 'warehouses', schema: 'inventory' })
|
|
@Index('idx_warehouses_tenant_id', ['tenantId'])
|
|
@Index('idx_warehouses_company_id', ['companyId'])
|
|
@Index('idx_warehouses_code_company', ['companyId', 'code'], { unique: true })
|
|
export class Warehouse {
|
|
@PrimaryGeneratedColumn('uuid')
|
|
id: string;
|
|
|
|
@Index()
|
|
@Column({ name: 'tenant_id', type: 'uuid' })
|
|
tenantId: string;
|
|
|
|
@Index()
|
|
@Column({ name: 'company_id', type: 'uuid', nullable: true })
|
|
companyId: string | null;
|
|
|
|
@ManyToOne(() => Company)
|
|
@JoinColumn({ name: 'company_id' })
|
|
company: Company;
|
|
|
|
@Index()
|
|
@Column({ name: 'branch_id', type: 'uuid', nullable: true })
|
|
branchId: string;
|
|
|
|
// Identificacion
|
|
@Index()
|
|
@Column({ type: 'varchar', length: 20 })
|
|
code: string;
|
|
|
|
@Column({ type: 'varchar', length: 100 })
|
|
name: string;
|
|
|
|
@Column({ type: 'text', nullable: true })
|
|
description: string;
|
|
|
|
// Tipo
|
|
@Index()
|
|
@Column({ name: 'warehouse_type', type: 'varchar', length: 20, default: 'standard' })
|
|
warehouseType: 'standard' | 'transit' | 'returns' | 'quarantine' | 'virtual';
|
|
|
|
// Direccion
|
|
@Column({ name: 'address_line1', type: 'varchar', length: 200, nullable: true })
|
|
addressLine1: string;
|
|
|
|
@Column({ name: 'address_line2', type: 'varchar', length: 200, nullable: true })
|
|
addressLine2: string;
|
|
|
|
@Column({ type: 'varchar', length: 100, nullable: true })
|
|
city: string;
|
|
|
|
@Column({ type: 'varchar', length: 100, nullable: true })
|
|
state: string;
|
|
|
|
@Column({ name: 'postal_code', type: 'varchar', length: 20, nullable: true })
|
|
postalCode: string;
|
|
|
|
@Column({ type: 'varchar', length: 3, default: 'MEX' })
|
|
country: string;
|
|
|
|
// Contacto
|
|
@Column({ name: 'manager_name', type: 'varchar', length: 100, nullable: true })
|
|
managerName: string;
|
|
|
|
@Column({ type: 'varchar', length: 30, nullable: true })
|
|
phone: string;
|
|
|
|
@Column({ type: 'varchar', length: 255, nullable: true })
|
|
email: string;
|
|
|
|
// Geolocalizacion
|
|
@Column({ type: 'decimal', precision: 10, scale: 8, nullable: true })
|
|
latitude: number;
|
|
|
|
@Column({ type: 'decimal', precision: 11, scale: 8, nullable: true })
|
|
longitude: number;
|
|
|
|
// Capacidad
|
|
@Column({ name: 'capacity_units', type: 'int', nullable: true })
|
|
capacityUnits: number;
|
|
|
|
@Column({ name: 'capacity_volume', type: 'decimal', precision: 10, scale: 4, nullable: true })
|
|
capacityVolume: number;
|
|
|
|
@Column({ name: 'capacity_weight', type: 'decimal', precision: 10, scale: 4, nullable: true })
|
|
capacityWeight: number;
|
|
|
|
// Configuracion
|
|
@Column({ type: 'jsonb', default: {} })
|
|
settings: {
|
|
allowNegative?: boolean;
|
|
autoReorder?: boolean;
|
|
};
|
|
|
|
// Relations (lazy-loaded to avoid circular dependency with inventory module)
|
|
// Note: Location entity in inventory module references this entity via warehouse_id FK
|
|
// Use: await warehouse.locations to load related locations
|
|
@OneToMany('Location', 'warehouse')
|
|
locations: Promise<any[]>;
|
|
|
|
// Estado
|
|
@Column({ name: 'is_active', type: 'boolean', default: true })
|
|
isActive: boolean;
|
|
|
|
@Column({ name: 'is_default', type: 'boolean', default: false })
|
|
isDefault: boolean;
|
|
|
|
// Metadata
|
|
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
|
|
createdAt: Date;
|
|
|
|
@Column({ name: 'created_by', type: 'uuid', nullable: true })
|
|
createdBy: string;
|
|
|
|
@UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
|
|
updatedAt: Date;
|
|
|
|
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
|
|
updatedBy: string;
|
|
|
|
@DeleteDateColumn({ name: 'deleted_at', type: 'timestamptz', nullable: true })
|
|
deletedAt: Date;
|
|
}
|