fix(ancpi): find NEW orderId after submit, track known IDs in queue
submitOrder now captures the previous orderId BEFORE submitting, then searches for a NEW orderId that isn't in the knownOrderIds set. Queue passes knownOrderIds between sequential items to prevent duplicate orderId assignment (unique constraint violation). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -434,11 +434,22 @@ export class EpayClient {
|
||||
|
||||
/* ── Order Submission ──────────────────────────────────────── */
|
||||
|
||||
async submitOrder(): Promise<string> {
|
||||
/**
|
||||
* Submit order. Pass knownOrderIds to skip them when finding the new orderId.
|
||||
*/
|
||||
async submitOrder(knownOrderIds?: Set<string>): Promise<string> {
|
||||
// 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<string> {
|
||||
@@ -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<string>,
|
||||
): Promise<string> {
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
@@ -124,10 +124,14 @@ async function processQueue(): Promise<void> {
|
||||
if (g.__epayQueueProcessing) return; // already running
|
||||
g.__epayQueueProcessing = true;
|
||||
|
||||
// Track all orderIds from this batch to avoid duplicates
|
||||
const knownOrderIds = new Set<string>();
|
||||
|
||||
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<void> {
|
||||
async function processItem(
|
||||
item: QueueItem,
|
||||
knownOrderIds: Set<string>,
|
||||
): Promise<string | null> {
|
||||
const { extractId, input } = item;
|
||||
|
||||
try {
|
||||
@@ -155,7 +162,7 @@ async function processItem(item: QueueItem): Promise<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user