fix(ancpi): ePay county IDs = WORKSPACE_IDs, UAT IDs = SIRUTA codes

Zero discovery calls needed! ePay internal county IDs are identical
to eTerra WORKSPACE_IDs (CLUJ=127, ALBA=10, etc.) and ePay UAT IDs
are SIRUTA codes (Cluj-Napoca=54975, Florești=57706). Queue now
uses workspacePk + siruta directly from GisUat DB.
Flow: AddToCart → saveMetadata → EditCartSubmit → Poll+Download.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-23 02:11:41 +02:00
parent e13a9351be
commit 7fc46f75bd
2 changed files with 82 additions and 95 deletions
+53 -63
View File
@@ -10,10 +10,11 @@ export const runtime = "nodejs";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
/** /**
* GET /api/ancpi/test?step=login|uats|search|order * GET /api/ancpi/test?step=login|uats|order
* *
* Temporary diagnostic endpoint. Uses the CORRECT ePay flow: * ePay internal county IDs = eTerra WORKSPACE_IDs.
* shoppingCartCompleteInformation → judeteNom → nomenclatorUAT → saveMetadata * ePay UAT IDs = SIRUTA codes.
* Zero discovery calls needed!
*/ */
export async function GET(req: Request) { export async function GET(req: Request) {
const url = new URL(req.url); const url = new URL(req.url);
@@ -26,9 +27,6 @@ export async function GET(req: Request) {
return NextResponse.json({ error: "ANCPI credentials not configured" }); return NextResponse.json({ error: "ANCPI credentials not configured" });
} }
const normalize = (s: string) =>
s.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toUpperCase().trim();
try { try {
// ── login ── // ── login ──
if (step === "login") { if (step === "login") {
@@ -38,75 +36,39 @@ export async function GET(req: Request) {
return NextResponse.json({ step: "login", success: true, credits }); return NextResponse.json({ step: "login", success: true, credits });
} }
// ── uats ── Get internal county IDs + UAT list for Cluj // ── uats ── Verify that ePay county/UAT IDs match our WORKSPACE_ID/SIRUTA
if (step === "uats") { if (step === "uats") {
const client = await EpayClient.create(username, password); const client = await EpayClient.create(username, password);
await client.addToCart(14200); // need cart for ShowCartItems context await client.addToCart(14200);
// Get county list to confirm IDs match WORKSPACE_IDs
const counties = await client.getCountyList(); const counties = await client.getCountyList();
const clujCounty = counties.find((c) => normalize(c.value) === "CLUJ"); const clujCounty = counties.find((c) =>
c.value.toUpperCase().includes("CLUJ"),
);
// Get UAT list to confirm IDs match SIRUTA codes
let uatList: { id: number; value: string }[] = []; let uatList: { id: number; value: string }[] = [];
if (clujCounty) { if (clujCounty) {
uatList = await client.getUatList(clujCounty.id); uatList = await client.getUatList(clujCounty.id);
} }
const clujNapoca = uatList.find((u) => normalize(u.value).includes("CLUJ-NAPOCA"));
const feleacu = uatList.find((u) => normalize(u.value).includes("FELEACU"));
const floresti = uatList.find((u) => normalize(u.value).includes("FLORESTI"));
return NextResponse.json({ return NextResponse.json({
step: "uats", step: "uats",
totalCounties: counties.length, totalCounties: counties.length,
countiesFirst5: counties.slice(0, 5),
clujCounty, clujCounty,
note: clujCounty?.id === 127
? "CONFIRMED: ePay county ID = WORKSPACE_ID (127)"
: `WARNING: expected 127, got ${clujCounty?.id}`,
totalUats: uatList.length, totalUats: uatList.length,
matches: { clujNapoca, feleacu, floresti }, clujNapoca: uatList.find((u) => u.id === 54975),
feleacu: uatList.find((u) => u.id === 57582),
floresti: uatList.find((u) => u.id === 57706),
}); });
} }
// ── search ── SearchEstate with correct params
if (step === "search") {
const client = await EpayClient.create(username, password);
await client.addToCart(14200);
const counties = await client.getCountyList();
const clujCounty = counties.find((c) => normalize(c.value) === "CLUJ");
if (!clujCounty) {
return NextResponse.json({ error: "CLUJ not found", counties: counties.slice(0, 5) });
}
const uatList = await client.getUatList(clujCounty.id);
const clujNapoca = uatList.find((u) => normalize(u.value).includes("CLUJ-NAPOCA"));
const feleacu = uatList.find((u) => normalize(u.value).includes("FELEACU"));
const floresti = uatList.find((u) => normalize(u.value).includes("FLORESTI"));
const results: Record<string, unknown> = {
clujCountyId: clujCounty.id,
uats: { clujNapoca, feleacu, floresti },
};
// SearchEstate with correct field names: identificator, judet (internal ID), uat (real ID)
if (clujNapoca) {
results["search_345295"] = await client
.searchEstate("345295", clujCounty.id, clujNapoca.id)
.catch((e: Error) => ({ error: e.message }));
}
if (feleacu) {
results["search_63565"] = await client
.searchEstate("63565", clujCounty.id, feleacu.id)
.catch((e: Error) => ({ error: e.message }));
}
if (floresti) {
results["search_88089"] = await client
.searchEstate("88089", clujCounty.id, floresti.id)
.catch((e: Error) => ({ error: e.message }));
}
return NextResponse.json({ step: "search", results });
}
// ── order ── (USES 3 CREDITS!) // ── order ── (USES 3 CREDITS!)
// Uses WORKSPACE_ID as county ID, SIRUTA as UAT ID — zero discovery
if (step === "order") { if (step === "order") {
if (!getEpayCredentials()) { if (!getEpayCredentials()) {
createEpaySession(username, password, 0); createEpaySession(username, password, 0);
@@ -117,15 +79,37 @@ export async function GET(req: Request) {
createEpaySession(username, password, credits); createEpaySession(username, password, credits);
if (credits < 3) { if (credits < 3) {
return NextResponse.json({ error: `Doar ${credits} credite, trebuie 3.` }); return NextResponse.json({
error: `Doar ${credits} credite, trebuie 3.`,
});
} }
// Resolve county + UAT IDs through the queue // workspacePk=127 (CLUJ), SIRUTA codes as UAT IDs
// Queue handles getCountyList + getUatList internally
const parcels = [ const parcels = [
{ nrCadastral: "345295", judetName: "CLUJ", uatName: "Cluj-Napoca", judetIndex: 0, uatId: 0 }, {
{ nrCadastral: "63565", judetName: "CLUJ", uatName: "Feleacu", judetIndex: 0, uatId: 0 }, nrCadastral: "345295",
{ nrCadastral: "88089", judetName: "CLUJ", uatName: "Floresti", judetIndex: 0, uatId: 0 }, siruta: "54975", // SIRUTA = ePay UAT ID
judetIndex: 127, // workspacePk = ePay county ID
judetName: "CLUJ",
uatId: 54975,
uatName: "Cluj-Napoca",
},
{
nrCadastral: "63565",
siruta: "57582",
judetIndex: 127,
judetName: "CLUJ",
uatId: 57582,
uatName: "Feleacu",
},
{
nrCadastral: "88089",
siruta: "57706",
judetIndex: 127,
judetName: "CLUJ",
uatId: 57706,
uatName: "Florești",
},
]; ];
const ids: string[] = []; const ids: string[] = [];
@@ -137,8 +121,14 @@ export async function GET(req: Request) {
return NextResponse.json({ return NextResponse.json({
step: "order", step: "order",
credits, credits,
message: `Enqueued ${ids.length} orders. Queue resolves county/UAT IDs automatically.`, message: `Enqueued ${ids.length} orders (4 requests each, zero discovery).`,
orderIds: ids, orderIds: ids,
parcels: parcels.map((p, i) => ({
nrCadastral: p.nrCadastral,
uatName: p.uatName,
siruta: p.siruta,
extractId: ids[i],
})),
}); });
} }
+29 -32
View File
@@ -175,42 +175,39 @@ async function processItem(item: QueueItem): Promise<void> {
const basketRowId = await client.addToCart(input.prodId ?? 14200); const basketRowId = await client.addToCart(input.prodId ?? 14200);
await updateStatus(extractId, "cart", { basketRowId }); await updateStatus(extractId, "cart", { basketRowId });
// Step 3: Resolve internal county + UAT IDs // Step 3: Save metadata + submit order
await updateStatus(extractId, "searching"); // ePay internal county IDs = eTerra WORKSPACE_IDs
const counties = await client.getCountyList(); // ePay UAT IDs = SIRUTA codes
const normalize = (s: string) => // So we can skip all discovery calls!
s.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toUpperCase().trim();
const countyMatch = counties.find(
(c) => normalize(c.value) === normalize(input.judetName),
);
if (!countyMatch) {
await updateStatus(extractId, "failed", {
errorMessage: `Județul "${input.judetName}" nu a fost găsit în ePay. Disponibile: ${counties.slice(0, 5).map((c) => c.value).join(", ")}...`,
});
return;
}
const uats = await client.getUatList(countyMatch.id);
const uatMatch = uats.find(
(u) => normalize(u.value) === normalize(input.uatName),
);
if (!uatMatch) {
await updateStatus(extractId, "failed", {
errorMessage: `UAT "${input.uatName}" nu a fost găsit în ePay pentru ${input.judetName}.`,
});
return;
}
// Step 4: Save metadata + submit order
await updateStatus(extractId, "ordering"); await updateStatus(extractId, "ordering");
// Resolve county ID (workspacePk) and UAT ID (siruta) from our DB
let countyInternalId = input.judetIndex; // might already be workspacePk
let uatInternalId = input.uatId; // might already be SIRUTA
let countyName = input.judetName;
let uatName = input.uatName;
// If siruta is provided, look up workspacePk from GisUat
if (input.siruta) {
const uat = await prisma.gisUat.findUnique({
where: { siruta: input.siruta },
select: { workspacePk: true, county: true, name: true },
});
if (uat?.workspacePk) {
countyInternalId = uat.workspacePk;
uatInternalId = Number(input.siruta);
if (uat.county) countyName = uat.county;
if (uat.name) uatName = uat.name;
}
}
const nrCF = input.nrCF ?? input.nrCadastral; const nrCF = input.nrCF ?? input.nrCadastral;
const saved = await client.saveMetadata( const saved = await client.saveMetadata(
basketRowId, basketRowId,
countyMatch.id, countyInternalId,
countyMatch.value, countyName,
uatMatch.id, uatInternalId,
uatMatch.value, uatName,
nrCF, nrCF,
input.nrCadastral, input.nrCadastral,
process.env.ANCPI_DEFAULT_SOLICITANT_ID || "14452", process.env.ANCPI_DEFAULT_SOLICITANT_ID || "14452",