feat(ares): ARES company lookup with prefill in customer/supplier modals
New /api/admin/ares proxy (browser cannot reach ares.gov.cz - CORS+CSP): GET /ico/:ico and GET /search?q= map the MFCR REST API to the form shape (street incl. orientation numbers, "511 01" PSC format, DIC). Guarded by customers.create/edit + warehouse.manage; token errors map to Czech messages. Shared AresAdornment button sits in the Nazev and ICO fields of both modals: ICO mode fills directly, name mode searches with a result picker. Tested against live ARES (BOHA, ICO 22599851). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
63
src/routes/admin/ares.ts
Normal file
63
src/routes/admin/ares.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import { requireAnyPermission } from "../../middleware/auth";
|
||||
import { success, error } from "../../utils/response";
|
||||
import { aresLookupByIco, aresSearchByName } from "../../services/ares.service";
|
||||
|
||||
// Czech messages for the service's token errors.
|
||||
const ARES_ERRORS: Record<string, { message: string; status: number }> = {
|
||||
invalid_ico: { message: "IČO musí být 8 číslic", status: 400 },
|
||||
not_found: {
|
||||
message: "Subjekt s tímto IČO nebyl v ARES nalezen",
|
||||
status: 404,
|
||||
},
|
||||
ares_unavailable: {
|
||||
message: "Registr ARES je momentálně nedostupný, zkuste to později",
|
||||
status: 502,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* ARES proxy — the browser cannot call ares.gov.cz directly (CORS + CSP), so
|
||||
* the customer/supplier modals go through these endpoints. Guarded by the
|
||||
* permissions of the two modals that use the prefill (customer editing and
|
||||
* warehouse supplier management); ARES data itself is public.
|
||||
*/
|
||||
export default async function aresRoutes(fastify: FastifyInstance) {
|
||||
const guard = requireAnyPermission(
|
||||
"customers.create",
|
||||
"customers.edit",
|
||||
"warehouse.manage",
|
||||
);
|
||||
|
||||
// GET /ico/:ico — single subject by IČO
|
||||
fastify.get<{ Params: { ico: string } }>(
|
||||
"/ico/:ico",
|
||||
{ preHandler: guard },
|
||||
async (request, reply) => {
|
||||
const result = await aresLookupByIco(request.params.ico);
|
||||
if ("error" in result) {
|
||||
const e = ARES_ERRORS[result.error];
|
||||
return error(reply, e.message, e.status);
|
||||
}
|
||||
return success(reply, result);
|
||||
},
|
||||
);
|
||||
|
||||
// GET /search?q=… — subjects by (part of) business name, max 10
|
||||
fastify.get<{ Querystring: { q?: string } }>(
|
||||
"/search",
|
||||
{ preHandler: guard },
|
||||
async (request, reply) => {
|
||||
const q = String(request.query.q ?? "").trim();
|
||||
if (q.length < 2) {
|
||||
return error(reply, "Zadejte alespoň 2 znaky názvu", 400);
|
||||
}
|
||||
const result = await aresSearchByName(q);
|
||||
if ("error" in result && !Array.isArray(result)) {
|
||||
const e = ARES_ERRORS[result.error];
|
||||
return error(reply, e.message, e.status);
|
||||
}
|
||||
return success(reply, result);
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user