- Added `verifyResourceLifecycle` integration to handle resource lifecycle operations. - Introduced `remove` method in `IResourceRepository` and implemented it in `SequelizeResourceRepository`. - Created `DeleteResourceDialog` component for confirming resource deletion. - Updated `resource.use-cases` to include `remove` and `setActive` methods for managing resource states. - Enhanced API routes to support resource status updates and deletions. - Added tests for resource lifecycle operations, ensuring correct behavior for activation, deactivation, and deletion. - Updated UI components to integrate new deletion functionality and provide feedback on resource status changes. - Improved localization for resource lifecycle actions in both English and Spanish.
163 lines
5.3 KiB
TypeScript
163 lines
5.3 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "node:test";
|
|
|
|
import { UniqueID } from "@repo/rdx-ddd";
|
|
import { Result } from "@repo/rdx-utils";
|
|
|
|
import { Resource } from "../domain/resource.aggregate";
|
|
import { ResourceCatalog } from "../domain/resource-catalog.aggregate";
|
|
import { ResourceCatalogError } from "../domain/resource-definition";
|
|
import { ResourceSpecification, ResourceValues } from "../domain/value-objects/resource-values.vo";
|
|
|
|
import type { IResourceRepository, InventoryContext } from "./resource.repository";
|
|
import { ResourceUseCases } from "./resource.use-cases";
|
|
|
|
function fixture() {
|
|
const company = UniqueID.generateNewID();
|
|
const actor = UniqueID.generateNewID();
|
|
const templateId = UniqueID.generateNewID().toPrimitive();
|
|
const fieldId = UniqueID.generateNewID().toPrimitive();
|
|
const spec = ResourceSpecification.create({
|
|
templateId,
|
|
templateName: "Aplicación",
|
|
fields: [{ fieldId, name: "Fabricante", type: "text", unit: "", choices: [], required: false }],
|
|
});
|
|
|
|
assert.ok(spec.isSuccess);
|
|
const values = ResourceValues.create(
|
|
{
|
|
name: "Office 2024",
|
|
templateId,
|
|
active: true,
|
|
notes: "Notas conservadas",
|
|
characteristics: { [fieldId]: "Microsoft" },
|
|
},
|
|
spec.data
|
|
);
|
|
|
|
assert.ok(values.isSuccess);
|
|
const created = Resource.create(
|
|
company,
|
|
spec.data,
|
|
values.data,
|
|
actor,
|
|
"2026-01-01T12:00:00.000Z"
|
|
);
|
|
|
|
assert.ok(created.isSuccess);
|
|
let resources = [created.data];
|
|
let inUse = false;
|
|
|
|
const context = (): InventoryContext => ({
|
|
catalog: ResourceCatalog.create(),
|
|
resources,
|
|
references: [],
|
|
actorNames: new Map([[actor.toPrimitive(), "Técnico"]]),
|
|
});
|
|
|
|
const repository: IResourceRepository = {
|
|
get: async () => Result.ok(context()),
|
|
save: async (id, action) => {
|
|
const changed = action({ ...context(), resources: id.equals(company) ? resources : [] });
|
|
|
|
if (!changed.isSuccess) {
|
|
return Result.fail(changed.error);
|
|
}
|
|
resources = [changed.data];
|
|
|
|
return Result.ok({ resource: changed.data, actorNames: context().actorNames });
|
|
},
|
|
remove: async (id, identity) => {
|
|
if (!(id.equals(company) && resources.some((resource) => resource.id.equals(identity)))) {
|
|
return Result.fail(new ResourceCatalogError("RESOURCE_NOT_FOUND"));
|
|
}
|
|
if (inUse) {
|
|
return Result.fail(new ResourceCatalogError("RESOURCE_IN_USE"));
|
|
}
|
|
resources = [];
|
|
|
|
return Result.ok(undefined);
|
|
},
|
|
};
|
|
|
|
return {
|
|
service: new ResourceUseCases(repository),
|
|
created: created.data,
|
|
company: company.toPrimitive(),
|
|
actor: actor.toPrimitive(),
|
|
setInUse: () => {
|
|
inUse = true;
|
|
},
|
|
};
|
|
}
|
|
|
|
test("recurso: activar/desactivar conserva datos e historial y repetir estado no añade revisiones", async () => {
|
|
const { service, company, actor, created } = fixture();
|
|
|
|
for (const [active, revisions] of [
|
|
[false, 2],
|
|
[false, 2],
|
|
[true, 3],
|
|
] as const) {
|
|
const result = await service.setActive(company, created.id.toPrimitive(), active, actor);
|
|
|
|
assert.ok(result.isSuccess);
|
|
assert.equal(result.data.resource.values.toPrimitive().active, active);
|
|
assert.equal(result.data.resource.history.length, revisions);
|
|
assert.deepEqual(
|
|
result.data.resource.values.toPrimitive().characteristics,
|
|
created.values.toPrimitive().characteristics
|
|
);
|
|
assert.equal(
|
|
result.data.resource.values.toPrimitive().notes,
|
|
created.values.toPrimitive().notes
|
|
);
|
|
assert.equal(result.data.resource.history.at(-1)?.actorId.toPrimitive(), actor);
|
|
}
|
|
});
|
|
|
|
test("recurso: valida identidades y rechaza actuar sobre recursos ajenos", async () => {
|
|
const { service, company, actor, created } = fixture();
|
|
const id = created.id.toPrimitive();
|
|
const invalid = await service.setActive("invalid", id, false, actor);
|
|
|
|
assert.ok(!invalid.isSuccess);
|
|
assert.equal(invalid.error.code, "INVALID_REQUEST");
|
|
const invalidActor = await service.setActive(company, id, false, "invalid");
|
|
|
|
assert.ok(!invalidActor.isSuccess);
|
|
const invalidDelete = await service.remove(company, "invalid");
|
|
|
|
assert.ok(!invalidDelete.isSuccess);
|
|
const other = UniqueID.generateNewID().toPrimitive();
|
|
const foreign = await service.setActive(other, id, false, actor);
|
|
|
|
assert.ok(!foreign.isSuccess);
|
|
assert.equal(foreign.error.code, "RESOURCE_NOT_FOUND");
|
|
const foreignDelete = await service.remove(other, id);
|
|
|
|
assert.ok(!foreignDelete.isSuccess);
|
|
assert.equal(foreignDelete.error.code, "RESOURCE_NOT_FOUND");
|
|
});
|
|
|
|
test("recurso: propaga el bloqueo por asociaciones y permite desactivar", async () => {
|
|
const { service, company, actor, created, setInUse } = fixture();
|
|
|
|
setInUse();
|
|
const removed = await service.remove(company, created.id.toPrimitive());
|
|
|
|
assert.ok(!removed.isSuccess);
|
|
assert.equal(removed.error.code, "RESOURCE_IN_USE");
|
|
assert.ok((await service.setActive(company, created.id.toPrimitive(), false, actor)).isSuccess);
|
|
});
|
|
|
|
test("recurso: elimina y la repetición devuelve ausencia sin efectos adicionales", async () => {
|
|
const { service, company, created } = fixture();
|
|
|
|
assert.ok((await service.remove(company, created.id.toPrimitive())).isSuccess);
|
|
const missing = await service.remove(company, created.id.toPrimitive());
|
|
|
|
assert.ok(!missing.isSuccess);
|
|
assert.equal(missing.error.code, "RESOURCE_NOT_FOUND");
|
|
});
|