Saltar al contenido principal

RPAfelApi Integration - Required Updates Analysis

📊 Current State Analysis

✅ What's Already Good

  1. FelController - NO CHANGES NEEDED

    • Accepts Invoice object (works for all document types)
    • Calls felService.certifyDocument (service handles routing)
    • Error handling is solid
    • Keep as-is for now
  2. Database Migration - GOOD

    • Tables for credit_note, debit_note, fel_cancellation exist
    • Proper indexes and relationships
    • FEL fields included
    • No changes needed
  3. Architecture - SOLID

    • Clean separation: Controller → Service → Provider
    • Event-driven design
    • Structure is good

🔧 Required Updates

1. Invoice Interface - NEEDS EXTENSION ⚠️

Current Issue:

  • Only supports type: "FACT"
  • Missing fields for NCRE, NDEB, ANULACION

Required Changes:

// apps/backend/src/fel/domain/fel.interface.ts

// Add union type for document types
export type FelDocumentType = 'FACT' | 'NCRE' | 'NDEB' | 'ANULACION';

// Extend Invoice interface
export interface Invoice {
// ... existing fields ...

generalData: {
type: FelDocumentType; // Changed from string
dateTimeIssue: string;
currencyCode: string;
};

// Add optional fields for NCRE/NDEB/ANULACION
originalInvoiceUuid?: string; // Required for NCRE, NDEB, ANULACION
adjustmentReason?: string; // Required for NCRE, NDEB
cancellationReason?: string; // Required for ANULACION
cancellationDate?: string; // For ANULACION
originalInvoiceDate?: string; // For ANULACION
}

Why:

  • RPAfelApi expects these fields in DTE JSON
  • Database tables already have these fields
  • Need to support all document types

2. FelService - NEEDS ROUTING LOGIC ⚠️

Current Issue:

  • Always converts to XML
  • Always uses direct certifiers
  • No RPAfelApi path

Required Changes:

// apps/backend/src/fel/application/fel.service.ts

async certifyDocument({
taxId,
document,
}: ICertifyDocumentParameters): Promise<undefined> {
const { businessData, felProviderData } = document;

try {
// Step 1: Fetch business data
const business = await this.businessesRepository.findById(businessData.id);
if (!business) {
throw new Error('Business not found');
}

// Step 2: Check if using RPAfelApi
const useRpaFelApi =
process.env.USE_RPA_FEL_API === 'true' ||
felProviderData.providerName === 'rpafelapi';

if (useRpaFelApi) {
return await this.certifyViaRpaFelApi(document, business, taxId);
}

// Step 3: Use direct certifier (existing logic)
// ... existing code continues ...
} catch (error) {
// ... existing error handling ...
}
}

private async certifyViaRpaFelApi(
document: Invoice,
business: SelectableBusiness,
taxId: string
): Promise<undefined> {
// Extract certifier config
const { felCertifier, encryptedFelToken } =
this.extractFelCertifierConfig(business.felCertifierConfig);

// Get certifier credentials
const certifierUser = this.getCertifierUser(business, felCertifier);
const certifierPassword = this.cryptoService.decrypt(encryptedFelToken);

// Convert Invoice to DTE JSON (not XML!)
const rpaUUID = document.addendumData.internalReference; // sale.id
const dteJson = this.xmlToDteJsonService.convertInvoiceToDteJson(
document,
rpaUUID
);

// Add certifier credentials to DTE JSON
dteJson.DatosEmision.DatosGenerales.rpaCertificador_Usuario = certifierUser;
dteJson.DatosEmision.DatosGenerales.rpaCertificador_Clave = certifierPassword;

// Get RPAfelApi provider
const provider = this.providerService.getProvider('rpafelapi');

// Certify via RPAfelApi
const result = await provider.certifyDocument({
taxId,
xmlContent: '', // Not needed for RPAfelApi
apiUrl: '', // Not needed
token: '', // RPAfelApi handles auth internally via DTE JSON
});

return result;
}

Why:

  • Need to route to RPAfelApi when enabled
  • RPAfelApi uses DTE JSON, not XML
  • Keep existing direct certifier path

3. ProviderService - NEEDS RPAfelApi PROVIDER ⚠️

Current Issue:

  • Only has digifact and infile
  • No rpafelapi provider

Required Changes:

// apps/backend/src/fel/application/provider.service.ts

import { ProviderRpaFelApiService } from '@/fel/infrastructure/provider-rpafelapi.service';

@Injectable()
export class ProviderService {
constructor(
private readonly providerDigifactService: ProviderDigifactService,
private readonly providerInfileService: ProviderInfileService,
private readonly providerRpaFelApiService: ProviderRpaFelApiService, // Add this
) {
this.providerMap = {
digifact: this.providerDigifactService,
infile: this.providerInfileService,
rpafelapi: this.providerRpaFelApiService, // Add this
};
}
}

Why:

  • Need to register RPAfelApi provider
  • ProviderService routes to correct provider

4. New Services Needed - CREATE NEW FILES ⚠️

A. ProviderRpaFelApiService

File: apps/backend/src/fel/infrastructure/provider-rpafelapi.service.ts

Purpose:

  • HTTP client for RPAfelApi
  • Converts DTE JSON to RPAfelApi format
  • Transforms responses

Status: Need to create (see implementation guide)

B. XmlToDteJsonService

File: apps/backend/src/fel/application/xml-to-dte-json.service.ts

Purpose:

  • Converts Invoice object to DTE JSON structure
  • Handles all document types (FACT, NCRE, NDEB, ANULACION)
  • Maps fields correctly

Status: Need to create (see implementation guide)


