diff --git a/src/app/api/ancpi/test/route.ts b/src/app/api/ancpi/test/route.ts index 52fc4f9..7a7b86a 100644 --- a/src/app/api/ancpi/test/route.ts +++ b/src/app/api/ancpi/test/route.ts @@ -77,69 +77,53 @@ export async function GET(req: Request) { } // ── Step: search ── - // SearchEstate.action returns HTML (Angular app), not JSON. - // Need to find the real AJAX endpoints from the Angular JS code. + // Test EditCartItemJson.action — the real endpoint for configuring cart items if (step === "search") { const client = await EpayClient.create(username, password); + const BASE = process.env.ANCPI_BASE_URL || "https://epay.ancpi.ro/epay"; - // Add to cart first + // Add to cart const basketRowId = await client.addToCart(14200); - // Load ShowCartItems.action — the Angular form page - const cartPageHtml = await client.getRawHtml( - `${process.env.ANCPI_BASE_URL || "https://epay.ancpi.ro/epay"}/ShowCartItems.action`, - ); + const results: Record = { basketRowId }; - // Extract Angular AJAX endpoints and form structure - // Look for: SearchEstate, EpayJsonInterceptor, ng-controller, $http - const patterns = [ - /SearchEstate[^"'\s]*/g, - /EpayJsonInterceptor[^"'\s]*/g, - /EditCartItem[^"'\s]*/g, - /\$http\.(post|get)\s*\(\s*['"]([^'"]+)['"]/g, - /action\s*[:=]\s*['"]([^'"]*)['"]/g, - /url\s*[:=]\s*['"]([^'"]*?\.action[^'"]*)['"]/g, - /ng-controller\s*=\s*["']([^"']+)["']/g, - /searchEstate|SearchEstate|cautaImobil/gi, - ]; + // Test 1: Set county via EditCartItemJson to get UAT list + try { + const body1 = new URLSearchParams(); + body1.set("basketId", String(basketRowId)); + body1.set("metadate.judet", "13"); // CLUJ - const found: Record = {}; - for (const pat of patterns) { - const matches = cartPageHtml.match(pat); - if (matches && matches.length > 0) { - found[pat.source.slice(0, 40)] = [...new Set(matches)].slice(0, 10); - } + const resp1 = await client.postRaw( + `${BASE}/EditCartItemJson.action`, + body1.toString(), + ); + results["setCounty_type"] = typeof resp1; + results["setCounty_len"] = typeof resp1 === "string" ? resp1.length : JSON.stringify(resp1).length; + results["setCounty_sample"] = (typeof resp1 === "string" ? resp1 : JSON.stringify(resp1)).slice(0, 1000); + } catch (e) { + results["setCounty_error"] = (e as Error).message; } - // Also extract any inline JSON data (Angular scope initialization) - const jsonMatches = cartPageHtml.match(/ng-init\s*=\s*["']([^"']{10,500})["']/g); + // Test 2: Try SearchEstate via the Angular way (maybe it's inside EditCartItemJson) + try { + const body2 = new URLSearchParams(); + body2.set("basketId", String(basketRowId)); + body2.set("identifier", "345295"); + body2.set("countyId", "13"); - // Find county/UAT dropdown references - const selectMatches = cartPageHtml.match(/]*(?:judet|county|uat)[^>]*>/gi); + const resp2 = await client.postRaw( + `${BASE}/SearchEstate.action`, + body2.toString(), + { "X-Requested-With": "XMLHttpRequest", Accept: "application/json" }, + ); + results["searchAjax_type"] = typeof resp2; + results["searchAjax_len"] = typeof resp2 === "string" ? resp2.length : JSON.stringify(resp2).length; + results["searchAjax_sample"] = (typeof resp2 === "string" ? resp2 : JSON.stringify(resp2)).slice(0, 1000); + } catch (e) { + results["searchAjax_error"] = (e as Error).message; + } - // Look for the specific search function - const searchFuncMatch = cartPageHtml.match( - /function\s+\w*[Ss]earch\w*\s*\([^)]*\)\s*\{[^}]{0,500}/g, - ); - - return NextResponse.json({ - step: "search", - basketRowId, - pageLength: cartPageHtml.length, - angularEndpoints: found, - ngInit: jsonMatches?.slice(0, 5) ?? [], - selectDropdowns: selectMatches?.slice(0, 5) ?? [], - searchFunctions: searchFuncMatch?.slice(0, 3) ?? [], - // Also check: does the page contain "SearchEstate" anywhere? - hasSearchEstate: cartPageHtml.includes("SearchEstate"), - hasJsonInterceptor: cartPageHtml.includes("EpayJsonInterceptor"), - // Sample of any .action URLs in the page - actionUrls: [...new Set( - (cartPageHtml.match(/['"][^'"]*\.action[^'"]*['"]/g) ?? []) - .map((s: string) => s.replace(/['"]/g, "")) - .filter((s: string) => s.length < 100), - )].slice(0, 20), - }); + return NextResponse.json({ step: "search", results }); } // ── Step: order ── (USES 3 CREDITS!) diff --git a/src/modules/parcel-sync/services/epay-client.ts b/src/modules/parcel-sync/services/epay-client.ts index 73bae3a..80d50a3 100644 --- a/src/modules/parcel-sync/services/epay-client.ts +++ b/src/modules/parcel-sync/services/epay-client.ts @@ -256,6 +256,22 @@ export class EpayClient { return String(response.data ?? ""); } + /* ── Raw POST (for endpoint discovery) ──────────────────── */ + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async postRaw(url: string, body: string, extraHeaders?: Record): Promise { + const response = await this.client.post(url, body, { + headers: { + "Content-Type": "application/x-www-form-urlencoded", + ...extraHeaders, + }, + timeout: DEFAULT_TIMEOUT_MS, + maxRedirects: 5, + validateStatus: () => true, + }); + return response.data; + } + /* ── Credits ───────────────────────────────────────────────── */ async getCredits(): Promise {