162 lines
4.6 KiB
TypeScript
162 lines
4.6 KiB
TypeScript
import {
|
|
Entity,
|
|
PrimaryGeneratedColumn,
|
|
Column,
|
|
CreateDateColumn,
|
|
UpdateDateColumn,
|
|
OneToMany,
|
|
Index,
|
|
} from 'typeorm';
|
|
import { MembershipLevel } from './membership-level.entity';
|
|
|
|
export enum ProgramStatus {
|
|
ACTIVE = 'active',
|
|
INACTIVE = 'inactive',
|
|
SUSPENDED = 'suspended',
|
|
}
|
|
|
|
export enum PointsCalculation {
|
|
FIXED_PER_PURCHASE = 'fixed_per_purchase',
|
|
PERCENTAGE_OF_AMOUNT = 'percentage_of_amount',
|
|
POINTS_PER_CURRENCY = 'points_per_currency',
|
|
}
|
|
|
|
@Entity('loyalty_programs', { schema: 'retail' })
|
|
@Index(['tenantId', 'status'])
|
|
@Index(['tenantId', 'code'], { unique: true })
|
|
export class LoyaltyProgram {
|
|
@PrimaryGeneratedColumn('uuid')
|
|
id: string;
|
|
|
|
@Column({ name: 'tenant_id', type: 'uuid' })
|
|
@Index()
|
|
tenantId: string;
|
|
|
|
@Column({ length: 20, unique: true })
|
|
code: string;
|
|
|
|
@Column({ length: 100 })
|
|
name: string;
|
|
|
|
@Column({ type: 'text', nullable: true })
|
|
description: string;
|
|
|
|
@Column({
|
|
type: 'enum',
|
|
enum: ProgramStatus,
|
|
default: ProgramStatus.ACTIVE,
|
|
})
|
|
status: ProgramStatus;
|
|
|
|
// Points configuration
|
|
@Column({
|
|
name: 'points_calculation',
|
|
type: 'enum',
|
|
enum: PointsCalculation,
|
|
default: PointsCalculation.POINTS_PER_CURRENCY,
|
|
})
|
|
pointsCalculation: PointsCalculation;
|
|
|
|
@Column({ name: 'points_per_currency', type: 'decimal', precision: 10, scale: 4, default: 1 })
|
|
pointsPerCurrency: number; // e.g., 1 point per $10 MXN
|
|
|
|
@Column({ name: 'currency_per_point', type: 'decimal', precision: 10, scale: 2, default: 10 })
|
|
currencyPerPoint: number; // e.g., $10 MXN = 1 point
|
|
|
|
@Column({ name: 'minimum_purchase', type: 'decimal', precision: 15, scale: 2, default: 0 })
|
|
minimumPurchase: number;
|
|
|
|
@Column({ name: 'round_points', type: 'boolean', default: true })
|
|
roundPoints: boolean;
|
|
|
|
@Column({ name: 'round_direction', length: 10, default: 'down' })
|
|
roundDirection: 'up' | 'down' | 'nearest';
|
|
|
|
// Redemption configuration
|
|
@Column({ name: 'points_value', type: 'decimal', precision: 10, scale: 4, default: 0.1 })
|
|
pointsValue: number; // Value of 1 point in currency (e.g., 1 point = $0.10)
|
|
|
|
@Column({ name: 'min_points_redemption', type: 'int', default: 100 })
|
|
minPointsRedemption: number;
|
|
|
|
@Column({ name: 'max_redemption_percent', type: 'decimal', precision: 5, scale: 2, default: 100 })
|
|
maxRedemptionPercent: number; // Max % of purchase that can be paid with points
|
|
|
|
@Column({ name: 'allow_partial_redemption', type: 'boolean', default: true })
|
|
allowPartialRedemption: boolean;
|
|
|
|
// Expiration
|
|
@Column({ name: 'points_expire', type: 'boolean', default: true })
|
|
pointsExpire: boolean;
|
|
|
|
@Column({ name: 'expiration_months', type: 'int', default: 12 })
|
|
expirationMonths: number;
|
|
|
|
@Column({ name: 'expiration_policy', length: 20, default: 'fifo' })
|
|
expirationPolicy: 'fifo' | 'lifo' | 'oldest_first';
|
|
|
|
// Bonus configuration
|
|
@Column({ name: 'welcome_bonus', type: 'int', default: 0 })
|
|
welcomeBonus: number;
|
|
|
|
@Column({ name: 'birthday_bonus', type: 'int', default: 0 })
|
|
birthdayBonus: number;
|
|
|
|
@Column({ name: 'referral_bonus', type: 'int', default: 0 })
|
|
referralBonus: number;
|
|
|
|
@Column({ name: 'referee_bonus', type: 'int', default: 0 })
|
|
refereeBonus: number;
|
|
|
|
// Multipliers
|
|
@Column({ name: 'double_points_days', type: 'jsonb', nullable: true })
|
|
doublePointsDays: string[]; // ['monday', 'tuesday', etc.]
|
|
|
|
@Column({ name: 'category_multipliers', type: 'jsonb', nullable: true })
|
|
categoryMultipliers: {
|
|
categoryId: string;
|
|
multiplier: number;
|
|
}[];
|
|
|
|
// Restrictions
|
|
@Column({ name: 'excluded_categories', type: 'jsonb', nullable: true })
|
|
excludedCategories: string[];
|
|
|
|
@Column({ name: 'excluded_products', type: 'jsonb', nullable: true })
|
|
excludedProducts: string[];
|
|
|
|
@Column({ name: 'included_branches', type: 'jsonb', nullable: true })
|
|
includedBranches: string[]; // null = all branches
|
|
|
|
// Valid dates
|
|
@Column({ name: 'valid_from', type: 'date', nullable: true })
|
|
validFrom: Date;
|
|
|
|
@Column({ name: 'valid_until', type: 'date', nullable: true })
|
|
validUntil: Date;
|
|
|
|
// Terms
|
|
@Column({ name: 'terms_and_conditions', type: 'text', nullable: true })
|
|
termsAndConditions: 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: 'created_by', type: 'uuid', nullable: true })
|
|
createdBy: string;
|
|
|
|
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
|
|
updatedBy: string;
|
|
|
|
// Relations
|
|
@OneToMany(() => MembershipLevel, (level) => level.program)
|
|
levels: MembershipLevel[];
|
|
}
|