From b7302d274ad0bba370cf710313a3625209389596 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Mon, 23 Mar 2026 04:20:37 +0200 Subject: [PATCH] docs: update SKILLS.md with complete ANCPI ePay documentation --- src/modules/parcel-sync/SKILLS.md | 85 ++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/src/modules/parcel-sync/SKILLS.md b/src/modules/parcel-sync/SKILLS.md index e53f1ca..9db4c25 100644 --- a/src/modules/parcel-sync/SKILLS.md +++ b/src/modules/parcel-sync/SKILLS.md @@ -214,6 +214,89 @@ siruta, layerId, status, totalRemote, totalLocal, newFeatures, removedFeatures, --- +## ANCPI ePay — CF Extract Ordering + +### Overview + +Orders CF extracts (Carte Funciară) from ANCPI ePay (epay.ancpi.ro). +Separate auth system from eTerra. Uses credits (prepaid, 1 per extract). + +### Critical Discovery: ID Mapping + +- **ePay internal county IDs = eTerra WORKSPACE_IDs** (CLUJ=127, ALBA=10, etc.) +- **ePay UAT IDs = SIRUTA codes** (Cluj-Napoca=54975, Florești=57706) +- This means ZERO discovery calls needed — use GisUat.workspacePk + siruta directly + +### Auth Flow (OpenAM) + +1. GET login page with `module=SelfRegistration&goto=http://epay.ancpi.ro:80/epay/LogIn.action` +2. POST credentials (`IDToken1`, `IDToken2`) → gets `AMAuthCookie` (NOT `iPlanetDirectoryPro`) +3. Navigate to `http://epay.ancpi.ro:80/epay/LogIn.action` (HTTP, not HTTPS!) for JSESSIONID +4. Session TTL: ~1 hour + +### Order Flow (4 requests per batch) + +1. `POST AddToCartOrWishListFromPost.action` × N → basketRowIds +2. `POST EpayJsonInterceptor.action` (multipart) × N → `reqType=saveProductMetadataForBasketItem` + `productMetadataJSON` +3. `POST EditCartSubmit.action` → `goToCheckout=true` (ONE submit for ALL items) +4. `GET CheckoutConfirmationSubmit.action` → confirms order +5. Poll `ShowOrderDetails.action?orderId=...` → parse documents from HTML-encoded JSON (`"` → `"`) +6. `POST DownloadFile.action?typeD=4&id=...` with `Content-Type: application/pdf` in REQUEST header + +### ePay Endpoint Gotchas + +1. **EpayJsonInterceptor uses form-urlencoded** (NOT JSON): `reqType=nomenclatorUAT&countyId=127` +2. **saveProductMetadataForBasketItem uses multipart/form-data** (form-data npm package) +3. **CF/CAD use `stringValues[0]`** (array!), not `stringValue` +4. **Document IDs are HTML-encoded** in ShowOrderDetails: `"idDocument":47301767` → decode first +5. **DownloadFile sends Content-Type: application/pdf in the REQUEST** (not response) +6. **EditCartSubmit returns 200** (not redirect) — Angular does client-side redirect to CheckoutConfirmation +7. **SearchEstate needs `identificator`/`judet`/`uat`** (not `identifier`/`countyId`/`uatId`), plus requires internal IDs +8. **MinIO metadata must be ASCII** — strip diacritics from values (`Florești` → `Floresti`) + +### Dedup Protection + +- **Queue level**: batch key = sorted cadastral numbers, 60s dedup window +- **API level**: optional `nonce` field, 60s idempotency cache +- **Test endpoint**: 30s dedup on hardcoded test parcels + +### Key Files + +| File | Purpose | +|------|---------| +| `services/epay-client.ts` | HTTP client (login, cart, metadata, submit, poll, download) | +| `services/epay-queue.ts` | Batch queue with dedup | +| `services/epay-storage.ts` | MinIO storage helpers | +| `services/epay-counties.ts` | County index mapping (legacy, not needed for ordering) | +| `services/epay-session-store.ts` | Session singleton | +| `services/epay-types.ts` | TypeScript types | +| `components/epay-connect.tsx` | Connection widget | +| `components/epay-order-button.tsx` | Per-parcel order button | +| `components/epay-tab.tsx` | Full "Extrase CF" tab | +| `api/ancpi/session/` | Connect/disconnect | +| `api/ancpi/order/` | Create batch orders | +| `api/ancpi/orders/` | List all extracts | +| `api/ancpi/credits/` | Credit balance | +| `api/ancpi/download/` | Stream PDF from MinIO | +| `api/ancpi/test/` | Diagnostic/test endpoint (temporary) | + +### DB Model: CfExtract + +- `orderId` — shared across batch items (NOT unique) +- `nrCadastral`, `siruta`, `judetName`, `uatName` — parcel identity +- `status` — pending|queued|cart|ordering|polling|downloading|completed|failed|cancelled +- `minioPath` — `parcele/{nrCadastral}/{idx}_Extras CF_{nrCadastral} - {DD-MM-YYYY}.pdf` +- `expiresAt` — 30 days after documentDate +- `version` — increments on re-order for same cadastral number + +### Credentials + +- Env vars: `ANCPI_USERNAME`, `ANCPI_PASSWORD` (hardcoded in docker-compose for Portainer CE) +- Default solicitant: ID `14452` (Beletage persoană juridică) +- MinIO bucket: `ancpi-documente` + +--- + ## Last Updated -2026-03-22 — Added county population via nomenclature API, local feature count in UAT dropdown. +2026-03-23 — ANCPI ePay CF extract ordering: full backend + UI + dedup protection.