erp-retail-backend-v2/src/modules/pos/entities/pos-order.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

224 lines
5.9 KiB
TypeScript

import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
OneToMany,
JoinColumn,
Index,
} from 'typeorm';
import { POSSession } from './pos-session.entity';
import { POSOrderLine } from './pos-order-line.entity';
import { POSPayment } from './pos-payment.entity';
export enum OrderStatus {
DRAFT = 'draft',
CONFIRMED = 'confirmed',
PAID = 'paid',
PARTIALLY_PAID = 'partially_paid',
VOIDED = 'voided',
REFUNDED = 'refunded',
}
export enum OrderType {
SALE = 'sale',
REFUND = 'refund',
EXCHANGE = 'exchange',
}
@Entity('pos_orders', { schema: 'retail' })
@Index(['tenantId', 'branchId', 'createdAt'])
@Index(['tenantId', 'sessionId'])
@Index(['tenantId', 'customerId'])
@Index(['tenantId', 'number'], { unique: true })
export class POSOrder {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ name: 'tenant_id', type: 'uuid' })
@Index()
tenantId: string;
@Column({ name: 'branch_id', type: 'uuid' })
branchId: string;
@Column({ name: 'session_id', type: 'uuid' })
sessionId: string;
@Column({ name: 'register_id', type: 'uuid' })
registerId: string;
@Column({ name: 'user_id', type: 'uuid' })
userId: string;
@Column({ length: 30, unique: true })
number: string;
@Column({
type: 'enum',
enum: OrderType,
default: OrderType.SALE,
})
type: OrderType;
@Column({
type: 'enum',
enum: OrderStatus,
default: OrderStatus.DRAFT,
})
status: OrderStatus;
// Customer (optional, from erp-core partners)
@Column({ name: 'customer_id', type: 'uuid', nullable: true })
customerId: string;
@Column({ name: 'customer_name', length: 200, nullable: true })
customerName: string;
@Column({ name: 'customer_rfc', length: 13, nullable: true })
customerRfc: string;
// Salesperson (for commission tracking)
@Column({ name: 'salesperson_id', type: 'uuid', nullable: true })
salespersonId: string;
// 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: 'discount_percent', type: 'decimal', precision: 5, scale: 2, default: 0 })
discountPercent: number;
@Column({ name: 'discount_reason', length: 255, nullable: true })
discountReason: string;
@Column({ name: 'discount_authorized_by', type: 'uuid', nullable: true })
discountAuthorizedBy: string;
@Column({ name: 'tax_amount', type: 'decimal', precision: 15, scale: 2, default: 0 })
taxAmount: 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: 'change_amount', type: 'decimal', precision: 15, scale: 2, default: 0 })
changeAmount: number;
// Tax breakdown
@Column({ name: 'tax_breakdown', type: 'jsonb', nullable: true })
taxBreakdown: {
taxId: string;
taxName: string;
rate: number;
base: number;
amount: number;
}[];
// 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;
// Coupon/Promotion
@Column({ name: 'coupon_id', type: 'uuid', nullable: true })
couponId: string;
@Column({ name: 'coupon_code', length: 50, nullable: true })
couponCode: string;
@Column({ name: 'promotion_ids', type: 'jsonb', nullable: true })
promotionIds: string[];
// Loyalty points
@Column({ name: 'loyalty_points_earned', type: 'int', default: 0 })
loyaltyPointsEarned: number;
@Column({ name: 'loyalty_points_redeemed', type: 'int', default: 0 })
loyaltyPointsRedeemed: number;
@Column({ name: 'loyalty_points_value', type: 'decimal', precision: 15, scale: 2, default: 0 })
loyaltyPointsValue: number;
// Invoicing
@Column({ name: 'requires_invoice', type: 'boolean', default: false })
requiresInvoice: boolean;
@Column({ name: 'cfdi_id', type: 'uuid', nullable: true })
cfdiId: string;
@Column({ name: 'invoice_status', length: 20, nullable: true })
invoiceStatus: 'pending' | 'issued' | 'cancelled';
// Reference to original order (for refunds/exchanges)
@Column({ name: 'original_order_id', type: 'uuid', nullable: true })
originalOrderId: string;
// Void info
@Column({ name: 'voided_at', type: 'timestamp with time zone', nullable: true })
voidedAt: Date;
@Column({ name: 'voided_by', type: 'uuid', nullable: true })
voidedBy: string;
@Column({ name: 'void_reason', length: 255, nullable: true })
voidReason: string;
// Notes
@Column({ type: 'text', nullable: true })
notes: string;
// Offline sync
@Column({ name: 'is_offline_order', type: 'boolean', default: false })
isOfflineOrder: boolean;
@Column({ name: 'offline_uuid', type: 'uuid', nullable: true })
offlineUuid: string;
@Column({ name: 'synced_at', type: 'timestamp with time zone', nullable: true })
syncedAt: Date;
// Receipt
@Column({ name: 'receipt_printed', type: 'boolean', default: false })
receiptPrinted: boolean;
@Column({ name: 'receipt_sent', type: 'boolean', default: false })
receiptSent: boolean;
@Column({ name: 'receipt_email', length: 100, nullable: true })
receiptEmail: 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: 'completed_at', type: 'timestamp with time zone', nullable: true })
completedAt: Date;
// Relations
@ManyToOne(() => POSSession, (session) => session.orders)
@JoinColumn({ name: 'session_id' })
session: POSSession;
@OneToMany(() => POSOrderLine, (line) => line.order)
lines: POSOrderLine[];
@OneToMany(() => POSPayment, (payment) => payment.order)
payments: POSPayment[];
}