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
import { InvoicesService } from '@erp-core/financial';
import { PaymentsService } from '@erp-core/financial';
import { PartnersService } from '@erp-core/core';
2.3 Servicios a Extender
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
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
@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
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
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
-- 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
8.2 Compliance
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