diff --git a/src/modules/parcel-sync/services/epay-client.ts b/src/modules/parcel-sync/services/epay-client.ts index c4ec153..0f6da40 100644 --- a/src/modules/parcel-sync/services/epay-client.ts +++ b/src/modules/parcel-sync/services/epay-client.ts @@ -552,20 +552,28 @@ export class EpayClient { .replace(/ț/g, "ț") .replace(/ș/g, "ș"); - // Parse metadateCereri blocks to match CF → solutii (document) - // Each metadateCerere has: metadate.CF.stringValues[0] + solutii[{idDocument,...}] - // Pattern: find each block with both CF and solutii - const metadataPattern = - /"metadate"\s*:\s*\{[^}]*"CF"\s*:\s*\{[^}]*"stringValues"\s*:\s*\["(\d+)"\][^]*?"solutii"\s*:\s*\[(\{[^[\]]*\})\]/g; + // Strategy: find CF numbers and solutii separately, then match by position. + // In the HTML, each metadateCereri block has both CF.stringValues and solutii + // in the same order. We find them independently and zip them. - let metaMatch; - while ((metaMatch = metadataPattern.exec(decoded)) !== null) { - const cfNumber = metaMatch[1] ?? ""; + // 1. Find all CF numbers: "CF":{"name":"CF",...,"stringValues":["345295"]} + const cfPattern = /"CF"\s*:\s*\{[^}]*"stringValues"\s*:\s*\["(\d+)"\]/g; + const cfNumbers: string[] = []; + let cfMatch; + while ((cfMatch = cfPattern.exec(decoded)) !== null) { + cfNumbers.push(cfMatch[1] ?? ""); + } + + // 2. Find all solutii blocks (CF extracts only, idTipDocument=null) + const solutiiPattern = /"solutii"\s*:\s*\[(\{[^[\]]*\})\]/g; + const allSolutii: EpaySolutionDoc[] = []; + let solutiiMatch; + while ((solutiiMatch = solutiiPattern.exec(decoded)) !== null) { try { - const solutii = JSON.parse(`[${metaMatch[2]}]`); - for (const s of solutii) { + const arr = JSON.parse(`[${solutiiMatch[1]}]`); + for (const s of arr) { if (s?.idDocument && s?.idTipDocument === null) { - const doc: EpaySolutionDoc = { + allSolutii.push({ idDocument: s.idDocument, idTipDocument: null, nume: s.nume ?? "", @@ -578,43 +586,26 @@ export class EpayClient { valabilNelimitat: s.valabilNelimitat ?? true, zileValabilitateDownload: s.zileValabilitateDownload ?? -1, transactionId: s.transactionId ?? 0, - }; - documents.push(doc); - if (cfNumber) documentsByCadastral.set(cfNumber, doc); + }); } } } catch { /* parse failed */ } } - // Fallback: simpler solutii pattern (without CF matching) - if (documents.length === 0) { - const solutiiPattern = /"solutii"\s*:\s*\[(\{[^[\]]*\})\]/g; - let solutiiMatch; - while ((solutiiMatch = solutiiPattern.exec(decoded)) !== null) { - try { - const arr = JSON.parse(`[${solutiiMatch[1]}]`); - for (const s of arr) { - if (s?.idDocument && s?.idTipDocument === null) { - documents.push({ - idDocument: s.idDocument, - idTipDocument: null, - nume: s.nume ?? "", - numar: s.numar ?? null, - serie: s.serie ?? null, - dataDocument: s.dataDocument ?? "", - contentType: s.contentType ?? "application/pdf", - linkDownload: s.linkDownload ?? "", - downloadValabil: s.downloadValabil ?? true, - valabilNelimitat: s.valabilNelimitat ?? true, - zileValabilitateDownload: s.zileValabilitateDownload ?? -1, - transactionId: s.transactionId ?? 0, - }); - } - } - } catch { /* parse failed */ } + // 3. Zip CF numbers with solutii — they appear in the same order + documents.push(...allSolutii); + for (let i = 0; i < Math.min(cfNumbers.length, allSolutii.length); i++) { + const cf = cfNumbers[i]; + const doc = allSolutii[i]; + if (cf && doc) { + documentsByCadastral.set(cf, doc); } } + console.log( + `[epay] Order ${orderId}: CFs=[${cfNumbers.join(",")}], docs=${allSolutii.length}, matched=${documentsByCadastral.size}`, + ); + if (documents.length === 0 && status === "Finalizata") { console.warn(`[epay] Order ${orderId}: Finalizata but no documents found`); }