erp-retail/orchestration/planes/fase-2-analisis-modulos/ANALISIS-RT-010-facturacion.md

526 lines
12 KiB
Markdown

# ANALISIS MODULO RT-010: FACTURACION CFDI 4.0
**Fecha:** 2025-12-18
**Fase:** 2 - Analisis por Modulo
**Modulo:** RT-010 Facturacion
**Herencia:** 60%
**Story Points:** 35
**Prioridad:** P0
---
## 1. DESCRIPCION GENERAL
### 1.1 Proposito
Generacion de comprobantes fiscales digitales (CFDI 4.0) para ventas en POS y e-commerce, con timbrado en tiempo real y portal de autofactura.
### 1.2 Funcionalidades Principales
| Funcionalidad | Descripcion | Criticidad |
|---------------|-------------|------------|
| Facturacion POS | Al cerrar venta | Critica |
| Publico general | RFC generico | Alta |
| Autofactura | Portal publico | Alta |
| Notas de credito | Por devolucion | Alta |
| Cancelacion | Dentro de plazo | Media |
| Reportes | Fiscales | Media |
---
## 2. HERENCIA DEL CORE
### 2.1 Componentes Heredados (60%)
| Componente Core | % Uso | Accion |
|-----------------|-------|--------|
| financial.invoices | 80% | EXTENDER |
| financial.invoice_lines | 80% | EXTENDER |
| financial.payments | 100% | HEREDAR |
| core.partners | 100% | HEREDAR |
### 2.2 Servicios a Heredar
```typescript
import { InvoicesService } from '@erp-core/financial';
import { PaymentsService } from '@erp-core/financial';
import { PartnersService } from '@erp-core/core';
```
### 2.3 Servicios a Extender
```typescript
class CFDIInvoiceService extends InvoicesService {
// Generacion CFDI
async generateCFDI(posOrderId: string): Promise<CFDI>;
async timbrar(cfdi: CFDI): Promise<TimbradoResult>;
// Cancelacion
async cancelCFDI(invoiceId: string, motivo: string): Promise<CancelResult>;
}
```
---
## 3. COMPONENTES NUEVOS
### 3.1 Estructura CFDI 4.0
```typescript
interface CFDI40 {
// Comprobante
version: '4.0';
serie: string;
folio: string;
fecha: Date;
formaPago: string; // 01 Efectivo, 04 Tarjeta, etc.
metodoPago: 'PUE' | 'PPD'; // Pago en una exhibicion / Parcialidades
tipoDeComprobante: 'I' | 'E' | 'T' | 'N' | 'P'; // Ingreso, Egreso, Traslado, Nomina, Pago
lugarExpedicion: string; // CP
// Emisor
emisor: {
rfc: string;
nombre: string;
regimenFiscal: string; // 601, 612, etc.
};
// Receptor
receptor: {
rfc: string;
nombre: string;
domicilioFiscalReceptor: string; // CP
regimenFiscalReceptor: string;
usoCFDI: string; // G03 Gastos en general, etc.
};
// Conceptos
conceptos: CFDIConcepto[];
// Impuestos
impuestos: {
totalImpuestosTrasladados: number;
totalImpuestosRetenidos: number;
traslados: CFDITraslado[];
retenciones?: CFDIRetencion[];
};
// Totales
subTotal: number;
descuento?: number;
total: number;
// Timbre (despues de timbrar)
timbreFiscalDigital?: {
version: '1.1';
uuid: string;
fechaTimbrado: Date;
rfcProvCertif: string;
selloCFD: string;
selloSAT: string;
noCertificadoSAT: string;
};
}
interface CFDIConcepto {
claveProdServ: string; // Clave SAT (ej: 01010101)
noIdentificacion?: string; // SKU
cantidad: number;
claveUnidad: string; // E48, H87, etc.
unidad?: string; // Descripcion unidad
descripcion: string;
valorUnitario: number;
importe: number;
descuento?: number;
objetoImp: '01' | '02' | '03'; // No objeto, Si objeto, Si objeto no desglosado
impuestos?: {
traslados: CFDITraslado[];
retenciones?: CFDIRetencion[];
};
}
interface CFDITraslado {
base: number;
impuesto: '002'; // IVA
tipoFactor: 'Tasa' | 'Cuota' | 'Exento';
tasaOCuota: number; // 0.160000
importe: number;
}
```
### 3.2 Servicios Backend
| Servicio | Metodos Principales |
|----------|-------------------|
| CFDIService | generate(), timbrar(), cancel(), validate() |
| CFDIBuilderService | fromPOSOrder(), fromEcommerceOrder() |
| PACService | timbrar(), consultar(), cancelar() |
| XMLService | buildXML(), parseXML(), validate() |
| PDFService | generatePDF() |
| AutoFacturaService | validateTicket(), generateFromTicket() |
### 3.3 Controladores
```typescript
@Controller('cfdi')
export class CFDIController {
// Generacion desde POS
@Post('pos/:orderId')
generateFromPOS(@Param('orderId') orderId: string,
@Body() dto: CFDIRequestDto): Promise<CFDI>;
// Generacion desde E-commerce
@Post('ecommerce/:orderId')
generateFromEcommerce(@Param('orderId') orderId: string): Promise<CFDI>;
// Factura publico general
@Post('public/:orderId')
generatePublicInvoice(@Param('orderId') orderId: string): Promise<CFDI>;
// Consulta
@Get(':id')
getCFDI(@Param('id') id: string): Promise<CFDI>;
@Get(':id/xml')
getXML(@Param('id') id: string): Promise<string>;
@Get(':id/pdf')
getPDF(@Param('id') id: string): Promise<Buffer>;
// Cancelacion
@Post(':id/cancel')
cancel(@Param('id') id: string, @Body() dto: CancelDto): Promise<CancelResult>;
// Notas de credito
@Post('credit-note')
createCreditNote(@Body() dto: CreditNoteDto): Promise<CFDI>;
// Reportes
@Get('report/monthly')
getMonthlyReport(@Query() filters: ReportFilters): Promise<CFDIReport>;
}
// API Publica - Autofactura
@Controller('autofactura')
export class AutofacturaController {
@Get('validate/:ticketNumber')
validateTicket(@Param('ticketNumber') ticketNumber: string): Promise<TicketValidation>;
@Post('generate')
generate(@Body() dto: AutofacturaDto): Promise<CFDI>;
@Get('download/:uuid')
download(@Param('uuid') uuid: string): Promise<{ xml: string; pdf: Buffer }>;
}
```
---
## 4. INTEGRACION PAC
### 4.1 Proveedores Soportados
```typescript
interface PACProvider {
name: string;
timbrar(xml: string): Promise<TimbradoResult>;
consultar(uuid: string): Promise<ConsultaResult>;
cancelar(uuid: string, motivo: string): Promise<CancelResult>;
}
// Implementaciones
class FinkokPAC implements PACProvider {
private readonly wsdlUrl = 'https://demo-facturacion.finkok.com/servicios/soap/stamp.wsdl';
// ...
}
class FacturamaPAC implements PACProvider {
private readonly apiUrl = 'https://api.facturama.mx/3/cfdis';
// ...
}
class SWsapienPAC implements PACProvider {
private readonly apiUrl = 'https://services.test.sw.com.mx/cfdi40/issue';
// ...
}
```
### 4.2 Configuracion
```yaml
cfdi_config:
pac:
primary: "finkok"
backup: "facturama"
timeout: 10000 # 10 segundos
retries: 3
emisor:
rfc: "XAXX010101000" # Configurable por tenant
nombre: "EMPRESA DEMO SA DE CV"
regimen: "601"
cp: "06600"
certificados:
cer_path: "/certs/{tenant}/cer.cer"
key_path: "/certs/{tenant}/key.key"
key_password: "${CFDI_KEY_PASSWORD}"
almacenamiento:
xml_path: "/storage/cfdi/{tenant}/{year}/{month}/"
retention_years: 5
```
---
## 5. FLUJOS DE NEGOCIO
### 5.1 Facturacion en POS
```
1. Cliente solicita factura al cerrar venta
2. Capturar datos fiscales:
- RFC
- Nombre o Razon Social
- Regimen Fiscal
- Uso CFDI
- CP Domicilio Fiscal
3. Validar RFC contra lista SAT (opcional)
4. Construir XML CFDI 4.0
5. Firmar con certificado
6. Enviar a PAC para timbrado
7. Si exito:
a. Guardar XML timbrado
b. Generar PDF
c. Enviar por email
d. Imprimir (opcional)
8. Si fallo:
a. Reintentar con PAC backup
b. Si falla: marcar para reintento posterior
```
### 5.2 Autofactura
```
1. Cliente accede al portal publico
2. Ingresa numero de ticket
3. Sistema valida:
- Ticket existe
- No esta facturado
- Dentro de plazo (30 dias)
4. Muestra detalle de compra
5. Cliente ingresa datos fiscales
6. Genera y timbra CFDI
7. Descarga XML y PDF
```
### 5.3 Cancelacion
```
1. Solicitar cancelacion
2. Validar:
- Dentro de plazo (30 dias)
- No tiene pagos aplicados
3. Seleccionar motivo:
- 01: Con documento relacionado (sustitucion)
- 02: Sin documento relacionado
- 03: No se llevo a cabo
- 04: Error en datos
4. Enviar solicitud a PAC
5. Si requiere aceptacion receptor:
- Esperar aceptacion
6. Confirmar cancelacion
```
---
## 6. TABLAS DDL
### 6.1 Tablas Nuevas
```sql
-- Configuracion CFDI por tenant
CREATE TABLE retail.cfdi_config (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) UNIQUE,
emisor_rfc VARCHAR(13) NOT NULL,
emisor_nombre VARCHAR(255) NOT NULL,
emisor_regimen VARCHAR(3) NOT NULL,
emisor_cp VARCHAR(5) NOT NULL,
pac_provider VARCHAR(20) NOT NULL DEFAULT 'finkok',
pac_user VARCHAR(100),
pac_password_encrypted TEXT,
cer_path TEXT,
key_path TEXT,
key_password_encrypted TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ
);
-- CFDIs emitidos
CREATE TABLE retail.cfdis (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id),
-- Relacion origen
source_type VARCHAR(20) NOT NULL, -- pos_order, ecommerce_order
source_id UUID NOT NULL,
-- Datos comprobante
serie VARCHAR(10),
folio VARCHAR(20),
uuid VARCHAR(36), -- UUID del SAT
fecha_emision TIMESTAMPTZ NOT NULL,
tipo_comprobante CHAR(1) NOT NULL, -- I, E, T, N, P
forma_pago VARCHAR(2),
metodo_pago VARCHAR(3),
-- Receptor
receptor_rfc VARCHAR(13) NOT NULL,
receptor_nombre VARCHAR(255) NOT NULL,
receptor_regimen VARCHAR(3),
receptor_cp VARCHAR(5),
uso_cfdi VARCHAR(4),
-- Totales
subtotal DECIMAL(12,2) NOT NULL,
descuento DECIMAL(12,2) DEFAULT 0,
total_impuestos DECIMAL(12,2) NOT NULL,
total DECIMAL(12,2) NOT NULL,
-- Estado
status VARCHAR(20) NOT NULL DEFAULT 'vigente', -- vigente, cancelado
cancel_date TIMESTAMPTZ,
cancel_reason VARCHAR(2),
-- Archivos
xml_content TEXT,
xml_path TEXT,
pdf_path TEXT,
-- Timbre
fecha_timbrado TIMESTAMPTZ,
rfc_pac VARCHAR(13),
sello_cfd TEXT,
sello_sat TEXT,
no_certificado_sat VARCHAR(20),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ,
UNIQUE(tenant_id, uuid)
);
-- Indices
CREATE INDEX idx_cfdis_source ON retail.cfdis(source_type, source_id);
CREATE INDEX idx_cfdis_uuid ON retail.cfdis(uuid);
CREATE INDEX idx_cfdis_fecha ON retail.cfdis(fecha_emision);
CREATE INDEX idx_cfdis_receptor ON retail.cfdis(receptor_rfc);
```
---
## 7. DEPENDENCIAS
### 7.1 Dependencias de Core
| Modulo | Estado | Requerido Para |
|--------|--------|---------------|
| MGN-010 Financial | 70% | Facturas base |
### 7.2 Dependencias de Retail
| Modulo | Tipo |
|--------|------|
| RT-001 Fundamentos | Prerequisito |
| RT-002 POS | Origen de facturas |
| RT-009 E-commerce | Origen de facturas |
### 7.3 Dependencias Externas
| Servicio | Proposito |
|----------|-----------|
| PAC (Finkok, Facturama) | Timbrado |
| SAT | Validacion RFC (opcional) |
---
## 8. CRITERIOS DE ACEPTACION
### 8.1 Funcionales
- [ ] Generar factura desde POS
- [ ] Generar factura publico general
- [ ] Timbrar en < 5 segundos
- [ ] Retry automatico con PAC backup
- [ ] Generar PDF
- [ ] Enviar por email
- [ ] Portal de autofactura
- [ ] Cancelar CFDI
- [ ] Generar nota de credito
- [ ] Almacenar XMLs 5 anos
### 8.2 Compliance
- [ ] CFDI 4.0 valido
- [ ] Catalogo SAT actualizado
- [ ] Certificados vigentes
- [ ] Timbre valido
---
## 9. ESTIMACION DETALLADA
| Componente | SP Backend | SP Frontend | Total |
|------------|-----------|-------------|-------|
| Entities + Migrations | 3 | - | 3 |
| CFDIService | 5 | - | 5 |
| CFDIBuilderService | 5 | - | 5 |
| PACService | 5 | - | 5 |
| XMLService | 3 | - | 3 |
| PDFService | 2 | - | 2 |
| AutofacturaService | 3 | - | 3 |
| Controllers | 3 | - | 3 |
| Autofactura Portal | - | 4 | 4 |
| Config UI | - | 2 | 2 |
| **TOTAL** | **29** | **6** | **35** |
---
## 10. CATALOGOS SAT REQUERIDOS
| Catalogo | Uso |
|----------|-----|
| c_FormaPago | 01 Efectivo, 04 Tarjeta, etc. |
| c_MetodoPago | PUE, PPD |
| c_UsoCFDI | G01, G03, etc. |
| c_RegimenFiscal | 601, 612, etc. |
| c_ClaveProdServ | Claves de productos |
| c_ClaveUnidad | E48, H87, etc. |
| c_TipoDeComprobante | I, E, T, N, P |
| c_Impuesto | 002 IVA |
| c_TasaOCuota | 0.160000, 0.000000 |
| c_Moneda | MXN, USD |
---
**Estado:** ANALISIS COMPLETO
**Bloqueado por:** RT-001, RT-002 o RT-009