310 lines
8.3 KiB
TypeScript
310 lines
8.3 KiB
TypeScript
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<string, any>;
|
|
|
|
// 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<string, any>;
|
|
|
|
@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[];
|
|
}
|