fix(ancpi): parse CF numbers and solutii separately, zip by position
The nested JSON in ePay HTML breaks [^}]* regex. New approach: find all CF.stringValues independently, find all solutii independently, then zip them by position (they appear in same order in HTML). This correctly maps CF number → document for batch orders. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -552,50 +552,28 @@ export class EpayClient {
|
|||||||
.replace(/ț/g, "ț")
|
.replace(/ț/g, "ț")
|
||||||
.replace(/ș/g, "ș");
|
.replace(/ș/g, "ș");
|
||||||
|
|
||||||
// Parse metadateCereri blocks to match CF → solutii (document)
|
// Strategy: find CF numbers and solutii separately, then match by position.
|
||||||
// Each metadateCerere has: metadate.CF.stringValues[0] + solutii[{idDocument,...}]
|
// In the HTML, each metadateCereri block has both CF.stringValues and solutii
|
||||||
// Pattern: find each block with both CF and solutii
|
// in the same order. We find them independently and zip them.
|
||||||
const metadataPattern =
|
|
||||||
/"metadate"\s*:\s*\{[^}]*"CF"\s*:\s*\{[^}]*"stringValues"\s*:\s*\["(\d+)"\][^]*?"solutii"\s*:\s*\[(\{[^[\]]*\})\]/g;
|
|
||||||
|
|
||||||
let metaMatch;
|
// 1. Find all CF numbers: "CF":{"name":"CF",...,"stringValues":["345295"]}
|
||||||
while ((metaMatch = metadataPattern.exec(decoded)) !== null) {
|
const cfPattern = /"CF"\s*:\s*\{[^}]*"stringValues"\s*:\s*\["(\d+)"\]/g;
|
||||||
const cfNumber = metaMatch[1] ?? "";
|
const cfNumbers: string[] = [];
|
||||||
try {
|
let cfMatch;
|
||||||
const solutii = JSON.parse(`[${metaMatch[2]}]`);
|
while ((cfMatch = cfPattern.exec(decoded)) !== null) {
|
||||||
for (const s of solutii) {
|
cfNumbers.push(cfMatch[1] ?? "");
|
||||||
if (s?.idDocument && s?.idTipDocument === null) {
|
|
||||||
const doc: EpaySolutionDoc = {
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
documents.push(doc);
|
|
||||||
if (cfNumber) documentsByCadastral.set(cfNumber, doc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch { /* parse failed */ }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: simpler solutii pattern (without CF matching)
|
// 2. Find all solutii blocks (CF extracts only, idTipDocument=null)
|
||||||
if (documents.length === 0) {
|
|
||||||
const solutiiPattern = /"solutii"\s*:\s*\[(\{[^[\]]*\})\]/g;
|
const solutiiPattern = /"solutii"\s*:\s*\[(\{[^[\]]*\})\]/g;
|
||||||
|
const allSolutii: EpaySolutionDoc[] = [];
|
||||||
let solutiiMatch;
|
let solutiiMatch;
|
||||||
while ((solutiiMatch = solutiiPattern.exec(decoded)) !== null) {
|
while ((solutiiMatch = solutiiPattern.exec(decoded)) !== null) {
|
||||||
try {
|
try {
|
||||||
const arr = JSON.parse(`[${solutiiMatch[1]}]`);
|
const arr = JSON.parse(`[${solutiiMatch[1]}]`);
|
||||||
for (const s of arr) {
|
for (const s of arr) {
|
||||||
if (s?.idDocument && s?.idTipDocument === null) {
|
if (s?.idDocument && s?.idTipDocument === null) {
|
||||||
documents.push({
|
allSolutii.push({
|
||||||
idDocument: s.idDocument,
|
idDocument: s.idDocument,
|
||||||
idTipDocument: null,
|
idTipDocument: null,
|
||||||
nume: s.nume ?? "",
|
nume: s.nume ?? "",
|
||||||
@@ -613,7 +591,20 @@ export class EpayClient {
|
|||||||
}
|
}
|
||||||
} catch { /* parse failed */ }
|
} 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") {
|
if (documents.length === 0 && status === "Finalizata") {
|
||||||
console.warn(`[epay] Order ${orderId}: Finalizata but no documents found`);
|
console.warn(`[epay] Order ${orderId}: Finalizata but no documents found`);
|
||||||
|
|||||||
Reference in New Issue
Block a user