5. FelModule - NEEDS NEW PROVIDERS ⚠️

Required Changes:

// apps/backend/src/fel/fel.modules.ts

import { ProviderRpaFelApiService } from '@/fel/infrastructure/provider-rpafelapi.service';
import { XmlToDteJsonService } from '@/fel/application/xml-to-dte-json.service';

@Module({
// ... existing imports ...
providers: [
FelService,
ProviderService,
XmlConversionService,
XmlToDteJsonService, // Add this
ProviderDigifactService,
ProviderInfileService,
ProviderRpaFelApiService, // Add this
],
// ...
})
export class FelModule {}

Why:

  • Register new services
  • Dependency injection

1. New Controller Endpoints - OPTIONAL 💡

Current: Controller works fine for basic certification

Could Add:

  • POST /fel/void-certificate - Void a certificate
  • POST /fel/query-payer-info - Query payer information
  • POST /fel/send-email - Send FEL document via email

Why Optional:

  • RPAfelApi has these endpoints
  • But you might not need them in FlowPOS
  • Can add later if needed

Example:

// apps/backend/src/fel/interfaces/fel.controller.ts

@Post('void-certificate')
async voidCertificate(@Body() request: VoidCertificateDto): Promise<any> {
// Call RPAfelApi void endpoint
// Or implement directly
}

@Post('query-payer-info')
async queryPayerInfo(@Body() request: QueryPayerInfoDto): Promise<any> {
// Call RPAfelApi query endpoint
// Or implement directly
}

Current: Basic Invoice interface

Could Add:

  • Separate interfaces for each document type
  • Better type safety

Example:

// Base interface
export interface BaseFelDocument {
businessData: { id: string };
felProviderData: { providerName: string };
generalData: { type: FelDocumentType; dateTimeIssue: string; currencyCode: string };
issuerData: { /* ... */ };
receiverData: { /* ... */ };
phrases: Phrase[];
addendumData: { /* ... */ };
}

// Specific interfaces
export interface Invoice extends BaseFelDocument {
generalData: { type: 'FACT'; /* ... */ };
items: InvoiceItem[];
total: number;
}

export interface CreditNote extends BaseFelDocument {
generalData: { type: 'NCRE'; /* ... */ };
originalInvoiceUuid: string;
adjustmentReason: string;
items: InvoiceItem[];
total: number;
}

export interface DebitNote extends BaseFelDocument {
generalData: { type: 'NDEB'; /* ... */ };
originalInvoiceUuid: string;
adjustmentReason: string;
items: InvoiceItem[];
total: number;
}

export interface Cancellation extends BaseFelDocument {
generalData: { type: 'ANULACION'; /* ... */ };
originalInvoiceUuid: string;
cancellationReason: string;
cancellationDate: string;
originalInvoiceDate: string;
}

// Union type
export type FelDocument = Invoice | CreditNote | DebitNote | Cancellation;

Why Optional:

  • More type safety
  • Better IDE support
  • Clearer intent
  • But adds complexity

📋 Summary: Required vs Optional

✅ Required Updates

  1. Invoice Interface - Add optional fields for NCRE/NDEB/ANULACION
  2. FelService - Add routing logic for RPAfelApi
  3. ProviderService - Register RPAfelApi provider
  4. ProviderRpaFelApiService - Create new service
  5. XmlToDteJsonService - Create new service
  6. FelModule - Register new services

💡 Optional Enhancements

  1. New Controller Endpoints - Void, query, email
  2. Extended Interfaces - Separate types for each document
  3. Validation Service - SAT rules validation
  4. Cache Service - (RPAfelApi handles this, but could add local cache)

🎯 Answer to Your Question

"Do we need to update the logic or structures?"

YES, but minimal:

  1. Controller - ✅ NO CHANGES (works fine as-is)
  2. Invoice Interface - ⚠️ MINOR UPDATE (add optional fields)
  3. FelService - ⚠️ ADD ROUTING (new method for RPAfelApi)
  4. ProviderService - ⚠️ REGISTER PROVIDER (one line)
  5. New Services - ⚠️ CREATE 2 NEW FILES (provider + converter)
  6. FelModule - ⚠️ REGISTER SERVICES (add to providers array)

"The fel.controller is currently working fine. Do you think it needs to be modified or updated?"

NO, controller is fine!

Why:

  • It accepts Invoice object (works for all document types)
  • It calls felService.certifyDocument (service handles routing)
  • Service layer abstraction means controller doesn't need to know about RPAfelApi
  • Error handling is already good

Only add new endpoints if you need:

  • Void certificate functionality
  • Query payer info
  • Send email

🚀 Implementation Priority

Phase 1: Core Integration (Required)

  1. ✅ Extend Invoice interface
  2. ✅ Create ProviderRpaFelApiService
  3. ✅ Create XmlToDteJsonService
  4. ✅ Update FelService with routing
  5. ✅ Update ProviderService
  6. ✅ Update FelModule

Phase 2: Testing

  1. ✅ Test with FACT documents
  2. ✅ Test with NCRE documents
  3. ✅ Test with NDEB documents
  4. ✅ Test with ANULACION documents

Phase 3: Optional Enhancements

  1. 💡 Add new controller endpoints (if needed)
  2. 💡 Add extended interfaces (if wanted)
  3. 💡 Add validation service (if needed)

💡 Key Insight

The beauty of your architecture:

  • Controller doesn't need to change because service layer handles routing
  • Database is already ready (migration done)
  • Just need to add RPAfelApi as another provider option
  • Existing code continues to work

This is a clean integration! 🎉


Last Updated: 2025-12-18
Status: Analysis Complete - Ready for Implementation