2026-10-04 16:36:09 +00:00
|
|
|
import { UniqueID } from "@repo/rdx-ddd";
|
|
|
|
|
import { Maybe, Result } from "@repo/rdx-utils";
|
|
|
|
|
import type { RequestHandler } from "express";
|
|
|
|
|
import type { Sequelize } from "sequelize";
|
|
|
|
|
|
2026-10-09 23:37:10 +00:00
|
|
|
import type { InventoryContext } from "./application/asset.repository";
|
2026-10-04 16:36:09 +00:00
|
|
|
import { AssetUseCases } from "./application/asset.use-cases";
|
|
|
|
|
import { AssetCatalogUseCases } from "./application/asset-catalog.use-cases";
|
2026-10-04 19:04:14 +00:00
|
|
|
import { AssetRelationshipUseCases } from "./application/asset-relationship.use-cases";
|
2026-10-07 16:08:48 +00:00
|
|
|
import { BrandUseCases } from "./application/brand.use-cases";
|
2026-10-07 08:16:39 +00:00
|
|
|
import { SupportUseCases } from "./application/support.use-cases";
|
2026-10-04 19:04:14 +00:00
|
|
|
import { WorkstationUseCases } from "./application/workstation.use-cases";
|
2026-10-04 16:36:09 +00:00
|
|
|
import { seedAssetCatalog } from "./domain/asset-catalog-seed";
|
|
|
|
|
import { registerAssetRoutes } from "./infrastructure/http/asset.routes";
|
|
|
|
|
import { registerAssetCatalogRoutes } from "./infrastructure/http/asset-catalog.routes";
|
2026-10-04 19:04:14 +00:00
|
|
|
import { registerRelationshipRoutes } from "./infrastructure/http/asset-relationship.routes";
|
2026-10-07 16:08:48 +00:00
|
|
|
import { registerBrandRoutes } from "./infrastructure/http/brand.routes";
|
2026-10-07 08:16:39 +00:00
|
|
|
import { registerSupportRoutes } from "./infrastructure/http/support.routes";
|
2026-10-04 19:04:14 +00:00
|
|
|
import { registerWorkstationRoutes } from "./infrastructure/http/workstation.routes";
|
2026-10-09 23:37:10 +00:00
|
|
|
import {
|
|
|
|
|
migrateInventory,
|
|
|
|
|
migrateLegacyAssetAssignments,
|
|
|
|
|
} from "./infrastructure/persistence/asset.model";
|
2026-10-04 16:36:09 +00:00
|
|
|
import {
|
|
|
|
|
CatalogModel,
|
|
|
|
|
migrateAssetCatalog,
|
|
|
|
|
} from "./infrastructure/persistence/asset-catalog.model";
|
|
|
|
|
import { AssetCatalogPersistenceMapper } from "./infrastructure/persistence/asset-catalog-persistence.mapper";
|
feat(dashboard): implement dashboard schemas and API integration
- Added Zod schemas for dashboard queries, entries, summaries, and companies.
- Created dashboard API functions for fetching summary, work, attention, activity, and companies data.
- Developed dashboard components including BlockState, DashboardDetailsDialog, and DashboardPage for rendering dashboard information.
- Implemented quick create functionality for companies, tickets, interventions, assets, and resources.
- Introduced a new ResourceDashboardReader for querying resource-related data.
- Added a StatisticCard component for displaying key performance indicators in the dashboard.
2026-10-08 11:27:27 +00:00
|
|
|
import { AssetDashboardReader } from "./infrastructure/persistence/asset-dashboard-reader";
|
2026-10-10 09:41:42 +00:00
|
|
|
import { normalizeAssetInventory } from "./infrastructure/persistence/asset-normalization-migration";
|
|
|
|
|
import { enforceAssetRelationalConstraints } from "./infrastructure/persistence/asset-relational-constraints";
|
2026-10-04 19:04:14 +00:00
|
|
|
import { migrateRelationships } from "./infrastructure/persistence/asset-relationship.model";
|
2026-10-07 16:08:48 +00:00
|
|
|
import { importLegacyBrands, migrateBrands } from "./infrastructure/persistence/brand-migration";
|
2026-10-04 16:36:09 +00:00
|
|
|
import { SequelizeAssetRepository } from "./infrastructure/persistence/sequelize-asset.repository";
|
|
|
|
|
import { SequelizeAssetCatalogRepository } from "./infrastructure/persistence/sequelize-asset-catalog.repository";
|
2026-10-07 16:08:48 +00:00
|
|
|
import { SequelizeBrandRepository } from "./infrastructure/persistence/sequelize-brand.repository";
|
2026-10-07 08:16:39 +00:00
|
|
|
import { SequelizeSupportRepository } from "./infrastructure/persistence/sequelize-support.repository";
|
|
|
|
|
import { migrateSupport } from "./infrastructure/persistence/support-migration";
|
2026-10-04 19:04:14 +00:00
|
|
|
import { migrateWorkstations } from "./infrastructure/persistence/workstation.model";
|
2026-10-04 16:36:09 +00:00
|
|
|
export async function createAssetModule(database: Sequelize, authenticate: RequestHandler) {
|
|
|
|
|
await migrateAssetCatalog(database);
|
|
|
|
|
await CatalogModel.findOrCreate({
|
|
|
|
|
where: { catalogKey: "global" },
|
|
|
|
|
defaults: { id: UniqueID.generateNewID().toPrimitive(), catalogKey: "global" },
|
|
|
|
|
});
|
|
|
|
|
const repository = new SequelizeAssetCatalogRepository(
|
|
|
|
|
database,
|
|
|
|
|
new AssetCatalogPersistenceMapper()
|
|
|
|
|
);
|
|
|
|
|
const seeded = await repository.update(Maybe.none(), (catalog) =>
|
|
|
|
|
Result.ok(seedAssetCatalog(catalog))
|
|
|
|
|
);
|
|
|
|
|
if (!seeded.isSuccess) {
|
|
|
|
|
throw new Error("No se pudo inicializar el catálogo de activos.");
|
|
|
|
|
}
|
2026-10-07 16:08:48 +00:00
|
|
|
await migrateBrands(database);
|
2026-10-04 16:36:09 +00:00
|
|
|
await migrateInventory(database);
|
2026-10-07 16:08:48 +00:00
|
|
|
const brands = new BrandUseCases(new SequelizeBrandRepository(database));
|
2026-10-04 19:04:14 +00:00
|
|
|
await migrateRelationships(database);
|
|
|
|
|
await migrateWorkstations(database);
|
2026-10-09 23:37:10 +00:00
|
|
|
await migrateLegacyAssetAssignments(database);
|
2026-10-10 09:41:42 +00:00
|
|
|
await normalizeAssetInventory(database);
|
|
|
|
|
await importLegacyBrands(database);
|
|
|
|
|
await enforceAssetRelationalConstraints(database);
|
2026-10-07 08:16:39 +00:00
|
|
|
await migrateSupport(database);
|
|
|
|
|
const support = new SupportUseCases(new SequelizeSupportRepository(database));
|
2026-10-04 19:04:14 +00:00
|
|
|
const assetRepository = new SequelizeAssetRepository(database);
|
|
|
|
|
const inventory = new AssetUseCases(assetRepository);
|
|
|
|
|
const workstations = new WorkstationUseCases(assetRepository);
|
|
|
|
|
const relationships = new AssetRelationshipUseCases(assetRepository);
|
2026-10-04 16:36:09 +00:00
|
|
|
const useCases = new AssetCatalogUseCases(repository);
|
|
|
|
|
return {
|
2026-10-04 21:06:07 +00:00
|
|
|
services: {
|
feat(dashboard): implement dashboard schemas and API integration
- Added Zod schemas for dashboard queries, entries, summaries, and companies.
- Created dashboard API functions for fetching summary, work, attention, activity, and companies data.
- Developed dashboard components including BlockState, DashboardDetailsDialog, and DashboardPage for rendering dashboard information.
- Implemented quick create functionality for companies, tickets, interventions, assets, and resources.
- Introduced a new ResourceDashboardReader for querying resource-related data.
- Added a StatisticCard component for displaying key performance indicators in the dashboard.
2026-10-08 11:27:27 +00:00
|
|
|
dashboard: new AssetDashboardReader(database),
|
2026-10-04 21:06:07 +00:00
|
|
|
inventory: {
|
2026-10-07 09:41:56 +00:00
|
|
|
workstations: async (companyId: UniqueID) => {
|
|
|
|
|
const result = await assetRepository.get(companyId);
|
|
|
|
|
if (!result.isSuccess) {
|
|
|
|
|
throw new Error("Puestos no disponibles.");
|
|
|
|
|
}
|
|
|
|
|
return result.data.workstations.map((item) => ({
|
|
|
|
|
id: item.id,
|
|
|
|
|
name: item.values.toPrimitive().name,
|
|
|
|
|
active: item.values.toPrimitive().active,
|
|
|
|
|
}));
|
|
|
|
|
},
|
2026-10-04 21:06:07 +00:00
|
|
|
list: async (companyId: UniqueID) => {
|
|
|
|
|
const result = await assetRepository.get(companyId);
|
|
|
|
|
if (!result.isSuccess) {
|
|
|
|
|
throw new Error("Inventario no disponible.");
|
|
|
|
|
}
|
2026-10-09 23:37:10 +00:00
|
|
|
return inventoryAssignments(result.data);
|
2026-10-04 21:06:07 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2026-10-04 16:36:09 +00:00
|
|
|
register: (app: Parameters<typeof registerAssetCatalogRoutes>[0]) => {
|
2026-10-07 16:08:48 +00:00
|
|
|
registerBrandRoutes(app, brands, authenticate);
|
2026-10-04 16:36:09 +00:00
|
|
|
registerAssetCatalogRoutes(app, useCases, authenticate);
|
|
|
|
|
registerAssetRoutes(app, inventory, authenticate);
|
2026-10-04 19:04:14 +00:00
|
|
|
registerRelationshipRoutes(app, relationships, authenticate);
|
|
|
|
|
registerWorkstationRoutes(app, workstations, authenticate);
|
2026-10-07 08:16:39 +00:00
|
|
|
registerSupportRoutes(app, support, authenticate);
|
2026-10-04 16:36:09 +00:00
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
2026-10-09 23:37:10 +00:00
|
|
|
|
|
|
|
|
function inventoryAssignments(context: InventoryContext) {
|
|
|
|
|
const peopleByAsset = new Map<string, Set<string>>();
|
|
|
|
|
for (const workstation of context.workstations) {
|
|
|
|
|
const values = workstation.values.toPrimitive();
|
|
|
|
|
if (!(values.active && values.personId)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
for (const assetId of [...values.assetIds, ...values.sharedAssetIds]) {
|
|
|
|
|
const people = peopleByAsset.get(assetId) ?? new Set<string>();
|
|
|
|
|
people.add(values.personId);
|
|
|
|
|
peopleByAsset.set(assetId, people);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const assignments: {
|
|
|
|
|
id: UniqueID;
|
|
|
|
|
name: string;
|
|
|
|
|
personId: string | null;
|
|
|
|
|
available: boolean;
|
|
|
|
|
}[] = [];
|
|
|
|
|
for (const asset of context.assets) {
|
|
|
|
|
const values = asset.values.toPrimitive();
|
|
|
|
|
const people = peopleByAsset.get(asset.id.toPrimitive()) ?? new Set<string>();
|
|
|
|
|
if (people.size) {
|
|
|
|
|
for (const personId of people) {
|
|
|
|
|
assignments.push({
|
|
|
|
|
id: asset.id,
|
|
|
|
|
name: values.name,
|
|
|
|
|
personId,
|
|
|
|
|
available: values.status !== "retired",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
assignments.push({
|
|
|
|
|
id: asset.id,
|
|
|
|
|
name: values.name,
|
|
|
|
|
personId: null,
|
|
|
|
|
available: values.status !== "retired",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return assignments;
|
|
|
|
|
}
|