2026-10-04 19:04:14 +00:00
|
|
|
import { z } from "zod/v4";
|
|
|
|
|
|
|
|
|
|
import { WorkstationValues } from "../../domain/value-objects/workstation-values";
|
|
|
|
|
import { Workstation } from "../../domain/workstation.aggregate";
|
|
|
|
|
import { WorkstationRevision } from "../../domain/workstation-revision.entity";
|
|
|
|
|
import { WorkstationInputSchema } from "../../domain/workstation-values";
|
|
|
|
|
|
|
|
|
|
import { inventoryIdentity } from "./asset-persistence.mapper";
|
|
|
|
|
import type {
|
|
|
|
|
WorkstationAssetModel,
|
|
|
|
|
WorkstationModel,
|
|
|
|
|
WorkstationRevisionModel,
|
|
|
|
|
} from "./workstation.model";
|
|
|
|
|
|
|
|
|
|
function valuesOf(raw: unknown, siteId: string | null, personId: string | null) {
|
2026-10-05 07:53:29 +00:00
|
|
|
// Las instantáneas anteriores no tenían recursos compartidos. Se interpretan como una lista vacía sin reescribir el historial.
|
|
|
|
|
const legacy = WorkstationInputSchema.extend({
|
|
|
|
|
sharedAssetIds: z.array(z.uuid()).max(200).optional(),
|
|
|
|
|
}).parse(raw);
|
|
|
|
|
const values = WorkstationValues.create({
|
|
|
|
|
...legacy,
|
|
|
|
|
sharedAssetIds: legacy.sharedAssetIds ?? [],
|
|
|
|
|
});
|
2026-10-04 19:04:14 +00:00
|
|
|
if (
|
|
|
|
|
!values.isSuccess ||
|
|
|
|
|
values.data.toPrimitive().siteId !== siteId ||
|
|
|
|
|
values.data.toPrimitive().personId !== personId
|
|
|
|
|
) {
|
|
|
|
|
throw new Error("Valores de puesto persistidos inconsistentes.");
|
|
|
|
|
}
|
|
|
|
|
return values.data;
|
|
|
|
|
}
|
|
|
|
|
export class WorkstationPersistenceMapper {
|
|
|
|
|
toDomain(
|
|
|
|
|
row: WorkstationModel,
|
|
|
|
|
revisions: readonly WorkstationRevisionModel[],
|
|
|
|
|
references: readonly WorkstationAssetModel[]
|
|
|
|
|
) {
|
|
|
|
|
const values = valuesOf(row.values, row.siteId, row.personId);
|
|
|
|
|
const ordered = [...revisions].sort((a, b) => a.position - b.position);
|
|
|
|
|
const history = ordered.map((revision, position) => {
|
|
|
|
|
if (
|
|
|
|
|
revision.position !== position ||
|
|
|
|
|
!z.iso.datetime().safeParse(revision.recordedAt).success ||
|
|
|
|
|
revision.recordedAt < (ordered[position - 1]?.recordedAt ?? "")
|
|
|
|
|
) {
|
|
|
|
|
throw new Error("Historial de puesto inconsistente.");
|
|
|
|
|
}
|
|
|
|
|
return WorkstationRevision.rehydrate(
|
|
|
|
|
{
|
|
|
|
|
values: valuesOf(revision.values, revision.siteId, revision.personId),
|
|
|
|
|
actorId: inventoryIdentity(revision.actorId),
|
|
|
|
|
recordedAt: revision.recordedAt,
|
|
|
|
|
},
|
|
|
|
|
inventoryIdentity(revision.id)
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
if (!(history.length && history.at(-1)?.values.equals(values))) {
|
|
|
|
|
throw new Error("Última revisión de puesto inconsistente.");
|
|
|
|
|
}
|
2026-10-05 07:53:29 +00:00
|
|
|
const expected = new Set(
|
|
|
|
|
history.flatMap((item) => [
|
|
|
|
|
...item.values.toPrimitive().assetIds,
|
|
|
|
|
...item.values.toPrimitive().sharedAssetIds,
|
|
|
|
|
])
|
|
|
|
|
);
|
2026-10-04 19:04:14 +00:00
|
|
|
if (
|
|
|
|
|
references.length !== expected.size ||
|
|
|
|
|
references.some(
|
|
|
|
|
(item) =>
|
|
|
|
|
item.companyId !== row.companyId ||
|
|
|
|
|
!expected.has(item.assetId) ||
|
|
|
|
|
item.activeKey !==
|
|
|
|
|
(values.active && values.assetIds.some((id) => id.toPrimitive() === item.assetId)
|
|
|
|
|
? `${row.companyId}:${item.assetId}`
|
|
|
|
|
: null)
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
throw new Error("Referencias de puesto inconsistentes.");
|
|
|
|
|
}
|
|
|
|
|
return Workstation.rehydrate(
|
|
|
|
|
{ companyId: inventoryIdentity(row.companyId), values, history },
|
|
|
|
|
inventoryIdentity(row.id)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
toPersistence(item: Workstation) {
|
|
|
|
|
const values = item.values.toPrimitive();
|
|
|
|
|
const companyId = item.companyId.toPrimitive();
|
|
|
|
|
const id = item.id.toPrimitive();
|
|
|
|
|
return {
|
|
|
|
|
workstation: { id, companyId, values, siteId: values.siteId, personId: values.personId },
|
|
|
|
|
revisions: item.history.map((revision, position) => ({
|
|
|
|
|
id: revision.id.toPrimitive(),
|
|
|
|
|
workstationId: id,
|
|
|
|
|
actorId: revision.actorId.toPrimitive(),
|
|
|
|
|
recordedAt: revision.recordedAt,
|
|
|
|
|
values: revision.values.toPrimitive(),
|
|
|
|
|
position,
|
|
|
|
|
siteId: revision.values.toPrimitive().siteId,
|
|
|
|
|
personId: revision.values.toPrimitive().personId,
|
|
|
|
|
})),
|
|
|
|
|
references: [
|
2026-10-05 07:53:29 +00:00
|
|
|
...new Set(
|
|
|
|
|
item.history.flatMap((revision) => [
|
|
|
|
|
...revision.values.toPrimitive().assetIds,
|
|
|
|
|
...revision.values.toPrimitive().sharedAssetIds,
|
|
|
|
|
])
|
|
|
|
|
),
|
2026-10-04 19:04:14 +00:00
|
|
|
].map((assetId) => ({
|
|
|
|
|
workstationId: id,
|
|
|
|
|
companyId,
|
|
|
|
|
assetId,
|
|
|
|
|
activeKey:
|
|
|
|
|
values.active && values.assetIds.includes(assetId) ? `${companyId}:${assetId}` : null,
|
|
|
|
|
})),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|