erp-retail-backend-v2/src/modules/ecommerce/entities/ecommerce-order-line.entity.ts
rckrdmrd a6186c4022 Migración desde erp-retail/backend - Estándar multi-repo v2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 08:11:34 -06:00

199 lines
5.1 KiB
TypeScript

import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
ManyToOne,
JoinColumn,
Index,
} from 'typeorm';
import { EcommerceOrder } from './ecommerce-order.entity';
export enum OrderLineStatus {
PENDING = 'pending',
RESERVED = 'reserved',
FULFILLED = 'fulfilled',
SHIPPED = 'shipped',
DELIVERED = 'delivered',
CANCELLED = 'cancelled',
RETURNED = 'returned',
REFUNDED = 'refunded',
}
@Entity('ecommerce_order_lines', { schema: 'retail' })
@Index(['tenantId', 'orderId'])
@Index(['tenantId', 'productId'])
export class EcommerceOrderLine {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ name: 'tenant_id', type: 'uuid' })
@Index()
tenantId: string;
@Column({ name: 'order_id', type: 'uuid' })
orderId: string;
@Column({ name: 'line_number', type: 'int' })
lineNumber: number;
@Column({
type: 'enum',
enum: OrderLineStatus,
default: OrderLineStatus.PENDING,
})
status: OrderLineStatus;
// Product (from erp-core)
@Column({ name: 'product_id', type: 'uuid' })
productId: string;
@Column({ name: 'product_code', length: 50 })
productCode: string;
@Column({ name: 'product_name', length: 200 })
productName: string;
@Column({ name: 'product_slug', length: 255, nullable: true })
productSlug: string;
@Column({ name: 'product_image', length: 255, nullable: true })
productImage: string;
// Variant
@Column({ name: 'variant_id', type: 'uuid', nullable: true })
variantId: string;
@Column({ name: 'variant_name', length: 200, nullable: true })
variantName: string;
@Column({ name: 'variant_sku', length: 50, nullable: true })
variantSku: string;
@Column({ name: 'variant_options', type: 'jsonb', nullable: true })
variantOptions: {
name: string;
value: string;
}[];
// Quantity
@Column({ type: 'decimal', precision: 15, scale: 4, default: 1 })
quantity: number;
@Column({ name: 'quantity_fulfilled', type: 'decimal', precision: 15, scale: 4, default: 0 })
quantityFulfilled: number;
@Column({ name: 'quantity_refunded', type: 'decimal', precision: 15, scale: 4, default: 0 })
quantityRefunded: number;
// UOM
@Column({ name: 'uom_id', type: 'uuid', nullable: true })
uomId: string;
@Column({ name: 'uom_name', length: 20, default: 'PZA' })
uomName: string;
// Pricing
@Column({ name: 'unit_price', type: 'decimal', precision: 15, scale: 4 })
unitPrice: number;
@Column({ name: 'original_price', type: 'decimal', precision: 15, scale: 4 })
originalPrice: number;
// Discounts
@Column({ name: 'discount_percent', type: 'decimal', precision: 5, scale: 2, default: 0 })
discountPercent: number;
@Column({ name: 'discount_amount', type: 'decimal', precision: 15, scale: 2, default: 0 })
discountAmount: number;
@Column({ name: 'promotion_id', type: 'uuid', nullable: true })
promotionId: string;
@Column({ name: 'promotion_name', length: 100, nullable: true })
promotionName: string;
// Tax
@Column({ name: 'tax_id', type: 'uuid', nullable: true })
taxId: string;
@Column({ name: 'tax_rate', type: 'decimal', precision: 5, scale: 4, default: 0 })
taxRate: number;
@Column({ name: 'tax_amount', type: 'decimal', precision: 15, scale: 2, default: 0 })
taxAmount: number;
@Column({ name: 'tax_included', type: 'boolean', default: true })
taxIncluded: boolean;
// Totals
@Column({ type: 'decimal', precision: 15, scale: 2, default: 0 })
subtotal: number;
@Column({ type: 'decimal', precision: 15, scale: 2, default: 0 })
total: number;
// Cost
@Column({ name: 'unit_cost', type: 'decimal', precision: 15, scale: 4, nullable: true })
unitCost: number;
// Weight (for shipping calculation)
@Column({ type: 'decimal', precision: 10, scale: 4, nullable: true })
weight: number;
@Column({ name: 'weight_unit', length: 5, default: 'kg' })
weightUnit: string;
// Warehouse
@Column({ name: 'warehouse_id', type: 'uuid', nullable: true })
warehouseId: string;
// Lot/Serial
@Column({ name: 'lot_number', length: 50, nullable: true })
lotNumber: string;
@Column({ name: 'serial_number', length: 50, nullable: true })
serialNumber: string;
// Custom options
@Column({ name: 'custom_options', type: 'jsonb', nullable: true })
customOptions: {
name: string;
value: string;
price?: number;
}[];
// Gift
@Column({ name: 'is_gift', type: 'boolean', default: false })
isGift: boolean;
@Column({ name: 'gift_message', type: 'text', nullable: true })
giftMessage: string;
// Refund
@Column({ name: 'refunded_at', type: 'timestamp with time zone', nullable: true })
refundedAt: Date;
@Column({ name: 'refund_amount', type: 'decimal', precision: 15, scale: 2, default: 0 })
refundAmount: number;
@Column({ name: 'refund_reason', length: 255, nullable: true })
refundReason: string;
// Notes
@Column({ type: 'text', nullable: true })
notes: string;
// Metadata
@Column({ type: 'jsonb', nullable: true })
metadata: Record<string, any>;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
// Relations
@ManyToOne(() => EcommerceOrder, (order) => order.lines)
@JoinColumn({ name: 'order_id' })
order: EcommerceOrder;
}