Saltar al contenido principal

RPAfelApi Enhancements

Date: 2025-01-21
Status: Implemented

Overview

This document describes the enhancements made to the RPAfelApi integration based on the official API documentation.

New Features

1. GetToken Endpoint Support ✅

Implementation: ProviderRpaFelApiService.getToken()

  • Purpose: Retrieve authentication tokens from RPAfelApi
  • Caching: Tokens are cached with expiration tracking
  • Auto-refresh: Tokens are refreshed 5 minutes before expiration
  • Usage:
const provider = providerService.getProvider("rpafelapi");
const token = await provider.getToken(userName, password);

Benefits:

  • Reduces API calls by caching tokens
  • Automatic token refresh
  • Better error handling

2. Void Certificate Endpoint ✅

Implementation: ProviderRpaFelApiService.voidCertificate()

  • Purpose: Cancel/void existing certificates
  • Endpoint: POST /api/fel/voidCertificate
  • Usage:
const voidRequest: RpaFelApiVoidRequest = {
NumeroDocumentoAAnular: "A-123456",
NITEmisor: "44653948",
IDReceptor: "49862952",
FechaEmisionDocumentoAnular: "2024-01-15T10:30:00",
FechaHoraAnulacion: "2024-01-15T11:00:00",
MotivoAnulacion: "Error en facturación",
Gface: "Digifact",
rpaCertificador_Usuario: "GT.000044653948.RPA_TEST"
};

const result = await provider.voidCertificate(voidRequest, token);

3. Email Notification Endpoint ✅

Implementation: ProviderRpaFelApiService.sendEmail()

  • Purpose: Queue email notifications for certificates
  • Endpoint: POST /api/fel/mailFel
  • Usage:
const mailRequest: RpaFelApiMailRequest = {
rpaUUID: "550e8400-e29b-41d4-a716-446655440000",
emails: ["customer@example.com", "accounting@example.com"]
};

const result = await provider.sendEmail(mailRequest);

4. Enhanced Error Handling ✅

Features:

  • Retry Logic: Automatic retry with exponential backoff
  • Transient Failure Handling: Retries on 401, 406, and 5xx errors
  • Better Logging: Structured logging with context
  • Error Preservation: Full error details preserved for upstream handlers

Configuration:

  • Max retries: 3
  • Initial delay: 1 second
  • Exponential backoff: 2^attempt

5. Special Case Handling ✅

Tip (Propina) Support

  • Detection: Automatically detects tip items by name ("PROPINA" or "TIP")
  • Flag: Sets PropinaAdenda: "1" in extra object when tip is detected
  • Implementation: XmlToDteJsonService.hasTipItem()

CUI Identification Type

  • Support: Handles CUI identification via TipoEspecial field
  • Mapping: receiverData.taxpayerTypeextra.TipoEspecial

Special NIT Phrase Handling

  • Detection: Identifies special NITs that require additional phrases
  • Special NITs: 87605473, 96167416, 11700207K, 14945908
  • Implementation: ProviderRpaFelApiService.requiresSpecialPhrase()

6. Token Caching ✅

Features:

  • In-memory cache with expiration tracking
  • Automatic cache invalidation
  • Per-user token caching
  • Cache clearing utility

Cache Structure:

interface CachedToken {
token: string;
expiresAt: Date;
userName: string;
}

Updated Interfaces

New Types

// Token Management
interface RpaFelApiTokenRequest {
UserName: string;
Password: string;
}

interface RpaFelApiTokenResponse {
Success: boolean;
response: {
token: string;
expira_en: string;
otorgado_a: string;
};
}

// Void Certificate
interface RpaFelApiVoidRequest {
NumeroDocumentoAAnular: string;
NITEmisor: string;
IDReceptor: string;
FechaEmisionDocumentoAnular: string;
FechaHoraAnulacion: string;
MotivoAnulacion: string;
Gface: string;
rpaCertificador_Usuario: string;
}

interface RpaFelApiVoidResponse {
ok: boolean;
voidID?: string;
data?: { /* ... */ };
}

// Email
interface RpaFelApiMailRequest {
rpaUUID: string;
emails: string[];
}

interface RpaFelApiMailResponse {
id: string;
}

Enhanced DTE JSON

interface DteJson {
// ... existing fields
extra?: {
subDomain?: string;
TipoEspecial?: string;
PropinaAdenda?: string; // NEW: Tip flag
};
}

