erp-transportistas-backend-v2/src/modules/carta-porte/entities/ubicacion-carta-porte.entity.ts
Adrian Flores Cortes 2120d6e8b0 feat(carta-porte): Add CFDI Carta Porte 3.1 compliance entities
- CartaPorte: Main CFDI entity with emisor/receptor, totals, XML/PDF
- UbicacionCartaPorte: Origin/destination locations with SAT codes
- MercanciaCartaPorte: Goods being transported with hazmat support
- FiguraTransporte: Operator/owner/lessor figures
- AutotransporteCartaPorte: Vehicle configuration and trailers
- HosLog: Hours of Service compliance (NOM-087)
- InspeccionPreViaje: Pre-trip inspection checklists

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 14:19:21 -06:00

113 lines
3.0 KiB
TypeScript

import {
Entity,
PrimaryGeneratedColumn,
Column,
Index,
ManyToOne,
JoinColumn,
} from 'typeorm';
import { CartaPorte } from './carta-porte.entity';
/**
* Tipo de Ubicación
*/
export enum TipoUbicacionCartaPorte {
ORIGEN = 'Origen',
DESTINO = 'Destino',
}
@Entity({ schema: 'compliance', name: 'ubicaciones_carta_porte' })
@Index('idx_ubicacion_carta', ['cartaPorteId'])
export class UbicacionCartaPorte {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ name: 'tenant_id', type: 'uuid' })
tenantId: string;
@Column({ name: 'carta_porte_id', type: 'uuid' })
cartaPorteId: string;
@ManyToOne(() => CartaPorte, (cp) => cp.ubicaciones)
@JoinColumn({ name: 'carta_porte_id' })
cartaPorte: CartaPorte;
// Tipo
@Column({ name: 'tipo_ubicacion', type: 'varchar', length: 10 })
tipoUbicacion: string;
// ID Ubicación (catálogo SAT)
@Column({ name: 'id_ubicacion', type: 'varchar', length: 10, nullable: true })
idUbicacion: string | null;
// RFC
@Column({ name: 'rfc_remitente_destinatario', type: 'varchar', length: 13, nullable: true })
rfcRemitenteDestinatario: string | null;
@Column({ name: 'nombre_remitente_destinatario', type: 'varchar', length: 200, nullable: true })
nombreRemitenteDestinatario: string | null;
// Domicilio
@Column({ type: 'varchar', length: 3, default: 'MEX' })
pais: string;
@Column({ type: 'varchar', length: 10, nullable: true })
estado: string | null;
@Column({ type: 'varchar', length: 10, nullable: true })
municipio: string | null;
@Column({ type: 'varchar', length: 10, nullable: true })
localidad: string | null;
@Column({ name: 'codigo_postal', type: 'varchar', length: 10 })
codigoPostal: string;
@Column({ type: 'varchar', length: 10, nullable: true })
colonia: string | null;
@Column({ type: 'varchar', length: 200, nullable: true })
calle: string | null;
@Column({ name: 'numero_exterior', type: 'varchar', length: 50, nullable: true })
numeroExterior: string | null;
@Column({ name: 'numero_interior', type: 'varchar', length: 50, nullable: true })
numeroInterior: string | null;
@Column({ type: 'varchar', length: 500, nullable: true })
referencia: string | null;
// Fechas
@Column({ name: 'fecha_hora_salida_llegada', type: 'timestamptz', nullable: true })
fechaHoraSalidaLlegada: Date | null;
// Distancia
@Column({ name: 'distancia_recorrida', type: 'decimal', precision: 10, scale: 2, nullable: true })
distanciaRecorrida: number | null;
// Secuencia
@Column({ type: 'int' })
secuencia: number;
// Helpers
get esOrigen(): boolean {
return this.tipoUbicacion === TipoUbicacionCartaPorte.ORIGEN;
}
get esDestino(): boolean {
return this.tipoUbicacion === TipoUbicacionCartaPorte.DESTINO;
}
get direccionCompleta(): string {
const partes = [
this.calle,
this.numeroExterior ? `#${this.numeroExterior}` : null,
this.numeroInterior ? `Int. ${this.numeroInterior}` : null,
this.colonia,
`CP ${this.codigoPostal}`,
].filter(Boolean);
return partes.join(', ');
}
}