feat(eterra): RGI API routes + test page for issued documents
New eTerra RGI (Registrul General de Intrare) integration: API routes (/api/eterra/rgi/): - POST /applications — list applications with workspace/year filters - GET /details?applicationId=X — application details - GET /issued-docs?applicationId=X&workspaceId=Y — issued documents list - GET /download-doc?wid=X&aid=Y&did=Z — download issued document EterraClient: added rgiPost, rgiGet, rgiDownload methods for RGI API. Test page (/rgi-test): - Filters: workspace, orgUnit, year - Toggle: "Doar solutionate cu termen viitor" - Table with application list, expandable issued docs, download links - Raw JSON debug sections (collapsible) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { EterraClient } from "@/modules/parcel-sync/services/eterra-client";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
type Body = {
|
||||
workspaceId: number;
|
||||
orgUnitId: number;
|
||||
year: string;
|
||||
page?: number;
|
||||
nrElements?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* POST /api/eterra/rgi/applications
|
||||
*
|
||||
* List RGI applications for a given workspace (county) and org unit (UAT).
|
||||
* Proxies eTerra rgi/applicationgrid/list endpoint.
|
||||
*/
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body = (await req.json()) as Body;
|
||||
const { workspaceId, orgUnitId, year } = body;
|
||||
|
||||
if (!workspaceId || !orgUnitId || !year) {
|
||||
return NextResponse.json(
|
||||
{ error: "workspaceId, orgUnitId and year are required" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const username = process.env.ETERRA_USERNAME ?? "";
|
||||
const password = process.env.ETERRA_PASSWORD ?? "";
|
||||
if (!username || !password) {
|
||||
return NextResponse.json(
|
||||
{ error: "Credentials missing" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
const client = await EterraClient.create(username, password);
|
||||
|
||||
const page = body.page ?? 0;
|
||||
const nrElements = body.nrElements ?? 25;
|
||||
|
||||
const payload = {
|
||||
filters: [
|
||||
{
|
||||
value: workspaceId,
|
||||
type: "NUMBER",
|
||||
key: "workspace.nomenPk",
|
||||
op: "=",
|
||||
},
|
||||
{
|
||||
value: orgUnitId,
|
||||
type: "NUMBER",
|
||||
key: "partyFunctionByOrgUnitId.nomenPk",
|
||||
op: "=",
|
||||
},
|
||||
],
|
||||
applicationFilters: {
|
||||
applicationType: "own",
|
||||
tabCode: "NUMBER_LIST",
|
||||
year,
|
||||
countyId: workspaceId,
|
||||
adminUnitId: orgUnitId,
|
||||
showAll: false,
|
||||
showNewRequests: false,
|
||||
showSuspended: false,
|
||||
showSolutionDeadlineExpired: false,
|
||||
showPendingLimitation: false,
|
||||
showCadastreNumberAllocated: false,
|
||||
showImmovableRegistered: false,
|
||||
showDocumentIssued: false,
|
||||
showRestitutionClosed: false,
|
||||
showRejected: false,
|
||||
showClosed: false,
|
||||
showWithdrawn: false,
|
||||
showSolutionDeadlineExceeded: false,
|
||||
},
|
||||
sorters: [],
|
||||
nrElements,
|
||||
page,
|
||||
};
|
||||
|
||||
const result = await client.rgiPost(
|
||||
"rgi/applicationgrid/list",
|
||||
payload,
|
||||
);
|
||||
|
||||
return NextResponse.json(result);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Eroare server";
|
||||
return NextResponse.json({ error: message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { EterraClient } from "@/modules/parcel-sync/services/eterra-client";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
/**
|
||||
* GET /api/eterra/rgi/details?applicationId=...
|
||||
*
|
||||
* Fetch RGI application details by application ID.
|
||||
* Proxies eTerra rgi/appdetail/details endpoint.
|
||||
*/
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const applicationId = req.nextUrl.searchParams.get("applicationId");
|
||||
|
||||
if (!applicationId) {
|
||||
return NextResponse.json(
|
||||
{ error: "applicationId is required" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const username = process.env.ETERRA_USERNAME ?? "";
|
||||
const password = process.env.ETERRA_PASSWORD ?? "";
|
||||
if (!username || !password) {
|
||||
return NextResponse.json(
|
||||
{ error: "Credentials missing" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
const client = await EterraClient.create(username, password);
|
||||
|
||||
const result = await client.rgiPost(
|
||||
`rgi/appdetail/details?applicationid=${encodeURIComponent(applicationId)}`,
|
||||
undefined,
|
||||
);
|
||||
|
||||
return NextResponse.json(result);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Eroare server";
|
||||
return NextResponse.json({ error: message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { EterraClient } from "@/modules/parcel-sync/services/eterra-client";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
/**
|
||||
* GET /api/eterra/rgi/download-doc?workspaceId=...&applicationId=...&docId=...
|
||||
*
|
||||
* Check file visibility and download an issued document from RGI.
|
||||
* Step 1: Calls rgi/appdetail/issueddocs/fileVisibility to check access.
|
||||
* Step 2: Downloads the file via rgi/appdetail/issueddocs/download.
|
||||
*/
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const workspaceId = req.nextUrl.searchParams.get("workspaceId");
|
||||
const applicationId = req.nextUrl.searchParams.get("applicationId");
|
||||
const docId = req.nextUrl.searchParams.get("docId");
|
||||
|
||||
if (!workspaceId || !applicationId || !docId) {
|
||||
return NextResponse.json(
|
||||
{ error: "workspaceId, applicationId and docId are required" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const username = process.env.ETERRA_USERNAME ?? "";
|
||||
const password = process.env.ETERRA_PASSWORD ?? "";
|
||||
if (!username || !password) {
|
||||
return NextResponse.json(
|
||||
{ error: "Credentials missing" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
const client = await EterraClient.create(username, password);
|
||||
|
||||
// Step 1: Check file visibility
|
||||
const visibilityPath = `rgi/appdetail/issueddocs/fileVisibility/${encodeURIComponent(workspaceId)}/${encodeURIComponent(applicationId)}/${encodeURIComponent(docId)}`;
|
||||
const visibility = await client.rgiGet(visibilityPath);
|
||||
|
||||
// Step 2: Attempt to download the file
|
||||
try {
|
||||
const downloadPath = `rgi/appdetail/issueddocs/download/${encodeURIComponent(workspaceId)}/${encodeURIComponent(applicationId)}/${encodeURIComponent(docId)}`;
|
||||
const { data, contentType, filename } =
|
||||
await client.rgiDownload(downloadPath);
|
||||
|
||||
return new NextResponse(new Uint8Array(data), {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": contentType,
|
||||
"Content-Disposition": `attachment; filename="${encodeURIComponent(filename)}"`,
|
||||
"Content-Length": String(data.length),
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
// Download failed — return the visibility response instead so the caller
|
||||
// can inspect what eTerra reported (may contain a URL or error details).
|
||||
return NextResponse.json({
|
||||
visibility,
|
||||
downloadFailed: true,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Eroare server";
|
||||
return NextResponse.json({ error: message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { EterraClient } from "@/modules/parcel-sync/services/eterra-client";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
/**
|
||||
* GET /api/eterra/rgi/issued-docs?applicationId=...&workspaceId=...
|
||||
*
|
||||
* List issued documents for an RGI application.
|
||||
* Proxies eTerra rgi/appdetail/issueddocs/list endpoint.
|
||||
*/
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const applicationId = req.nextUrl.searchParams.get("applicationId");
|
||||
const workspaceId = req.nextUrl.searchParams.get("workspaceId");
|
||||
|
||||
if (!applicationId || !workspaceId) {
|
||||
return NextResponse.json(
|
||||
{ error: "applicationId and workspaceId are required" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const username = process.env.ETERRA_USERNAME ?? "";
|
||||
const password = process.env.ETERRA_PASSWORD ?? "";
|
||||
if (!username || !password) {
|
||||
return NextResponse.json(
|
||||
{ error: "Credentials missing" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
const client = await EterraClient.create(username, password);
|
||||
|
||||
const result = await client.rgiPost(
|
||||
`rgi/appdetail/issueddocs/list?applicationid=${encodeURIComponent(applicationId)}&reSaveDocsInPendingAndTiomeOut=false&workspaceid=${encodeURIComponent(workspaceId)}`,
|
||||
{
|
||||
filters: [],
|
||||
sorters: [],
|
||||
nrElements: 50,
|
||||
page: 0,
|
||||
},
|
||||
);
|
||||
|
||||
return NextResponse.json(result);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Eroare server";
|
||||
return NextResponse.json({ error: message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user