import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany, Index, } from 'typeorm'; import { EcommerceOrderLine } from './ecommerce-order-line.entity'; export enum EcommerceOrderStatus { PENDING = 'pending', CONFIRMED = 'confirmed', PROCESSING = 'processing', READY_FOR_PICKUP = 'ready_for_pickup', SHIPPED = 'shipped', DELIVERED = 'delivered', CANCELLED = 'cancelled', REFUNDED = 'refunded', } export enum PaymentStatus { PENDING = 'pending', AUTHORIZED = 'authorized', CAPTURED = 'captured', FAILED = 'failed', REFUNDED = 'refunded', PARTIALLY_REFUNDED = 'partially_refunded', } export enum FulfillmentType { SHIP = 'ship', PICKUP = 'pickup', DELIVERY = 'delivery', } @Entity('ecommerce_orders', { schema: 'retail' }) @Index(['tenantId', 'status', 'createdAt']) @Index(['tenantId', 'customerId']) @Index(['tenantId', 'number'], { unique: true }) @Index(['tenantId', 'paymentStatus']) export class EcommerceOrder { @PrimaryGeneratedColumn('uuid') id: string; @Column({ name: 'tenant_id', type: 'uuid' }) @Index() tenantId: string; @Column({ length: 30, unique: true }) number: string; @Column({ type: 'enum', enum: EcommerceOrderStatus, default: EcommerceOrderStatus.PENDING, }) status: EcommerceOrderStatus; @Column({ name: 'payment_status', type: 'enum', enum: PaymentStatus, default: PaymentStatus.PENDING, }) paymentStatus: PaymentStatus; @Column({ name: 'fulfillment_type', type: 'enum', enum: FulfillmentType, default: FulfillmentType.SHIP, }) fulfillmentType: FulfillmentType; // Customer @Column({ name: 'customer_id', type: 'uuid', nullable: true }) customerId: string; @Column({ name: 'customer_email', length: 100 }) customerEmail: string; @Column({ name: 'customer_phone', length: 20, nullable: true }) customerPhone: string; @Column({ name: 'customer_name', length: 200 }) customerName: string; @Column({ name: 'is_guest', type: 'boolean', default: false }) isGuest: boolean; // Currency @Column({ name: 'currency_code', length: 3, default: 'MXN' }) currencyCode: string; @Column({ name: 'exchange_rate', type: 'decimal', precision: 10, scale: 6, default: 1 }) exchangeRate: number; // Amounts @Column({ type: 'decimal', precision: 15, scale: 2, default: 0 }) subtotal: number; @Column({ name: 'discount_amount', type: 'decimal', precision: 15, scale: 2, default: 0 }) discountAmount: number; @Column({ name: 'tax_amount', type: 'decimal', precision: 15, scale: 2, default: 0 }) taxAmount: number; @Column({ name: 'shipping_amount', type: 'decimal', precision: 15, scale: 2, default: 0 }) shippingAmount: number; @Column({ name: 'shipping_tax', type: 'decimal', precision: 15, scale: 2, default: 0 }) shippingTax: number; @Column({ type: 'decimal', precision: 15, scale: 2, default: 0 }) total: number; @Column({ name: 'amount_paid', type: 'decimal', precision: 15, scale: 2, default: 0 }) amountPaid: number; @Column({ name: 'amount_refunded', type: 'decimal', precision: 15, scale: 2, default: 0 }) amountRefunded: number; // Item counts @Column({ name: 'items_count', type: 'int', default: 0 }) itemsCount: number; @Column({ name: 'items_quantity', type: 'decimal', precision: 15, scale: 4, default: 0 }) itemsQuantity: number; // Coupon @Column({ name: 'coupon_id', type: 'uuid', nullable: true }) couponId: string; @Column({ name: 'coupon_code', length: 50, nullable: true }) couponCode: string; @Column({ name: 'coupon_discount', type: 'decimal', precision: 15, scale: 2, default: 0 }) couponDiscount: number; // Loyalty @Column({ name: 'loyalty_points_used', type: 'int', default: 0 }) loyaltyPointsUsed: number; @Column({ name: 'loyalty_points_value', type: 'decimal', precision: 15, scale: 2, default: 0 }) loyaltyPointsValue: number; @Column({ name: 'loyalty_points_earned', type: 'int', default: 0 }) loyaltyPointsEarned: number; // Shipping address @Column({ name: 'shipping_address', type: 'jsonb' }) shippingAddress: { firstName: string; lastName: string; company?: string; address1: string; address2?: string; city: string; state: string; postalCode: string; country: string; phone: string; instructions?: string; }; // Billing address @Column({ name: 'billing_address', type: 'jsonb' }) billingAddress: { firstName: string; lastName: string; company?: string; rfc?: string; address1: string; address2?: string; city: string; state: string; postalCode: string; country: string; phone: string; }; // Shipping @Column({ name: 'shipping_method_id', type: 'uuid', nullable: true }) shippingMethodId: string; @Column({ name: 'shipping_method_name', length: 100, nullable: true }) shippingMethodName: string; @Column({ name: 'shipping_carrier', length: 100, nullable: true }) shippingCarrier: string; @Column({ name: 'tracking_number', length: 100, nullable: true }) trackingNumber: string; @Column({ name: 'tracking_url', length: 255, nullable: true }) trackingUrl: string; @Column({ name: 'estimated_delivery', type: 'date', nullable: true }) estimatedDelivery: Date; @Column({ name: 'shipped_at', type: 'timestamp with time zone', nullable: true }) shippedAt: Date; @Column({ name: 'delivered_at', type: 'timestamp with time zone', nullable: true }) deliveredAt: Date; // Pickup @Column({ name: 'pickup_branch_id', type: 'uuid', nullable: true }) pickupBranchId: string; @Column({ name: 'pickup_ready_at', type: 'timestamp with time zone', nullable: true }) pickupReadyAt: Date; @Column({ name: 'picked_up_at', type: 'timestamp with time zone', nullable: true }) pickedUpAt: Date; // Payment @Column({ name: 'payment_method', length: 50, nullable: true }) paymentMethod: string; @Column({ name: 'payment_gateway', length: 50, nullable: true }) paymentGateway: string; @Column({ name: 'payment_transaction_id', length: 100, nullable: true }) paymentTransactionId: string; @Column({ name: 'payment_details', type: 'jsonb', nullable: true }) paymentDetails: Record; // Invoice @Column({ name: 'requires_invoice', type: 'boolean', default: false }) requiresInvoice: boolean; @Column({ name: 'invoice_rfc', length: 13, nullable: true }) invoiceRfc: string; @Column({ name: 'invoice_uso_cfdi', length: 4, nullable: true }) invoiceUsoCfdi: string; @Column({ name: 'cfdi_id', type: 'uuid', nullable: true }) cfdiId: string; @Column({ name: 'invoice_status', length: 20, nullable: true }) invoiceStatus: string; // Gift @Column({ name: 'is_gift', type: 'boolean', default: false }) isGift: boolean; @Column({ name: 'gift_message', type: 'text', nullable: true }) giftMessage: string; // Notes @Column({ name: 'customer_notes', type: 'text', nullable: true }) customerNotes: string; @Column({ name: 'internal_notes', type: 'text', nullable: true }) internalNotes: string; // Cancellation @Column({ name: 'cancelled_at', type: 'timestamp with time zone', nullable: true }) cancelledAt: Date; @Column({ name: 'cancellation_reason', length: 255, nullable: true }) cancellationReason: string; // Source cart @Column({ name: 'cart_id', type: 'uuid', nullable: true }) cartId: string; // Fulfillment warehouse @Column({ name: 'warehouse_id', type: 'uuid', nullable: true }) warehouseId: string; // Analytics @Column({ name: 'utm_source', length: 100, nullable: true }) utmSource: string; @Column({ name: 'utm_medium', length: 100, nullable: true }) utmMedium: string; @Column({ name: 'utm_campaign', length: 100, nullable: true }) utmCampaign: string; @Column({ name: 'device_type', length: 20, nullable: true }) deviceType: string; @Column({ name: 'ip_address', length: 45, nullable: true }) ipAddress: string; // Metadata @Column({ type: 'jsonb', nullable: true }) metadata: Record; @CreateDateColumn({ name: 'created_at' }) createdAt: Date; @UpdateDateColumn({ name: 'updated_at' }) updatedAt: Date; @Column({ name: 'confirmed_at', type: 'timestamp with time zone', nullable: true }) confirmedAt: Date; // Relations @OneToMany(() => EcommerceOrderLine, (line) => line.order) lines: EcommerceOrderLine[]; }