import assert from "node:assert/strict"; import { AssetResponseSchema, CatalogResponseSchema, InventoryResponseSchema, SaveDefinitionResponseSchema, } from "@metis/assets/common"; import { CompanyResponseSchema } from "@metis/companies/common"; import { z } from "zod/v4"; import { UniqueID } from "../../../packages/rdx-ddd/src/index"; export async function verifyInventory( request: (path: string, body?: unknown, origin?: string, token?: string) => Promise, companyId: string, otherId: string ) { const path = `/assets/${companyId}`; async function save(url: string, values: unknown) { const response = await request(url, { values }); assert.ok([200, 201].includes(response.status), await response.clone().text()); return AssetResponseSchema.parse(await response.json()).asset; } async function error(url: string, values: unknown, code: string, status = 409) { const response = await request(url, { values }); assert.equal(response.status, status); assert.equal(z.object({ code: z.string() }).parse(await response.json()).code, code); } async function read(url = path) { const response = await request(url); assert.equal(response.status, 200); return InventoryResponseSchema.parse(await response.json()); } const catalog = CatalogResponseSchema.parse( await (await request(`/asset-catalog/${companyId}`)).json() ); const monitor = catalog.items.find((item) => item.values.name === "Monitor"); assert.ok(monitor); const laptop = catalog.items.find((item) => item.values.name === "Portátil"); assert.ok(laptop); const inch = catalog.items.find((item) => item.values.name === "Tamaño de pantalla"); assert.ok(inch); async function site(company: string) { const response = await request(`/companies/${company}/sites`, { name: "Sede inventario", address: null, }); assert.equal(response.status, 201); const saved = CompanyResponseSchema.parse(await response.json()).company.sites.at(-1); assert.ok(saved); return saved; } const ownSite = await site(companyId); const foreignSite = await site(otherId); const input = { name: "MON-01", templateId: monitor.id, siteId: null, status: "available", notes: "", characteristics: {}, }; assert.equal((await read()).assets.length, 0); const created = await save(path, input); assert.equal(created.history.length, 1); assert.equal(created.id.charAt(14), "7"); assert.equal(created.history[0]?.id.charAt(14), "7"); assert.ok(created.history[0]?.actorName); assert.ok(created.history[0]?.actorId); assert.equal((await read(`/assets/${otherId}`)).assets.length, 0); await error(`/assets/${otherId}/${created.id}/update`, input, "ASSET_NOT_FOUND", 404); await error(path, { ...input, siteId: foreignSite.id }, "SITE_NOT_FOUND", 404); await error(path, { ...input, characteristics: { [inch.id]: 24 } }, "INVALID_CHARACTERISTICS"); await error( path, { ...input, characteristics: { [foreignSite.id]: 24 } }, "INVALID_CHARACTERISTICS" ); await error(path, { ...input, actorId: foreignSite.id }, "INVALID_REQUEST", 400); assert.equal((await request(path, { values: input }, "https://other.example")).status, 403); assert.equal((await request(path, { values: input }, undefined, "a".repeat(64))).status, 403); const inUse = await save(`${path}/${created.id}/update`, { ...input, siteId: ownSite.id, status: "in_use", characteristics: { [inch.id]: "24 pulgadas" }, }); assert.equal(inUse.id, created.id); assert.equal(inUse.history.length, 2); const unchanged = await save(`${path}/${created.id}/update`, inUse.values); assert.deepEqual(unchanged.history, inUse.history); await error( `${path}/${created.id}/update`, { ...inUse.values, templateId: laptop.id }, "TEMPLATE_FIXED" ); const retired = await save(`${path}/${created.id}/update`, { ...inUse.values, status: "retired", }); assert.equal(retired.history.length, 3); const section = { id: UniqueID.generateNewID().toPrimitive(), name: "Pantalla", description: "" }; const templateResponse = await request(`/asset-catalog/${companyId}`, { values: { kind: "template", name: "Monitor obligatorio inventario", sections: [section], description: "", fields: [{ fieldId: inch.id, required: true, sectionId: section.id }], }, }); assert.equal(templateResponse.status, 201); const templateId = SaveDefinitionResponseSchema.parse(await templateResponse.json()).savedId; await error(path, { ...input, templateId }, "REQUIRED_CHARACTERISTICS"); await error(`/assets/${otherId}`, { ...input, templateId }, "TEMPLATE_UNAVAILABLE"); const custom = await save(path, { ...input, templateId, name: "MON-02", characteristics: { [inch.id]: "0" }, }); const revisionId = custom.history[0]?.id; assert.equal( ( await request(`/asset-catalog/${companyId}/${templateId}/update`, { values: { kind: "template", name: "Plantilla renombrada", description: "", fields: [{ fieldId: inch.id, required: false }], }, }) ).status, 200 ); const current = (await read()).assets.find((asset) => asset.id === custom.id); assert.ok(current); assert.equal(current.specification.templateName, "Monitor obligatorio inventario"); assert.equal(current.specification.fields[0]?.required, true); assert.deepEqual(current.specification.sections, [section]); assert.equal(current.specification.fields[0]?.sectionId, section.id); await error( `${path}/${custom.id}/update`, { ...custom.values, characteristics: {} }, "REQUIRED_CHARACTERISTICS" ); assert.equal( (await request(`/asset-catalog/${companyId}/${templateId}/status`, { active: false })).status, 200 ); await error(path, { ...input, templateId }, "TEMPLATE_UNAVAILABLE"); const updated = await save(`${path}/${custom.id}/update`, { ...custom.values, notes: "Plantilla conservada", }); assert.equal(updated.history[0]?.id, revisionId); const stored = (await read()).assets.find((asset) => asset.id === updated.id); assert.deepEqual(stored, updated); const router = catalog.items.find((item) => item.values.name === "Router"); const ports = catalog.items.find((item) => item.values.name === "Puertos físicos"); assert.ok(router && ports); const networkAsset = await save(path, { ...input, name: "Router texto largo", templateId: router.id, characteristics: { [ports.id]: "24 RJ45\n4 SFP+" }, }); const networkUpdated = await save(`${path}/${networkAsset.id}/update`, { ...networkAsset.values, characteristics: { [ports.id]: "24 RJ45\n4 SFP+\nUSB de servicio" }, }); const networkStored = (await read()).assets.find((asset) => asset.id === networkUpdated.id); assert.deepEqual(networkStored, networkUpdated); assert.equal(networkStored?.history[0]?.values.characteristics[ports.id], "24 RJ45\n4 SFP+"); assert.equal(networkStored?.values.characteristics[ports.id], "24 RJ45\n4 SFP+\nUSB de servicio"); assert.equal((await request("/assets/00000000-0000-4000-8000-000000000001")).status, 404); }