diff --git a/src/modules/parcel-sync/services/epay-client.ts b/src/modules/parcel-sync/services/epay-client.ts index 9e9a20b..eb89c4c 100644 --- a/src/modules/parcel-sync/services/epay-client.ts +++ b/src/modules/parcel-sync/services/epay-client.ts @@ -434,11 +434,22 @@ export class EpayClient { /* ── Order Submission ──────────────────────────────────────── */ - async submitOrder(): Promise { + /** + * Submit order. Pass knownOrderIds to skip them when finding the new orderId. + */ + async submitOrder(knownOrderIds?: Set): Promise { + // Get current latest orderId BEFORE submitting (to detect the new one) + let previousOrderId: string | null = null; + try { + previousOrderId = await this.getLatestOrderId(); + } catch { + // No previous orders + } + const body = new URLSearchParams(); body.set("goToCheckout", "true"); - await this.client.post( + const response = await this.client.post( `${BASE_URL}/EditCartSubmit.action`, body.toString(), { @@ -449,7 +460,12 @@ export class EpayClient { }, ); - return this.getLatestOrderId(); + const finalUrl = + response.request?.res?.responseUrl ?? response.config?.url ?? ""; + console.log(`[epay] EditCartSubmit: finalUrl=${finalUrl.slice(0, 100)}`); + + // Find the NEW orderId (different from previous + not in knownOrderIds) + return this.findNewOrderId(previousOrderId, knownOrderIds); } private async getLatestOrderId(): Promise { @@ -459,6 +475,36 @@ export class EpayClient { const html = String(response.data ?? ""); const match = html.match(/ShowOrderDetails\.action\?orderId=(\d+)/); if (match) return match[1] ?? ""; + throw new Error("Could not determine orderId"); + } + + private async findNewOrderId( + previousOrderId: string | null, + knownOrderIds?: Set, + ): Promise { + const response = await this.client.get(`${BASE_URL}/LogIn.action`, { + timeout: DEFAULT_TIMEOUT_MS, + }); + const html = String(response.data ?? ""); + + // Find ALL orderIds on the page + const allMatches = html.matchAll(/ShowOrderDetails\.action\?orderId=(\d+)/g); + for (const m of allMatches) { + const oid = m[1] ?? ""; + if (!oid) continue; + if (oid === previousOrderId) continue; + if (knownOrderIds?.has(oid)) continue; + console.log(`[epay] New orderId: ${oid}`); + return oid; + } + + // If no new orderId found, the latest one might be it (first order) + const latest = html.match(/ShowOrderDetails\.action\?orderId=(\d+)/); + if (latest?.[1]) { + console.log(`[epay] Using latest orderId: ${latest[1]}`); + return latest[1]; + } + throw new Error("Could not determine orderId after checkout"); } diff --git a/src/modules/parcel-sync/services/epay-queue.ts b/src/modules/parcel-sync/services/epay-queue.ts index bbb3979..164ded0 100644 --- a/src/modules/parcel-sync/services/epay-queue.ts +++ b/src/modules/parcel-sync/services/epay-queue.ts @@ -124,10 +124,14 @@ async function processQueue(): Promise { if (g.__epayQueueProcessing) return; // already running g.__epayQueueProcessing = true; + // Track all orderIds from this batch to avoid duplicates + const knownOrderIds = new Set(); + try { while (g.__epayQueue && g.__epayQueue.length > 0) { const item = g.__epayQueue.shift()!; - await processItem(item); + const orderId = await processItem(item, knownOrderIds); + if (orderId) knownOrderIds.add(orderId); } } finally { g.__epayQueueProcessing = false; @@ -145,7 +149,10 @@ async function updateStatus( }); } -async function processItem(item: QueueItem): Promise { +async function processItem( + item: QueueItem, + knownOrderIds: Set, +): Promise { const { extractId, input } = item; try { @@ -155,7 +162,7 @@ async function processItem(item: QueueItem): Promise { await updateStatus(extractId, "failed", { errorMessage: "Nu ești conectat la ePay.", }); - return; + return null; } const client = await EpayClient.create(creds.username, creds.password); @@ -167,7 +174,7 @@ async function processItem(item: QueueItem): Promise { await updateStatus(extractId, "failed", { errorMessage: `Credite insuficiente: ${credits}. Reîncărcați contul pe epay.ancpi.ro.`, }); - return; + return null; } // Step 2: Add to cart @@ -216,10 +223,10 @@ async function processItem(item: QueueItem): Promise { await updateStatus(extractId, "failed", { errorMessage: "Salvarea metadatelor în ePay a eșuat.", }); - return; + return null; } - const orderId = await client.submitOrder(); + const orderId = await client.submitOrder(knownOrderIds); await updateStatus(extractId, "polling", { orderId }); @@ -242,7 +249,7 @@ async function processItem(item: QueueItem): Promise { epayStatus: finalStatus.status, errorMessage: `Comanda ${finalStatus.status.toLowerCase()}.`, }); - return; + return null; } // Step 6: Download PDF @@ -254,7 +261,7 @@ async function processItem(item: QueueItem): Promise { epayStatus: finalStatus.status, errorMessage: "Nu s-a găsit documentul PDF în comanda finalizată.", }); - return; + return null; } await updateStatus(extractId, "downloading", { @@ -303,9 +310,12 @@ async function processItem(item: QueueItem): Promise { console.log( `[epay-queue] Completed: ${input.nrCadastral} → ${path} (credits: ${newCredits})`, ); + + return orderId; } catch (error) { const message = error instanceof Error ? error.message : "Eroare necunoscută"; console.error(`[epay-queue] Failed: ${input.nrCadastral}:`, message); await updateStatus(extractId, "failed", { errorMessage: message }); + return null; } }