import { UniqueID } from "@repo/rdx-ddd"; import { Maybe, Result } from "@repo/rdx-utils"; import type { RequestHandler } from "express"; import type { Sequelize } from "sequelize"; import type { InventoryContext } from "./application/asset.repository"; import { AssetUseCases } from "./application/asset.use-cases"; import { AssetCatalogUseCases } from "./application/asset-catalog.use-cases"; import { AssetRelationshipUseCases } from "./application/asset-relationship.use-cases"; import { BrandUseCases } from "./application/brand.use-cases"; import { SupportUseCases } from "./application/support.use-cases"; import { WorkstationUseCases } from "./application/workstation.use-cases"; import { seedAssetCatalog } from "./domain/asset-catalog-seed"; import { registerAssetRoutes } from "./infrastructure/http/asset.routes"; import { registerAssetCatalogRoutes } from "./infrastructure/http/asset-catalog.routes"; import { registerRelationshipRoutes } from "./infrastructure/http/asset-relationship.routes"; import { registerBrandRoutes } from "./infrastructure/http/brand.routes"; import { registerSupportRoutes } from "./infrastructure/http/support.routes"; import { registerWorkstationRoutes } from "./infrastructure/http/workstation.routes"; import { migrateInventory } from "./infrastructure/persistence/asset.model"; import { CatalogModel, migrateAssetCatalog, } from "./infrastructure/persistence/asset-catalog.model"; import { AssetCatalogPersistenceMapper } from "./infrastructure/persistence/asset-catalog-persistence.mapper"; import { AssetDashboardReader } from "./infrastructure/persistence/asset-dashboard-reader"; import { enforceAssetRelationalConstraints } from "./infrastructure/persistence/asset-relational-constraints"; import { initializeAssetInventorySchema } from "./infrastructure/persistence/asset-relational-schema"; import { migrateRelationships } from "./infrastructure/persistence/asset-relationship.model"; import { migrateBrands } from "./infrastructure/persistence/brand-migration"; import { SequelizeAssetRepository } from "./infrastructure/persistence/sequelize-asset.repository"; import { SequelizeAssetCatalogRepository } from "./infrastructure/persistence/sequelize-asset-catalog.repository"; import { SequelizeBrandRepository } from "./infrastructure/persistence/sequelize-brand.repository"; import { SequelizeSupportRepository } from "./infrastructure/persistence/sequelize-support.repository"; import { migrateSupport } from "./infrastructure/persistence/support-migration"; import { migrateWorkstations } from "./infrastructure/persistence/workstation.model"; 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."); } await migrateBrands(database); await migrateInventory(database); const brands = new BrandUseCases(new SequelizeBrandRepository(database)); await migrateRelationships(database); await migrateWorkstations(database); await initializeAssetInventorySchema(database); await enforceAssetRelationalConstraints(database); await migrateSupport(database); const support = new SupportUseCases(new SequelizeSupportRepository(database)); const assetRepository = new SequelizeAssetRepository(database); const inventory = new AssetUseCases(assetRepository); const workstations = new WorkstationUseCases(assetRepository); const relationships = new AssetRelationshipUseCases(assetRepository); const useCases = new AssetCatalogUseCases(repository); return { services: { dashboard: new AssetDashboardReader(database), inventory: { 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, })); }, list: async (companyId: UniqueID) => { const result = await assetRepository.get(companyId); if (!result.isSuccess) { throw new Error("Inventario no disponible."); } return inventoryAssignments(result.data); }, }, }, register: (app: Parameters[0]) => { registerBrandRoutes(app, brands, authenticate); registerAssetCatalogRoutes(app, useCases, authenticate); registerAssetRoutes(app, inventory, authenticate); registerRelationshipRoutes(app, relationships, authenticate); registerWorkstationRoutes(app, workstations, authenticate); registerSupportRoutes(app, support, authenticate); }, }; } function inventoryAssignments(context: InventoryContext) { const peopleByAsset = new Map>(); 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(); 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(); 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; }