erp-retail/orchestration/planes/fase-2-analisis-modulos/ANALISIS-RT-005-clientes.md

499 lines
12 KiB
Markdown

# 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<Customer>;
async quickSearch(email: string): Promise<Customer>;
// Programa lealtad
async getPoints(customerId: string): Promise<LoyaltyInfo>;
async getLoyaltyCard(customerId: string): Promise<LoyaltyCard>;
}
```
---
## 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<Customer[]>;
@Post('quick-register')
quickRegister(@Body() dto: QuickRegisterDto): Promise<Customer>;
@Get(':id/history')
getPurchaseHistory(@Param('id') id: string): Promise<PurchaseHistory>;
// Lealtad
@Get(':id/loyalty')
getLoyaltyInfo(@Param('id') id: string): Promise<LoyaltyInfo>;
@Get(':id/loyalty/card')
getLoyaltyCard(@Param('id') id: string): Promise<LoyaltyCard>;
@Post(':id/loyalty/earn')
earnPoints(@Param('id') id: string, @Body() dto: EarnPointsDto): Promise<LoyaltyTransaction>;
@Post(':id/loyalty/redeem')
redeemPoints(@Param('id') id: string, @Body() dto: RedeemPointsDto): Promise<LoyaltyTransaction>;
@Get(':id/loyalty/transactions')
getTransactions(@Param('id') id: string): Promise<LoyaltyTransaction[]>;
}
@Controller('loyalty')
export class LoyaltyController {
// Programas
@Get('programs')
getPrograms(): Promise<LoyaltyProgram[]>;
@Post('programs')
createProgram(@Body() dto: CreateProgramDto): Promise<LoyaltyProgram>;
// Tarjetas
@Post('cards/issue')
issueCard(@Body() dto: IssueCardDto): Promise<LoyaltyCard>;
@Get('cards/:number')
getCardByNumber(@Param('number') number: string): Promise<LoyaltyCard>;
}
```
---
## 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