526 lines
12 KiB
Markdown
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
|