Usage Examples

Complete Workflow

// 1. Get token (with caching)
const provider = providerService.getProvider("rpafelapi");
const token = await provider.getToken(userName, password);

// 2. Generate certificate
const dteJson = xmlToDteJsonService.convertInvoiceToDteJson(invoice, rpaUUID);
const certificate = await provider.certifyDocument({
taxId,
xmlContent: JSON.stringify(dteJson),
apiUrl: "",
token
});

// 3. Send email notification
await provider.sendEmail({
rpaUUID: certificate.rpaUUID,
emails: ["customer@example.com"]
});

// 4. Void certificate (if needed)
await provider.voidCertificate({
NumeroDocumentoAAnular: certificate.Autorizacion,
NITEmisor: taxId,
IDReceptor: receiverTaxId,
FechaEmisionDocumentoAnular: certificate.Fecha_DTE,
FechaHoraAnulacion: new Date().toISOString(),
MotivoAnulacion: "Error en facturación",
Gface: "Digifact",
rpaCertificador_Usuario: userName
}, token);

Tip Handling

// Invoice with tip item
const invoice: Invoice = {
// ... other fields
items: [
{
name: "Meal",
// ... other item fields
},
{
name: "PROPINA", // Tip item detected automatically
// ... other item fields
}
]
};

// PropinaAdenda flag is automatically set to "1"
const dteJson = xmlToDteJsonService.convertInvoiceToDteJson(invoice, rpaUUID);
// dteJson.extra.PropinaAdenda === "1"

CUI Identification

const invoice: Invoice = {
// ... other fields
receiverData: {
taxId: "2260269730101", // CUI format
taxName: "Customer Name",
taxpayerType: "CUI", // Set to CUI
// ... other fields
}
};

// TipoEspecial is automatically set in extra
const dteJson = xmlToDteJsonService.convertInvoiceToDteJson(invoice, rpaUUID);
// dteJson.extra.TipoEspecial === "CUI"

Error Handling

Retry Logic

The service automatically retries failed requests with exponential backoff:

// Automatic retry on transient failures
try {
const result = await provider.certifyDocument({ /* ... */ });
} catch (error) {
// Retries automatically on:
// - 401 Unauthorized (token refresh)
// - 406 Not Acceptable (already signed)
// - 5xx Server errors
// Does NOT retry on:
// - 400 Bad Request (client error)
// - 403 Forbidden (authorization error)
}

Error Response Structure

// Enhanced error object
{
message: string;
response?: {
status: number;
statusText: string;
data: any;
};
responseData?: any; // Full error response from API
}

Configuration

Environment Variables

# RPAfelApi URL (optional, defaults based on NODE_ENV)
RPA_FEL_API_URL=https://fel.rpapos.com/api/fel

# For development
RPA_FEL_API_URL=https://fel-dev.rpapos.com/api/fel

Retry Configuration

Currently hardcoded but can be made configurable:

private readonly maxRetries = 3;
private readonly retryDelay = 1000; // 1 second

Testing

Unit Tests

All new methods should have unit tests covering:

  • Token caching and expiration
  • Retry logic
  • Error handling
  • Special case detection

Integration Tests

Test scenarios:

  1. Token retrieval and caching
  2. Certificate generation with retry
  3. Void certificate flow
  4. Email notification
  5. Tip detection
  6. CUI identification
  7. Special NIT phrase handling

Migration Notes

Breaking Changes

None - all changes are backward compatible.

Deprecations

  • Direct password usage in Authorization header (still works, but GetToken is preferred)

Recommendations

  1. Use GetToken: Always use getToken() instead of passing password directly
  2. Handle Errors: Implement proper error handling for retry scenarios
  3. Monitor Cache: Clear token cache if authentication issues occur
  4. Use Email Endpoint: Use sendEmail() for better email delivery tracking

Future Enhancements

  1. GetSignedCertificate Endpoint: Implement retrieval of signed certificates
  2. Pub/Sub Integration: Subscribe to certification events
  3. Configurable Retry: Make retry parameters configurable
  4. Token Refresh Background Job: Automatic token refresh before expiration
  5. Metrics/Monitoring: Add metrics for API calls, cache hits, retries

References


Last Updated: 2025-01-21
Maintained By: FEL Team