erp-retail/orchestration/planes/fase-2-analisis-modulos/ANALISIS-RT-009-ecommerce.md

568 lines
14 KiB
Markdown

# ANALISIS MODULO RT-009: E-COMMERCE
**Fecha:** 2025-12-18
**Fase:** 2 - Analisis por Modulo
**Modulo:** RT-009 E-commerce
**Herencia:** 20%
**Story Points:** 55
**Prioridad:** P2
---
## 1. DESCRIPCION GENERAL
### 1.1 Proposito
Tienda online integrada con inventario, carrito de compras, checkout, pasarelas de pago y opciones de entrega.
### 1.2 Funcionalidades Principales
| Funcionalidad | Descripcion | Criticidad |
|---------------|-------------|------------|
| Catalogo online | Navegacion y busqueda | Alta |
| Carrito | Persistente | Alta |
| Checkout | Flujo completo | Critica |
| Pagos | Multiples pasarelas | Critica |
| Envio | Multiples opciones | Alta |
| Pedidos | Gestion backoffice | Alta |
---
## 2. HERENCIA DEL CORE
### 2.1 Componentes Heredados (20%)
| Componente Core | % Uso | Accion |
|-----------------|-------|--------|
| inventory.products | 100% | HEREDAR |
| sales.pricelists | 100% | HEREDAR |
| core.partners | 100% | HEREDAR |
### 2.2 Servicios a Heredar
```typescript
import { ProductsService } from '@erp-core/inventory';
import { PricelistsService } from '@erp-core/sales';
import { PartnersService } from '@erp-core/core';
```
---
## 3. COMPONENTES NUEVOS
### 3.1 Entidades (TypeORM)
```typescript
// 1. EcommerceOrder - Pedido online
@Entity('ecommerce_orders', { schema: 'retail' })
export class EcommerceOrder {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column('uuid')
tenantId: string;
@Column()
orderNumber: string;
@ManyToOne(() => Partner)
customer: Partner;
@Column({ type: 'enum', enum: EcommerceOrderStatus })
status: EcommerceOrderStatus;
// pending, paid, preparing, shipped, ready_pickup, delivered, cancelled
@Column({ type: 'timestamptz' })
orderDate: Date;
// Totales
@Column({ type: 'decimal', precision: 12, scale: 2 })
subtotal: number;
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0 })
discountAmount: number;
@Column({ type: 'decimal', precision: 12, scale: 2 })
shippingCost: number;
@Column({ type: 'decimal', precision: 12, scale: 2 })
taxAmount: number;
@Column({ type: 'decimal', precision: 12, scale: 2 })
total: number;
// Pago
@Column({ type: 'enum', enum: PaymentStatus })
paymentStatus: PaymentStatus;
@Column({ nullable: true })
paymentMethod: string;
@Column({ nullable: true })
paymentReference: string;
// Entrega
@Column({ type: 'enum', enum: DeliveryMethod })
deliveryMethod: DeliveryMethod; // shipping, pickup
@ManyToOne(() => Branch, { nullable: true })
pickupBranch: Branch; // Si es pickup
@Column({ type: 'jsonb', nullable: true })
shippingAddress: Address;
@Column({ nullable: true })
trackingNumber: string;
@OneToMany(() => EcommerceOrderLine, line => line.order)
lines: EcommerceOrderLine[];
@Column({ nullable: true })
notes: string;
}
// 2. EcommerceOrderLine
@Entity('ecommerce_order_lines', { schema: 'retail' })
export class EcommerceOrderLine {
@PrimaryGeneratedColumn('uuid')
id: string;
@ManyToOne(() => EcommerceOrder)
order: EcommerceOrder;
@ManyToOne(() => Product)
product: Product;
@Column()
productName: string;
@Column({ type: 'decimal', precision: 12, scale: 4 })
quantity: number;
@Column({ type: 'decimal', precision: 12, scale: 2 })
unitPrice: number;
@Column({ type: 'decimal', precision: 12, scale: 2 })
total: number;
}
// 3. Cart - Carrito (session-based)
@Entity('carts', { schema: 'retail' })
export class Cart {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column('uuid')
tenantId: string;
@ManyToOne(() => Partner, { nullable: true })
customer: Partner; // null si guest
@Column({ nullable: true })
sessionId: string; // Para guests
@OneToMany(() => CartItem, item => item.cart)
items: CartItem[];
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0 })
subtotal: number;
@Column({ type: 'timestamptz' })
createdAt: Date;
@Column({ type: 'timestamptz' })
updatedAt: Date;
@Column({ type: 'timestamptz', nullable: true })
expiresAt: Date;
}
// 4. CartItem
@Entity('cart_items', { schema: 'retail' })
export class CartItem {
@PrimaryGeneratedColumn('uuid')
id: string;
@ManyToOne(() => Cart)
cart: Cart;
@ManyToOne(() => Product)
product: Product;
@Column({ type: 'decimal', precision: 12, scale: 4 })
quantity: number;
@Column({ type: 'decimal', precision: 12, scale: 2 })
unitPrice: number;
@Column({ type: 'decimal', precision: 12, scale: 2 })
total: number;
}
// 5. ShippingRate
@Entity('shipping_rates', { schema: 'retail' })
export class ShippingRate {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column('uuid')
tenantId: string;
@Column()
name: string; // "Envio estandar", "Express"
@Column()
carrier: string; // "Fedex", "DHL", "Estafeta"
@Column({ type: 'decimal', precision: 12, scale: 2 })
baseRate: number;
@Column({ type: 'decimal', precision: 12, scale: 2, nullable: true })
freeShippingMinimum: number;
@Column({ type: 'int', nullable: true })
estimatedDays: number;
@Column({ type: 'boolean', default: true })
isActive: boolean;
}
```
### 3.2 Servicios Backend
| Servicio | Metodos Principales |
|----------|-------------------|
| CatalogService | search(), getByCategory(), getProduct() |
| CartService | create(), addItem(), updateItem(), removeItem(), clear() |
| CheckoutService | validate(), calculateTotals(), processPayment() |
| PaymentGatewayService | createPayment(), capture(), refund() |
| ShippingService | calculateRates(), createShipment(), track() |
| EcommerceOrderService | create(), updateStatus(), getByCustomer() |
### 3.3 Controladores
```typescript
// API Publica (Storefront)
@Controller('store')
export class StorefrontController {
// Catalogo
@Get('products')
getProducts(@Query() filters: CatalogFilters): Promise<PaginatedProducts>;
@Get('products/:id')
getProduct(@Param('id') id: string): Promise<ProductDetail>;
@Get('products/search')
searchProducts(@Query('q') query: string): Promise<Product[]>;
@Get('categories')
getCategories(): Promise<Category[]>;
// Carrito
@Get('cart')
getCart(): Promise<Cart>;
@Post('cart/items')
addToCart(@Body() dto: AddToCartDto): Promise<Cart>;
@Put('cart/items/:id')
updateCartItem(@Param('id') id: string, @Body() dto: UpdateCartDto): Promise<Cart>;
@Delete('cart/items/:id')
removeFromCart(@Param('id') id: string): Promise<Cart>;
// Checkout
@Post('checkout/validate')
validateCheckout(@Body() dto: CheckoutDto): Promise<CheckoutValidation>;
@Get('checkout/shipping-rates')
getShippingRates(@Query() dto: ShippingQuery): Promise<ShippingRate[]>;
@Post('checkout/complete')
completeCheckout(@Body() dto: CompleteCheckoutDto): Promise<EcommerceOrder>;
// Pagos
@Post('payments/create')
createPayment(@Body() dto: PaymentDto): Promise<PaymentIntent>;
@Post('payments/webhook')
handleWebhook(@Body() payload: any): Promise<void>;
// Pedidos (autenticado)
@Get('orders')
@UseGuards(AuthGuard)
getMyOrders(): Promise<EcommerceOrder[]>;
@Get('orders/:id')
@UseGuards(AuthGuard)
getOrder(@Param('id') id: string): Promise<EcommerceOrder>;
}
// API Backoffice
@Controller('ecommerce')
export class EcommerceController {
// Gestion de pedidos
@Get('orders')
getOrders(@Query() filters: OrderFilters): Promise<PaginatedOrders>;
@Put('orders/:id/status')
updateStatus(@Param('id') id: string, @Body() dto: StatusDto): Promise<EcommerceOrder>;
@Post('orders/:id/ship')
markAsShipped(@Param('id') id: string, @Body() dto: ShipDto): Promise<EcommerceOrder>;
// Configuracion
@Get('shipping-rates')
getShippingRates(): Promise<ShippingRate[]>;
@Post('shipping-rates')
createShippingRate(@Body() dto: CreateRateDto): Promise<ShippingRate>;
}
```
---
## 4. INTEGRACIONES EXTERNAS
### 4.1 Pasarelas de Pago
```typescript
interface PaymentGateway {
name: string;
createPayment(order: EcommerceOrder): Promise<PaymentIntent>;
capturePayment(paymentId: string): Promise<PaymentResult>;
refund(paymentId: string, amount: number): Promise<RefundResult>;
}
// Implementaciones
class StripeGateway implements PaymentGateway { ... }
class ConektaGateway implements PaymentGateway { ... }
class MercadoPagoGateway implements PaymentGateway { ... }
```
### 4.2 Proveedores de Envio
```typescript
interface ShippingProvider {
name: string;
calculateRate(origin: Address, destination: Address, weight: number): Promise<ShippingQuote>;
createShipment(order: EcommerceOrder): Promise<Shipment>;
getTracking(trackingNumber: string): Promise<TrackingInfo>;
}
// Implementaciones
class FedexProvider implements ShippingProvider { ... }
class DHLProvider implements ShippingProvider { ... }
class EstafetaProvider implements ShippingProvider { ... }
```
---
## 5. FLUJOS DE NEGOCIO
### 5.1 Flujo de Compra
```
1. Cliente navega catalogo
2. Agrega productos al carrito
3. Revisa carrito
4. Inicia checkout
5. Login/registro (o guest)
6. Selecciona direccion de envio
7. Selecciona metodo de envio
8. Ve resumen con totales
9. Selecciona metodo de pago
10. Procesa pago
11. Confirmacion de pedido
12. Email de confirmacion
```
### 5.2 Flujo de Gestion de Pedido
```
1. Pedido creado (PENDING)
2. Pago confirmado (PAID)
3. Preparando (PREPARING)
- Reservar stock
- Imprimir etiqueta
4. Enviado (SHIPPED) o Listo para recoger (READY_PICKUP)
- Tracking disponible
5. Entregado (DELIVERED)
6. Fin (o cancelado en cualquier punto)
```
---
## 6. TABLAS DDL
### 6.1 Tablas Nuevas
```sql
-- Pedidos
CREATE TABLE retail.ecommerce_orders (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id),
order_number VARCHAR(20) NOT NULL,
customer_id UUID NOT NULL REFERENCES core.partners(id),
status VARCHAR(20) NOT NULL DEFAULT 'pending',
order_date TIMESTAMPTZ NOT NULL DEFAULT NOW(),
subtotal DECIMAL(12,2) NOT NULL,
discount_amount DECIMAL(12,2) DEFAULT 0,
shipping_cost DECIMAL(12,2) NOT NULL DEFAULT 0,
tax_amount DECIMAL(12,2) NOT NULL DEFAULT 0,
total DECIMAL(12,2) NOT NULL,
payment_status VARCHAR(20),
payment_method VARCHAR(50),
payment_reference VARCHAR(100),
delivery_method VARCHAR(20) NOT NULL,
pickup_branch_id UUID REFERENCES retail.branches(id),
shipping_address JSONB,
tracking_number VARCHAR(50),
notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ,
UNIQUE(tenant_id, order_number)
);
-- Lineas
CREATE TABLE retail.ecommerce_order_lines (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id),
order_id UUID NOT NULL REFERENCES retail.ecommerce_orders(id) ON DELETE CASCADE,
product_id UUID NOT NULL REFERENCES inventory.products(id),
product_name VARCHAR(255) NOT NULL,
quantity DECIMAL(12,4) NOT NULL,
unit_price DECIMAL(12,2) NOT NULL,
total DECIMAL(12,2) NOT NULL
);
-- Carritos
CREATE TABLE retail.carts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id),
customer_id UUID REFERENCES core.partners(id),
session_id VARCHAR(100),
subtotal DECIMAL(12,2) DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ
);
CREATE TABLE retail.cart_items (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id),
cart_id UUID NOT NULL REFERENCES retail.carts(id) ON DELETE CASCADE,
product_id UUID NOT NULL REFERENCES inventory.products(id),
quantity DECIMAL(12,4) NOT NULL,
unit_price DECIMAL(12,2) NOT NULL,
total DECIMAL(12,2) NOT NULL
);
-- Tarifas de envio
CREATE TABLE retail.shipping_rates (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id),
name VARCHAR(100) NOT NULL,
carrier VARCHAR(50) NOT NULL,
base_rate DECIMAL(12,2) NOT NULL,
free_shipping_minimum DECIMAL(12,2),
estimated_days INT,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
---
## 7. DEPENDENCIAS
### 7.1 Dependencias de Retail
| Modulo | Tipo |
|--------|------|
| RT-001 Fundamentos | Prerequisito |
| RT-003 Inventario | Stock |
| RT-005 Clientes | Clientes y puntos |
| RT-006 Precios | Precios online |
### 7.2 Dependencias Externas
| Servicio | Proposito |
|----------|-----------|
| Stripe/Conekta | Pagos |
| Fedex/DHL | Envios |
| SendGrid | Emails |
### 7.3 Bloquea a
| Modulo | Razon |
|--------|-------|
| RT-010 Facturacion | Facturas de pedidos |
---
## 8. CRITERIOS DE ACEPTACION
### 8.1 Storefront
- [ ] Navegar catalogo
- [ ] Buscar productos
- [ ] Ver detalle de producto
- [ ] Stock en tiempo real
- [ ] Agregar al carrito
- [ ] Carrito persistente
- [ ] Checkout como guest o registrado
- [ ] Multiples metodos de pago
- [ ] Envio o pickup
- [ ] Confirmacion por email
### 8.2 Backoffice
- [ ] Ver pedidos
- [ ] Actualizar estado
- [ ] Generar etiqueta envio
- [ ] Registrar tracking
- [ ] Cancelar pedido
---
## 9. ESTIMACION DETALLADA
| Componente | SP Backend | SP Frontend | Total |
|------------|-----------|-------------|-------|
| Entities + Migrations | 5 | - | 5 |
| CatalogService | 3 | - | 3 |
| CartService | 5 | - | 5 |
| CheckoutService | 5 | - | 5 |
| PaymentGatewayService | 8 | - | 8 |
| ShippingService | 5 | - | 5 |
| OrderService | 5 | - | 5 |
| Storefront UI | - | 13 | 13 |
| Backoffice UI | - | 6 | 6 |
| **TOTAL** | **36** | **19** | **55** |
---
**Estado:** ANALISIS COMPLETO
**Bloqueado por:** RT-001, RT-003, RT-005, RT-006