# ANALISIS MODULO RT-005: CLIENTES Y PROGRAMA DE LEALTAD **Fecha:** 2025-12-18 **Fase:** 2 - Analisis por Modulo **Modulo:** RT-005 Clientes **Herencia:** 40% **Story Points:** 34 **Prioridad:** P1 --- ## 1. DESCRIPCION GENERAL ### 1.1 Proposito Gestion de clientes con programa de fidelizacion basado en puntos, niveles de membresia y recompensas. ### 1.2 Funcionalidades Principales | Funcionalidad | Descripcion | Criticidad | |---------------|-------------|------------| | Registro cliente | Datos minimos en POS | Alta | | Programa puntos | Acumulacion y canje | Alta | | Niveles membresia | Bronce, Plata, Oro | Media | | Historial compras | 3 anos | Media | | Segmentacion | Por comportamiento | Baja | --- ## 2. HERENCIA DEL CORE ### 2.1 Componentes Heredados (40%) | Componente Core | % Uso | Accion | |-----------------|-------|--------| | core.partners | 100% | HEREDAR (clientes) | | core.partner_contacts | 100% | HEREDAR | | crm.leads | 20% | OPCIONAL | ### 2.2 Servicios a Heredar ```typescript import { PartnersService } from '@erp-core/core'; import { ContactsService } from '@erp-core/core'; ``` ### 2.3 Servicios a Extender ```typescript class RetailCustomerService extends PartnersService { // Busqueda rapida async quickSearch(phone: string): Promise; async quickSearch(email: string): Promise; // Programa lealtad async getPoints(customerId: string): Promise; async getLoyaltyCard(customerId: string): Promise; } ``` --- ## 3. COMPONENTES NUEVOS ### 3.1 Entidades (TypeORM) ```typescript // 1. LoyaltyProgram - Programa de lealtad @Entity('loyalty_programs', { schema: 'retail' }) export class LoyaltyProgram { @PrimaryGeneratedColumn('uuid') id: string; @Column('uuid') tenantId: string; @Column() code: string; @Column() name: string; @Column({ nullable: true }) description: string; @Column({ type: 'decimal', precision: 5, scale: 2, default: 1 }) pointsPerCurrency: number; // 1 punto por $10 @Column({ type: 'decimal', precision: 5, scale: 2, default: 0.01 }) currencyPerPoint: number; // $0.10 por punto @Column({ type: 'int', default: 100 }) minPointsRedeem: number; @Column({ type: 'int', nullable: true }) pointsExpiryDays: number; // null = no expiran @Column({ type: 'boolean', default: true }) isActive: boolean; } // 2. LoyaltyCard - Tarjeta de cliente @Entity('loyalty_cards', { schema: 'retail' }) export class LoyaltyCard { @PrimaryGeneratedColumn('uuid') id: string; @Column('uuid') tenantId: string; @ManyToOne(() => LoyaltyProgram) program: LoyaltyProgram; @ManyToOne(() => Partner) customer: Partner; @Column() cardNumber: string; @Column({ type: 'date' }) issueDate: Date; @Column({ type: 'int', default: 0 }) pointsBalance: number; @Column({ type: 'int', default: 0 }) pointsEarned: number; @Column({ type: 'int', default: 0 }) pointsRedeemed: number; @Column({ type: 'int', default: 0 }) pointsExpired: number; @Column({ type: 'boolean', default: true }) isActive: boolean; } // 3. LoyaltyTransaction - Movimiento de puntos @Entity('loyalty_transactions', { schema: 'retail' }) export class LoyaltyTransaction { @PrimaryGeneratedColumn('uuid') id: string; @Column('uuid') tenantId: string; @ManyToOne(() => LoyaltyCard) card: LoyaltyCard; @Column({ type: 'enum', enum: LoyaltyTransactionType }) transactionType: LoyaltyTransactionType; // earn, redeem, expire, adjust @Column({ type: 'int' }) pointsAmount: number; @Column({ nullable: true }) referenceType: string; // pos_order, promotion, manual @Column({ type: 'uuid', nullable: true }) referenceId: string; @Column({ nullable: true }) notes: string; @Column({ type: 'timestamptz' }) createdAt: Date; } // 4. MembershipLevel - Niveles @Entity('membership_levels', { schema: 'retail' }) export class MembershipLevel { @PrimaryGeneratedColumn('uuid') id: string; @Column('uuid') tenantId: string; @ManyToOne(() => LoyaltyProgram) program: LoyaltyProgram; @Column() name: string; // Bronce, Plata, Oro @Column({ type: 'int' }) minPointsYear: number; // Puntos minimos para alcanzar @Column({ type: 'decimal', precision: 3, scale: 2, default: 1 }) multiplier: number; // 1x, 1.5x, 2x @Column({ type: 'jsonb', nullable: true }) benefits: object; // Beneficios adicionales } ``` ### 3.2 Servicios Backend | Servicio | Metodos Principales | |----------|-------------------| | RetailCustomerService | quickSearch(), register(), getHistory() | | LoyaltyProgramService | create(), configure(), getActive() | | LoyaltyCardService | issue(), activate(), getBalance() | | LoyaltyTransactionService | earnPoints(), redeemPoints(), expire() | | MembershipService | calculateLevel(), upgrade(), downgrade() | ### 3.3 Controladores ```typescript @Controller('customers') export class RetailCustomerController { // Clientes @Get('search') quickSearch(@Query('q') query: string): Promise; @Post('quick-register') quickRegister(@Body() dto: QuickRegisterDto): Promise; @Get(':id/history') getPurchaseHistory(@Param('id') id: string): Promise; // Lealtad @Get(':id/loyalty') getLoyaltyInfo(@Param('id') id: string): Promise; @Get(':id/loyalty/card') getLoyaltyCard(@Param('id') id: string): Promise; @Post(':id/loyalty/earn') earnPoints(@Param('id') id: string, @Body() dto: EarnPointsDto): Promise; @Post(':id/loyalty/redeem') redeemPoints(@Param('id') id: string, @Body() dto: RedeemPointsDto): Promise; @Get(':id/loyalty/transactions') getTransactions(@Param('id') id: string): Promise; } @Controller('loyalty') export class LoyaltyController { // Programas @Get('programs') getPrograms(): Promise; @Post('programs') createProgram(@Body() dto: CreateProgramDto): Promise; // Tarjetas @Post('cards/issue') issueCard(@Body() dto: IssueCardDto): Promise; @Get('cards/:number') getCardByNumber(@Param('number') number: string): Promise; } ``` --- ## 4. SISTEMA DE PUNTOS ### 4.1 Configuracion ```yaml loyalty_config: points: earn_rate: 1 # 1 punto por cada $10 redeem_rate: 100 # 100 puntos = $10 descuento min_redeem: 100 # Minimo para canjear max_discount_percent: 50 # Maximo descuento por puntos expiry_days: null # No expiran (o 365) levels: - name: "Bronce" min_points_year: 0 multiplier: 1.0 benefits: [] - name: "Plata" min_points_year: 1000 multiplier: 1.5 benefits: - "Envio gratis e-commerce" - "Ofertas exclusivas" - name: "Oro" min_points_year: 5000 multiplier: 2.0 benefits: - "Envio gratis e-commerce" - "Ofertas exclusivas" - "Acceso VIP preventas" - "Descuento cumpleaños 20%" ``` ### 4.2 Calculo de Puntos ```typescript // Al cerrar venta function calculatePoints(order: POSOrder, card: LoyaltyCard): number { const program = card.program; const level = getMembershipLevel(card); // Base: 1 punto por cada $10 const basePoints = Math.floor(order.total / program.pointsPerCurrency); // Multiplicador por nivel const multipliedPoints = Math.floor(basePoints * level.multiplier); // Puntos extra por promociones const bonusPoints = calculateBonusPoints(order); return multipliedPoints + bonusPoints; } // Canje de puntos function redeemPoints(points: number, program: LoyaltyProgram): number { if (points < program.minPointsRedeem) { throw new Error('Puntos insuficientes'); } // Calcular descuento const discount = points * program.currencyPerPoint; return discount; } ``` --- ## 5. FLUJOS DE NEGOCIO ### 5.1 Flujo en POS ``` 1. Cliente se identifica (telefono/tarjeta) ↓ 2. Buscar tarjeta de lealtad ↓ 3. Mostrar puntos disponibles ↓ 4. Realizar venta normal ↓ 5. Preguntar si desea canjear puntos ↓ 6. Si canjea: a. Calcular descuento b. Aplicar a orden c. Registrar redeem ↓ 7. Cerrar venta ↓ 8. Calcular puntos ganados ↓ 9. Registrar earn ↓ 10. Imprimir puntos en ticket ``` ### 5.2 Flujo de Registro ``` 1. Cliente nuevo en POS ↓ 2. Registro rapido (nombre, telefono) ↓ 3. Crear partner en core ↓ 4. Crear tarjeta lealtad ↓ 5. Asignar nivel Bronce ↓ 6. Opcional: puntos bienvenida ``` --- ## 6. TABLAS DDL ### 6.1 Tablas Definidas ```sql -- Ya en 03-retail-tables.sql CREATE TABLE retail.loyalty_programs (...); CREATE TABLE retail.loyalty_cards (...); CREATE TABLE retail.loyalty_transactions (...); -- Agregar niveles CREATE TABLE retail.membership_levels ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id), program_id UUID NOT NULL REFERENCES retail.loyalty_programs(id), name VARCHAR(50) NOT NULL, min_points_year INT NOT NULL DEFAULT 0, multiplier DECIMAL(3,2) NOT NULL DEFAULT 1.00, benefits JSONB, created_at TIMESTAMPTZ DEFAULT NOW() ); ``` ### 6.2 Indices ```sql -- Busqueda rapida cliente CREATE INDEX idx_partners_phone ON core.partners(phone); CREATE INDEX idx_partners_email ON core.partners(email); -- Tarjetas CREATE UNIQUE INDEX idx_loyalty_cards_number ON retail.loyalty_cards(tenant_id, card_number); CREATE INDEX idx_loyalty_cards_customer ON retail.loyalty_cards(customer_id); -- Transacciones CREATE INDEX idx_loyalty_transactions_card ON retail.loyalty_transactions(card_id); CREATE INDEX idx_loyalty_transactions_date ON retail.loyalty_transactions(created_at); ``` --- ## 7. DEPENDENCIAS ### 7.1 Dependencias de Core | Modulo | Estado | Requerido Para | |--------|--------|---------------| | MGN-005 Catalogs | 0% | Partners (clientes) | | MGN-014 CRM | 0% | Opcional | ### 7.2 Dependencias de Retail | Modulo | Tipo | |--------|------| | RT-001 Fundamentos | Prerequisito | ### 7.3 Bloquea a | Modulo | Razon | |--------|-------| | RT-002 POS | Integracion puntos | | RT-009 E-commerce | Clientes y puntos | --- ## 8. CRITERIOS DE ACEPTACION ### 8.1 Funcionales - [ ] Buscar cliente por telefono - [ ] Buscar cliente por email - [ ] Registro rapido de cliente - [ ] Crear programa de lealtad - [ ] Emitir tarjeta a cliente - [ ] Consultar balance de puntos - [ ] Acumular puntos al comprar - [ ] Canjear puntos por descuento - [ ] Ver historial de transacciones - [ ] Calcular nivel de membresia - [ ] Ver historial de compras (3 anos) ### 8.2 Performance - [ ] Busqueda cliente < 500ms - [ ] Consulta puntos < 200ms --- ## 9. RIESGOS | Riesgo | Probabilidad | Impacto | Mitigacion | |--------|--------------|---------|------------| | Fraude de puntos | Media | Alto | Auditoria + limites | | Performance busqueda | Baja | Medio | Indices | --- ## 10. ESTIMACION DETALLADA | Componente | SP Backend | SP Frontend | Total | |------------|-----------|-------------|-------| | Entities + Migrations | 3 | - | 3 | | RetailCustomerService | 5 | - | 5 | | LoyaltyProgramService | 3 | - | 3 | | LoyaltyCardService | 5 | - | 5 | | LoyaltyTransactionService | 3 | - | 3 | | MembershipService | 2 | - | 2 | | Controllers | 3 | - | 3 | | Customer Pages | - | 5 | 5 | | Loyalty Pages | - | 5 | 5 | | **TOTAL** | **24** | **10** | **34** | --- ## 11. REFERENCIAS | Documento | Ubicacion | |-----------|-----------| | Epica RT-005 | docs/08-epicas/EPIC-RT-005-clientes.md | | Modulo Core Partners | erp-core/backend/src/modules/partners/ | --- **Estado:** ANALISIS COMPLETO **Bloqueado por:** RT-001 Fundamentos