diff --git a/api/apps/geoprocessing/src/export/pieces-exporters/scenario-metadata.piece-exporter.ts b/api/apps/geoprocessing/src/export/pieces-exporters/scenario-metadata.piece-exporter.ts index d544b57346..2ede0a0d5b 100644 --- a/api/apps/geoprocessing/src/export/pieces-exporters/scenario-metadata.piece-exporter.ts +++ b/api/apps/geoprocessing/src/export/pieces-exporters/scenario-metadata.piece-exporter.ts @@ -50,6 +50,20 @@ export class ScenarioMetadataPieceExporter implements ExportPieceProcessor { return piece === ClonePiece.ScenarioMetadata; } + private async getStableIdForScenarioCostSurface( + costSurfaceId: string, + ): Promise { + return await this.entityManager + .createQueryBuilder() + .select(['stable_id']) + .from('cost_surfaces', 'cs') + .where('cs.id = :costSurfaceId', { + costSurfaceId: costSurfaceId, + }) + .execute() + .then((result: { stable_id: string }[]) => result[0]?.stable_id); + } + async run(input: ExportJobInput): Promise { const scenarioId = input.resourceId; @@ -77,6 +91,9 @@ export class ScenarioMetadataPieceExporter implements ExportPieceProcessor { throw new Error(errorMessage); } + const scenarioCostSurfaceStableId: string = + await this.getStableIdForScenarioCostSurface(scenario.cost_surface_id); + const [blmRange]: [SelectScenarioBlmResult] = await this.entityManager .createQueryBuilder() .select(['values', 'defaults', 'range']) @@ -101,7 +118,7 @@ export class ScenarioMetadataPieceExporter implements ExportPieceProcessor { solutionsAreLocked: scenario.solutions_are_locked, type: scenario.type, status: scenario.status ?? undefined, - cost_surface_id: scenario.cost_surface_id, + cost_surface_id: scenarioCostSurfaceStableId, }; const relativePath = ClonePieceRelativePathResolver.resolveFor( diff --git a/api/apps/geoprocessing/src/import/pieces-importers/project-cost-surfaces.piece-importer.ts b/api/apps/geoprocessing/src/import/pieces-importers/project-cost-surfaces.piece-importer.ts index 8029c509e0..8a07594ca7 100644 --- a/api/apps/geoprocessing/src/import/pieces-importers/project-cost-surfaces.piece-importer.ts +++ b/api/apps/geoprocessing/src/import/pieces-importers/project-cost-surfaces.piece-importer.ts @@ -123,7 +123,7 @@ export class ProjectCostSurfacesPieceImporter implements ImportPieceProcessor { .createQueryBuilder() .insert() .into('cost_surfaces') - .values(omit(costSurfaceData, ['origin_id'])) + .values(costSurfaceData) .execute(), ), ); diff --git a/api/apps/geoprocessing/src/import/pieces-importers/scenario-metadata.piece-importer.ts b/api/apps/geoprocessing/src/import/pieces-importers/scenario-metadata.piece-importer.ts index 89ea99b05d..823fd4a1ed 100644 --- a/api/apps/geoprocessing/src/import/pieces-importers/scenario-metadata.piece-importer.ts +++ b/api/apps/geoprocessing/src/import/pieces-importers/scenario-metadata.piece-importer.ts @@ -84,6 +84,21 @@ export class ScenarioMetadataPieceImporter implements ImportPieceProcessor { .execute(); } + private async mapCostSurfaceStableIdToIdOfClonedCostSurface( + em: EntityManager, + costSurfaceId: string, + projectId: string, + ): Promise { + return await em + .createQueryBuilder() + .select('id') + .from('cost_surfaces', 'cs') + .where('cs.stable_id = :costSurfaceId', { costSurfaceId }) + .andWhere('cs.project_id = :projectId', { projectId }) + .execute() + .then((result) => result[0]?.id); + } + async run(input: ImportJobInput): Promise { const { pieceResourceId: scenarioId, @@ -121,6 +136,13 @@ export class ScenarioMetadataPieceImporter implements ImportPieceProcessor { const scenarioCloning = resourceKind === ResourceKind.Scenario; await this.entityManager.transaction(async (em) => { + const idOfClonedCostSurfaceLinkedToScenario = + await this.mapCostSurfaceStableIdToIdOfClonedCostSurface( + em, + metadata.cost_surface_id, + projectId, + ); + if (scenarioCloning) { await this.updateScenario(em, scenarioId, metadata, input.ownerId); } else { @@ -135,7 +157,10 @@ export class ScenarioMetadataPieceImporter implements ImportPieceProcessor { em, scenarioId, projectId, - metadata, + { + ...metadata, + cost_surface_id: idOfClonedCostSurfaceLinkedToScenario, + }, input.ownerId, ); } diff --git a/api/apps/geoprocessing/test/integration/cloning/piece-exporters/project-cost-surface.piece-exporter.e2e-spec.ts b/api/apps/geoprocessing/test/integration/cloning/piece-exporters/project-cost-surface.piece-exporter.e2e-spec.ts index bff44e4eef..9b6d3958c6 100644 --- a/api/apps/geoprocessing/test/integration/cloning/piece-exporters/project-cost-surface.piece-exporter.e2e-spec.ts +++ b/api/apps/geoprocessing/test/integration/cloning/piece-exporters/project-cost-surface.piece-exporter.e2e-spec.ts @@ -1,7 +1,6 @@ import { geoprocessingConnections } from '@marxan-geoprocessing/ormconfig'; import { ClonePiece, ExportJobInput } from '@marxan/cloning'; import { ResourceKind } from '@marxan/cloning/domain'; -import { ProjectCustomFeaturesContent } from '@marxan/cloning/infrastructure/clone-piece-data/project-custom-features'; import { CloningFilesRepository } from '@marxan/cloning-files-repository'; import { GeoFeatureGeometry } from '@marxan/geofeatures'; import { FixtureType } from '@marxan/utils/tests/fixture-type'; @@ -9,14 +8,12 @@ import { Test } from '@nestjs/testing'; import { getEntityManagerToken, TypeOrmModule } from '@nestjs/typeorm'; import { isLeft, Right } from 'fp-ts/lib/Either'; import { Readable } from 'stream'; -import { EntityManager, In } from 'typeorm'; +import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; import { DeleteProjectAndOrganization, GivenCostSurfaceData, GivenCostSurfaces, - GivenFeatures, - GivenFeaturesData, GivenProjectExists, readSavedFile, } from '../fixtures';