feat: use @nodecfdi/sat-ws-descarga-masiva for SAT sync
Replace manual SOAP authentication with the official nodecfdi library which properly handles WS-Security signatures for SAT web services. - Add sat-client.service.ts using Fiel.create() for authentication - Update sat.service.ts to use new client - Update fiel.service.ts to return raw certificate data Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
"@horux/shared": "workspace:*",
|
"@horux/shared": "workspace:*",
|
||||||
"@nodecfdi/cfdi-core": "^1.0.1",
|
"@nodecfdi/cfdi-core": "^1.0.1",
|
||||||
"@nodecfdi/credentials": "^3.2.0",
|
"@nodecfdi/credentials": "^3.2.0",
|
||||||
|
"@nodecfdi/sat-ws-descarga-masiva": "^2.0.0",
|
||||||
"@prisma/client": "^5.22.0",
|
"@prisma/client": "^5.22.0",
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
|
|||||||
@@ -179,22 +179,24 @@ export async function deleteFiel(tenantId: string): Promise<boolean> {
|
|||||||
* Solo debe usarse internamente por el servicio de SAT
|
* Solo debe usarse internamente por el servicio de SAT
|
||||||
*/
|
*/
|
||||||
export async function getDecryptedFiel(tenantId: string): Promise<{
|
export async function getDecryptedFiel(tenantId: string): Promise<{
|
||||||
credential: Credential;
|
cerContent: string;
|
||||||
|
keyContent: string;
|
||||||
|
password: string;
|
||||||
rfc: string;
|
rfc: string;
|
||||||
} | null> {
|
} | null> {
|
||||||
const fiel = await prisma.fielCredential.findUnique({
|
const fiel = await prisma.fielCredential.findUnique({
|
||||||
where: { tenantId },
|
where: { tenantId },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!fiel || !fiel.isActive) {
|
if (!fiel || !fiel.isActive) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verificar que no esté vencida
|
// Verificar que no esté vencida
|
||||||
if (new Date() > fiel.validUntil) {
|
if (new Date() > fiel.validUntil) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Desencriptar todas las credenciales juntas
|
// Desencriptar todas las credenciales juntas
|
||||||
const { cerData, keyData, password } = decryptFielCredentials(
|
const { cerData, keyData, password } = decryptFielCredentials(
|
||||||
@@ -205,15 +207,10 @@ export async function getDecryptedFiel(tenantId: string): Promise<{
|
|||||||
Buffer.from(fiel.encryptionTag)
|
Buffer.from(fiel.encryptionTag)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Crear credencial
|
|
||||||
const credential = Credential.create(
|
|
||||||
cerData.toString('binary'),
|
|
||||||
keyData.toString('binary'),
|
|
||||||
password
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
credential,
|
cerContent: cerData.toString('binary'),
|
||||||
|
keyContent: keyData.toString('binary'),
|
||||||
|
password,
|
||||||
rfc: fiel.rfc,
|
rfc: fiel.rfc,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
203
apps/api/src/services/sat/sat-client.service.ts
Normal file
203
apps/api/src/services/sat/sat-client.service.ts
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
import {
|
||||||
|
Fiel,
|
||||||
|
HttpsWebClient,
|
||||||
|
FielRequestBuilder,
|
||||||
|
Service,
|
||||||
|
QueryParameters,
|
||||||
|
DateTimePeriod,
|
||||||
|
DownloadType,
|
||||||
|
RequestType,
|
||||||
|
ServiceEndpoints,
|
||||||
|
} from '@nodecfdi/sat-ws-descarga-masiva';
|
||||||
|
|
||||||
|
export interface FielData {
|
||||||
|
cerContent: string;
|
||||||
|
keyContent: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea el servicio de descarga masiva del SAT usando los datos de la FIEL
|
||||||
|
*/
|
||||||
|
export function createSatService(fielData: FielData): Service {
|
||||||
|
// Crear FIEL usando el método estático create
|
||||||
|
const fiel = Fiel.create(fielData.cerContent, fielData.keyContent, fielData.password);
|
||||||
|
|
||||||
|
// Verificar que la FIEL sea válida
|
||||||
|
if (!fiel.isValid()) {
|
||||||
|
throw new Error('La FIEL no es válida o está vencida');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear cliente HTTP
|
||||||
|
const webClient = new HttpsWebClient();
|
||||||
|
|
||||||
|
// Crear request builder con la FIEL
|
||||||
|
const requestBuilder = new FielRequestBuilder(fiel);
|
||||||
|
|
||||||
|
// Crear y retornar el servicio
|
||||||
|
return new Service(requestBuilder, webClient, undefined, ServiceEndpoints.cfdi());
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface QueryResult {
|
||||||
|
success: boolean;
|
||||||
|
requestId?: string;
|
||||||
|
message: string;
|
||||||
|
statusCode?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VerifyResult {
|
||||||
|
success: boolean;
|
||||||
|
status: 'pending' | 'processing' | 'ready' | 'failed' | 'rejected';
|
||||||
|
packageIds: string[];
|
||||||
|
totalCfdis: number;
|
||||||
|
message: string;
|
||||||
|
statusCode?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DownloadResult {
|
||||||
|
success: boolean;
|
||||||
|
packageContent: string; // Base64 encoded ZIP
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Realiza una consulta al SAT para solicitar CFDIs
|
||||||
|
*/
|
||||||
|
export async function querySat(
|
||||||
|
service: Service,
|
||||||
|
fechaInicio: Date,
|
||||||
|
fechaFin: Date,
|
||||||
|
tipo: 'emitidos' | 'recibidos',
|
||||||
|
requestType: 'metadata' | 'cfdi' = 'cfdi'
|
||||||
|
): Promise<QueryResult> {
|
||||||
|
try {
|
||||||
|
const period = DateTimePeriod.createFromValues(
|
||||||
|
formatDateForSat(fechaInicio),
|
||||||
|
formatDateForSat(fechaFin)
|
||||||
|
);
|
||||||
|
|
||||||
|
const downloadType = new DownloadType(tipo === 'emitidos' ? 'issued' : 'received');
|
||||||
|
const reqType = new RequestType(requestType === 'cfdi' ? 'xml' : 'metadata');
|
||||||
|
|
||||||
|
const parameters = QueryParameters.create(period, downloadType, reqType);
|
||||||
|
const result = await service.query(parameters);
|
||||||
|
|
||||||
|
if (!result.getStatus().isAccepted()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: result.getStatus().getMessage(),
|
||||||
|
statusCode: result.getStatus().getCode().toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
requestId: result.getRequestId(),
|
||||||
|
message: 'Solicitud aceptada',
|
||||||
|
statusCode: result.getStatus().getCode().toString(),
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('[SAT Query Error]', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: error.message || 'Error al realizar consulta',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica el estado de una solicitud
|
||||||
|
*/
|
||||||
|
export async function verifySatRequest(
|
||||||
|
service: Service,
|
||||||
|
requestId: string
|
||||||
|
): Promise<VerifyResult> {
|
||||||
|
try {
|
||||||
|
const result = await service.verify(requestId);
|
||||||
|
|
||||||
|
const statusCode = result.getStatusRequest().getValue();
|
||||||
|
let status: VerifyResult['status'];
|
||||||
|
|
||||||
|
// Los valores del SAT para estado de solicitud (getValue retorna número o string)
|
||||||
|
const codeNum = typeof statusCode === 'string' ? parseInt(statusCode, 10) : statusCode;
|
||||||
|
switch (codeNum) {
|
||||||
|
case 1:
|
||||||
|
status = 'pending';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
status = 'processing';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
status = 'ready';
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
status = 'failed';
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
status = 'rejected';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
status = 'pending';
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: result.getStatus().isAccepted(),
|
||||||
|
status,
|
||||||
|
packageIds: result.getPackageIds(),
|
||||||
|
totalCfdis: result.getNumberCfdis(),
|
||||||
|
message: result.getStatus().getMessage(),
|
||||||
|
statusCode: result.getStatus().getCode().toString(),
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('[SAT Verify Error]', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 'failed',
|
||||||
|
packageIds: [],
|
||||||
|
totalCfdis: 0,
|
||||||
|
message: error.message || 'Error al verificar solicitud',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Descarga un paquete de CFDIs
|
||||||
|
*/
|
||||||
|
export async function downloadSatPackage(
|
||||||
|
service: Service,
|
||||||
|
packageId: string
|
||||||
|
): Promise<DownloadResult> {
|
||||||
|
try {
|
||||||
|
const result = await service.download(packageId);
|
||||||
|
|
||||||
|
if (!result.getStatus().isAccepted()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
packageContent: '',
|
||||||
|
message: result.getStatus().getMessage(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
packageContent: result.getPackageContent(),
|
||||||
|
message: 'Paquete descargado',
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('[SAT Download Error]', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
packageContent: '',
|
||||||
|
message: error.message || 'Error al descargar paquete',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formatea una fecha para el SAT (YYYY-MM-DD HH:mm:ss)
|
||||||
|
*/
|
||||||
|
function formatDateForSat(date: Date): string {
|
||||||
|
const pad = (n: number) => n.toString().padStart(2, '0');
|
||||||
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +
|
||||||
|
`${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
||||||
|
}
|
||||||
@@ -1,44 +1,28 @@
|
|||||||
import { prisma } from '../../config/database.js';
|
import { prisma } from '../../config/database.js';
|
||||||
import { getDecryptedFiel } from '../fiel.service.js';
|
import { getDecryptedFiel } from '../fiel.service.js';
|
||||||
import { authenticate, isTokenValid } from './sat-auth.service.js';
|
|
||||||
import {
|
import {
|
||||||
requestDownload,
|
createSatService,
|
||||||
verifyRequest,
|
querySat,
|
||||||
downloadPackage,
|
verifySatRequest,
|
||||||
isRequestComplete,
|
downloadSatPackage,
|
||||||
isRequestFailed,
|
type FielData,
|
||||||
isRequestInProgress,
|
} from './sat-client.service.js';
|
||||||
SAT_REQUEST_STATES,
|
|
||||||
} from './sat-download.service.js';
|
|
||||||
import { processPackage, type CfdiParsed } from './sat-parser.service.js';
|
import { processPackage, type CfdiParsed } from './sat-parser.service.js';
|
||||||
import type { SatSyncJob, CfdiSyncType, SatSyncType } from '@horux/shared';
|
import type { SatSyncJob, CfdiSyncType, SatSyncType } from '@horux/shared';
|
||||||
import type { Credential } from '@nodecfdi/credentials/node';
|
import type { Service } from '@nodecfdi/sat-ws-descarga-masiva';
|
||||||
|
|
||||||
const POLL_INTERVAL_MS = 30000; // 30 segundos
|
const POLL_INTERVAL_MS = 30000; // 30 segundos
|
||||||
const MAX_POLL_ATTEMPTS = 60; // 30 minutos máximo
|
const MAX_POLL_ATTEMPTS = 60; // 30 minutos máximo
|
||||||
const YEARS_TO_SYNC = 10;
|
const YEARS_TO_SYNC = 10;
|
||||||
|
|
||||||
interface SyncContext {
|
interface SyncContext {
|
||||||
credential: Credential;
|
fielData: FielData;
|
||||||
token: string;
|
service: Service;
|
||||||
tokenExpiresAt: Date;
|
|
||||||
rfc: string;
|
rfc: string;
|
||||||
tenantId: string;
|
tenantId: string;
|
||||||
schemaName: string;
|
schemaName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtiene o renueva el token de autenticación
|
|
||||||
*/
|
|
||||||
async function ensureValidToken(ctx: SyncContext): Promise<void> {
|
|
||||||
if (!isTokenValid({ token: ctx.token, expiresAt: ctx.tokenExpiresAt })) {
|
|
||||||
console.log('[SAT] Renovando token...');
|
|
||||||
const newToken = await authenticate(ctx.credential);
|
|
||||||
ctx.token = newToken.token;
|
|
||||||
ctx.tokenExpiresAt = newToken.expiresAt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actualiza el progreso de un job
|
* Actualiza el progreso de un job
|
||||||
*/
|
*/
|
||||||
@@ -202,63 +186,52 @@ async function processDateRange(
|
|||||||
): Promise<{ found: number; downloaded: number; inserted: number; updated: number }> {
|
): Promise<{ found: number; downloaded: number; inserted: number; updated: number }> {
|
||||||
console.log(`[SAT] Procesando ${tipoCfdi} desde ${fechaInicio.toISOString()} hasta ${fechaFin.toISOString()}`);
|
console.log(`[SAT] Procesando ${tipoCfdi} desde ${fechaInicio.toISOString()} hasta ${fechaFin.toISOString()}`);
|
||||||
|
|
||||||
await ensureValidToken(ctx);
|
|
||||||
|
|
||||||
// 1. Solicitar descarga
|
// 1. Solicitar descarga
|
||||||
const requestResponse = await requestDownload({
|
const queryResult = await querySat(ctx.service, fechaInicio, fechaFin, tipoCfdi);
|
||||||
credential: ctx.credential,
|
|
||||||
token: ctx.token,
|
|
||||||
rfc: ctx.rfc,
|
|
||||||
fechaInicio,
|
|
||||||
fechaFin,
|
|
||||||
tipoSolicitud: 'CFDI',
|
|
||||||
tipoCfdi,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (requestResponse.codEstatus !== '5000') {
|
if (!queryResult.success) {
|
||||||
if (requestResponse.codEstatus === '5004') {
|
// Código 5004 = No hay CFDIs en el rango
|
||||||
|
if (queryResult.statusCode === '5004') {
|
||||||
console.log('[SAT] No se encontraron CFDIs en el rango');
|
console.log('[SAT] No se encontraron CFDIs en el rango');
|
||||||
return { found: 0, downloaded: 0, inserted: 0, updated: 0 };
|
return { found: 0, downloaded: 0, inserted: 0, updated: 0 };
|
||||||
}
|
}
|
||||||
throw new Error(`Error SAT: ${requestResponse.codEstatus} - ${requestResponse.mensaje}`);
|
throw new Error(`Error SAT: ${queryResult.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const idSolicitud = requestResponse.idSolicitud;
|
const requestId = queryResult.requestId!;
|
||||||
console.log(`[SAT] Solicitud creada: ${idSolicitud}`);
|
console.log(`[SAT] Solicitud creada: ${requestId}`);
|
||||||
|
|
||||||
await updateJobProgress(jobId, { satRequestId: idSolicitud });
|
await updateJobProgress(jobId, { satRequestId: requestId });
|
||||||
|
|
||||||
// 2. Esperar y verificar solicitud
|
// 2. Esperar y verificar solicitud
|
||||||
let verifyResponse;
|
let verifyResult;
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
|
|
||||||
while (attempts < MAX_POLL_ATTEMPTS) {
|
while (attempts < MAX_POLL_ATTEMPTS) {
|
||||||
await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL_MS));
|
await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL_MS));
|
||||||
attempts++;
|
attempts++;
|
||||||
|
|
||||||
await ensureValidToken(ctx);
|
verifyResult = await verifySatRequest(ctx.service, requestId);
|
||||||
verifyResponse = await verifyRequest(ctx.credential, ctx.token, ctx.rfc, idSolicitud);
|
console.log(`[SAT] Estado solicitud: ${verifyResult.status} (intento ${attempts})`);
|
||||||
|
|
||||||
console.log(`[SAT] Estado solicitud: ${verifyResponse.estadoSolicitud} (intento ${attempts})`);
|
if (verifyResult.status === 'ready') {
|
||||||
|
|
||||||
if (isRequestComplete(verifyResponse.estadoSolicitud)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRequestFailed(verifyResponse.estadoSolicitud)) {
|
if (verifyResult.status === 'failed' || verifyResult.status === 'rejected') {
|
||||||
throw new Error(`Solicitud fallida: ${verifyResponse.mensaje}`);
|
throw new Error(`Solicitud fallida: ${verifyResult.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!verifyResponse || !isRequestComplete(verifyResponse.estadoSolicitud)) {
|
if (!verifyResult || verifyResult.status !== 'ready') {
|
||||||
throw new Error('Timeout esperando respuesta del SAT');
|
throw new Error('Timeout esperando respuesta del SAT');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Descargar paquetes
|
// 3. Descargar paquetes
|
||||||
const packageIds = verifyResponse.paquetes;
|
const packageIds = verifyResult.packageIds;
|
||||||
await updateJobProgress(jobId, {
|
await updateJobProgress(jobId, {
|
||||||
satPackageIds: packageIds,
|
satPackageIds: packageIds,
|
||||||
cfdisFound: verifyResponse.numeroCfdis,
|
cfdisFound: verifyResult.totalCfdis,
|
||||||
});
|
});
|
||||||
|
|
||||||
let totalInserted = 0;
|
let totalInserted = 0;
|
||||||
@@ -269,11 +242,15 @@ async function processDateRange(
|
|||||||
const packageId = packageIds[i];
|
const packageId = packageIds[i];
|
||||||
console.log(`[SAT] Descargando paquete ${i + 1}/${packageIds.length}: ${packageId}`);
|
console.log(`[SAT] Descargando paquete ${i + 1}/${packageIds.length}: ${packageId}`);
|
||||||
|
|
||||||
await ensureValidToken(ctx);
|
const downloadResult = await downloadSatPackage(ctx.service, packageId);
|
||||||
const packageResponse = await downloadPackage(ctx.credential, ctx.token, ctx.rfc, packageId);
|
|
||||||
|
|
||||||
// 4. Procesar paquete
|
if (!downloadResult.success) {
|
||||||
const cfdis = processPackage(packageResponse.paquete);
|
console.error(`[SAT] Error descargando paquete ${packageId}: ${downloadResult.message}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Procesar paquete (el contenido viene en base64)
|
||||||
|
const cfdis = processPackage(downloadResult.packageContent);
|
||||||
totalDownloaded += cfdis.length;
|
totalDownloaded += cfdis.length;
|
||||||
|
|
||||||
console.log(`[SAT] Procesando ${cfdis.length} CFDIs del paquete`);
|
console.log(`[SAT] Procesando ${cfdis.length} CFDIs del paquete`);
|
||||||
@@ -293,7 +270,7 @@ async function processDateRange(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
found: verifyResponse.numeroCfdis,
|
found: verifyResult.totalCfdis,
|
||||||
downloaded: totalDownloaded,
|
downloaded: totalDownloaded,
|
||||||
inserted: totalInserted,
|
inserted: totalInserted,
|
||||||
updated: totalUpdated,
|
updated: totalUpdated,
|
||||||
@@ -408,11 +385,20 @@ export async function startSync(
|
|||||||
dateTo?: Date
|
dateTo?: Date
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
// Obtener credenciales FIEL
|
// Obtener credenciales FIEL
|
||||||
const fielData = await getDecryptedFiel(tenantId);
|
const decryptedFiel = await getDecryptedFiel(tenantId);
|
||||||
if (!fielData) {
|
if (!decryptedFiel) {
|
||||||
throw new Error('No hay FIEL configurada o está vencida');
|
throw new Error('No hay FIEL configurada o está vencida');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fielData: FielData = {
|
||||||
|
cerContent: decryptedFiel.cerContent,
|
||||||
|
keyContent: decryptedFiel.keyContent,
|
||||||
|
password: decryptedFiel.password,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Crear servicio SAT
|
||||||
|
const service = createSatService(fielData);
|
||||||
|
|
||||||
// Obtener datos del tenant
|
// Obtener datos del tenant
|
||||||
const tenant = await prisma.tenant.findUnique({
|
const tenant = await prisma.tenant.findUnique({
|
||||||
where: { id: tenantId },
|
where: { id: tenantId },
|
||||||
@@ -448,14 +434,10 @@ export async function startSync(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Autenticar con SAT
|
|
||||||
const tokenData = await authenticate(fielData.credential);
|
|
||||||
|
|
||||||
const ctx: SyncContext = {
|
const ctx: SyncContext = {
|
||||||
credential: fielData.credential,
|
fielData,
|
||||||
token: tokenData.token,
|
service,
|
||||||
tokenExpiresAt: tokenData.expiresAt,
|
rfc: decryptedFiel.rfc,
|
||||||
rfc: fielData.rfc,
|
|
||||||
tenantId,
|
tenantId,
|
||||||
schemaName: tenant.schemaName,
|
schemaName: tenant.schemaName,
|
||||||
};
|
};
|
||||||
|
|||||||
34
pnpm-lock.yaml
generated
34
pnpm-lock.yaml
generated
@@ -26,6 +26,9 @@ importers:
|
|||||||
'@nodecfdi/credentials':
|
'@nodecfdi/credentials':
|
||||||
specifier: ^3.2.0
|
specifier: ^3.2.0
|
||||||
version: 3.2.0(luxon@3.7.2)
|
version: 3.2.0(luxon@3.7.2)
|
||||||
|
'@nodecfdi/sat-ws-descarga-masiva':
|
||||||
|
specifier: ^2.0.0
|
||||||
|
version: 2.0.0(@nodecfdi/cfdi-core@1.0.1)(luxon@3.7.2)
|
||||||
'@prisma/client':
|
'@prisma/client':
|
||||||
specifier: ^5.22.0
|
specifier: ^5.22.0
|
||||||
version: 5.22.0(prisma@5.22.0)
|
version: 5.22.0(prisma@5.22.0)
|
||||||
@@ -484,6 +487,23 @@ packages:
|
|||||||
'@types/luxon':
|
'@types/luxon':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@nodecfdi/rfc@2.0.6':
|
||||||
|
resolution: {integrity: sha512-DiNC6j/mubbci8D9Qj9tdCm4/T/Q3ST92qpQ+AuHKJFVZ+/98F6ap8QFKeYK2ECu71wQGqAgkbmgQmVONAI5gg==}
|
||||||
|
engines: {node: '>=18 <=22 || ^16'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/luxon': 3.4.2
|
||||||
|
luxon: ^3.4.4
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/luxon':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@nodecfdi/sat-ws-descarga-masiva@2.0.0':
|
||||||
|
resolution: {integrity: sha512-FAmypqJfilOd29bf2bgMdysUkQKsu6ZirgljRfH4VFClXXtDHKmjOKahX0AbegUFc1GhtLjxhQgM+PJX3zhOdA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@nodecfdi/cfdi-core': ^1.0.0
|
||||||
|
luxon: ^3.6.1
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -2545,6 +2565,20 @@ snapshots:
|
|||||||
luxon: 3.7.2
|
luxon: 3.7.2
|
||||||
ts-mixer: 6.0.4
|
ts-mixer: 6.0.4
|
||||||
|
|
||||||
|
'@nodecfdi/rfc@2.0.6(luxon@3.7.2)':
|
||||||
|
dependencies:
|
||||||
|
luxon: 3.7.2
|
||||||
|
|
||||||
|
'@nodecfdi/sat-ws-descarga-masiva@2.0.0(@nodecfdi/cfdi-core@1.0.1)(luxon@3.7.2)':
|
||||||
|
dependencies:
|
||||||
|
'@nodecfdi/cfdi-core': 1.0.1
|
||||||
|
'@nodecfdi/credentials': 3.2.0(luxon@3.7.2)
|
||||||
|
'@nodecfdi/rfc': 2.0.6(luxon@3.7.2)
|
||||||
|
jszip: 3.10.1
|
||||||
|
luxon: 3.7.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/luxon'
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
|
|||||||
Reference in New Issue
Block a user