From 0cf5c6ad340acd086afc681528c9f326f8191a7e Mon Sep 17 00:00:00 2001 From: alexeh Date: Fri, 25 Aug 2023 02:13:17 +0300 Subject: [PATCH] update methodology calc., integrate new indicators --- ...92854789441-UpdateImpactStoredFunctions.ts | 200 ++++++++++++++++++ .../authentication.controller.ts | 14 ++ api/src/modules/h3-data/h3-data.repository.ts | 4 +- api/src/modules/h3-data/h3-data.service.ts | 12 +- api/src/modules/impact/impact.module.ts | 2 + api/src/modules/impact/impact.service.ts | 19 +- .../impact/views/impact-view.updater.ts | 38 ++++ .../sourcing-data-import.service.ts | 2 +- .../dto/indicator-coefficients.dto.ts | 32 ++- .../indicator-record-calculated-values.dto.ts | 4 +- .../indicator-records.module.ts | 6 +- .../impact-calculation.dependencies.ts | 107 ++++++++++ .../services/impact-calculator.service.ts | 154 +++++++------- .../indicator-dependency-manager.service.ts | 88 +++----- .../dto/indicator-computed-raw-data.dto.ts | 4 +- .../modules/indicators/indicator.entity.ts | 6 +- .../modules/indicators/indicators.service.ts | 4 +- ...ing-records-with-indicator-raw-data.dto.ts | 54 +---- .../e2e/authorization/authorization.spec.ts | 6 +- api/test/e2e/h3-data/h3-data.spec.ts | 7 +- api/test/e2e/h3-data/mocks/h3-data.mock.ts | 5 +- .../e2e/h3-data/mocks/h3-impact-map.mock.ts | 5 +- .../e2e/impact/impact-chart/chart.spec.ts | 8 +- .../e2e/impact/impact-table/impact.spec.ts | 32 +-- ...ed-interventions-scenario.preconditions.ts | 4 +- ...coefficients-intervention.preconditions.ts | 4 +- ...new-material-intervention.preconditions.ts | 4 +- ...new-supplier-intervention.preconditions.ts | 4 +- .../two-scenarios.preconditions.ts | 4 +- .../mixed-scenarios.preconditions.ts | 4 +- .../same-materials-scenarios.preconditions.ts | 4 +- .../e2e/impact/mocks/sorting.preconditions.ts | 4 +- api/test/e2e/indicators/indicators.spec.ts | 20 +- .../location-types.spec.ts | 8 +- .../intervention-validations.spec.ts | 50 +++-- api/test/e2e/targets/targets.spec.ts | 7 +- api/test/entity-mocks.ts | 9 +- .../import-data/xlsx-uploads/import-mocks.ts | 10 +- .../xlsx-uploads/sourcing-data-import.spec.ts | 6 +- .../indicator-records.service.spec.ts | 63 +++--- .../indicator-status-changes.spec.ts | 14 +- .../utils/indicator-records-preconditions.ts | 16 +- .../scenario-interventions-preconditions.ts | 16 +- 43 files changed, 695 insertions(+), 369 deletions(-) create mode 100644 api/src/migrations/1692854789441-UpdateImpactStoredFunctions.ts create mode 100644 api/src/modules/impact/views/impact-view.updater.ts create mode 100644 api/src/modules/indicator-records/services/impact-calculation.dependencies.ts diff --git a/api/src/migrations/1692854789441-UpdateImpactStoredFunctions.ts b/api/src/migrations/1692854789441-UpdateImpactStoredFunctions.ts new file mode 100644 index 0000000000..fa04185ee3 --- /dev/null +++ b/api/src/migrations/1692854789441-UpdateImpactStoredFunctions.ts @@ -0,0 +1,200 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class UpdateImpactStoredFunctions1692854789441 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + /** + * @description: This function is used to get the h3 table name and column name for a given indicator by its name code + */ + await queryRunner.query(` + CREATE OR REPLACE FUNCTION get_h3_table_column_for_indicators_by_name_code(name_code text) + RETURNS TABLE (h3_table_name varchar, h3_column_name varchar, h3_resolution int) AS + $$ + SELECT h3_data."h3tableName", h3_data."h3columnName", h3_data."h3resolution" + FROM h3_data + INNER JOIN "indicator" ind ON ind."id" = h3_data."indicatorId" + WHERE ind."nameCode" = name_code + $$ + LANGUAGE SQL;`); + + /** + * @description: Calculates Impact for deforestation, climate risk, carbon and natural conversion + * + * @notes: ##NOTE: Assuming that deforestation-ghg emissions/human land use has been preprocessed and stored in the ddbb + * ## UPDATED DEFORESTATION, CLIMATE RISK FORMULAS/CARBON, NATURAL CONVERSION: + */ + + await queryRunner.query(` + CREATE OR REPLACE FUNCTION get_annual_landscape_impact_over_georegion( + geo_region_id uuid, + name_code text, + material_id uuid, + h3_material_type material_to_h3_type_enum + ) + RETURNS float AS + $$ + DECLARE + h3_resolution integer; + indicator_h3_table_name varchar; + indicator_h3_column_name varchar; + h3_indicator_resolution varchar; + material_h3_table_name varchar; + material_h3_column_name varchar; + sum float; + BEGIN + + -- Get h3data table name, column for indicator given name_code + SELECT * INTO indicator_h3_table_name, indicator_h3_column_name, h3_indicator_resolution + FROM get_h3_table_column_for_indicators_by_name_code(name_code); + + -- Get h3data table name, column and resolution for the material, given the material id and h3_ + SELECT * INTO material_h3_table_name, material_h3_column_name, h3_resolution + FROM get_h3_table_column_for_material(material_id, h3_material_type); + + -- Sum landscape impact values + EXECUTE format( + 'SELECT sum(h3ind.%I * h3prod.%I ) + FROM + get_h3_uncompact_geo_region($1, $2) geo_region + INNER JOIN %I h3ind ON h3ind.h3index = geo_region.h3index + INNER JOIN %I h3prod ON h3ind.h3index = h3prod.h3index; + ', indicator_h3_column_name, material_h3_column_name, indicator_h3_table_name, material_h3_table_name) + USING geo_region_id, h3_resolution + INTO sum; + RETURN sum; + END; + $$ + LANGUAGE plpgsql; + `); + /** + * @description: Calculates Impact for new indicators added as part of this change + * + * @notes: ## NEW INDICATORS: + * + * ## Water quality - use the same function as the blue water footprint + * #I have slightly modified the formula to make it dependent on the indicator table + */ + + await queryRunner.query(` + CREATE OR REPLACE FUNCTION get_indicator_coefficient_impact( + name_code text, + adminRegionId uuid, + material_id uuid) + RETURNS float AS + $$ + DECLARE + indicator_id uuid; + value float; + BEGIN + + --get indicatorId + SELECT "id" INTO indicator_id FROM "indicator" + WHERE "nameCode" = name_code; + + -- get water footprint value by location, material and indicator + EXECUTE format( + 'SELECT + COALESCE ( + ( + SELECT ic."value" /1000 --convert the m3 to Mm3 + FROM "indicator_coefficient" ic + WHERE ic."adminRegionId" = $1 + AND ic."materialId" = $2 + AND ic."indicatorId" = $3 + AND ic."value" IS NOT NULL + ), + ( + SELECT ic."value" /1000 --convert the m3 to Mm3 + FROM "indicator_coefficient" ic + WHERE ic."adminRegionId" IS NULL + AND ic."materialId" = $2 + AND ic."indicatorId" = $3 + AND ic."value" IS NOT NULL + ) + ) AS value;' + ) + USING adminRegionId, material_id, indicator_id + INTO value; + RETURN value; + END; + $$ + LANGUAGE plpgsql; + `); + + await queryRunner.query(` + DROP FUNCTION IF EXISTS get_percentage_water_stress_area; + + CREATE OR REPLACE FUNCTION get_percentage_water_stress_area( +geo_region_id uuid, +name_code text +) +RETURNS float AS +$$ + DECLARE + aqueduct_h3_table_name varchar; + aqueduct_h3_column_name varchar; + h3_resolution integer; + percentage float; + + BEGIN + + -- Get h3data table name, column + SELECT * INTO aqueduct_h3_table_name, aqueduct_h3_column_name, h3_resolution + FROM get_h3_table_column_for_indicators_by_name_code(name_code); + + + EXECUTE format( + 'SELECT reduced.ws_area/ reduced.g_area as percentage + FROM + (SELECT + sum(case when aqueduct.%I > 3 then 1 else 0 end) ws_area, count(aqueduct.%I) g_area + FROM get_h3_uncompact_geo_region($1, $2) geo_region + INNER JOIN %I aqueduct ON aqueduct.h3index = geo_region.h3index) reduced + WHERE reduced.g_area > 0;', + aqueduct_h3_column_name, + aqueduct_h3_column_name, + aqueduct_h3_table_name + ) + USING geo_region_id, h3_resolution + INTO percentage; + RETURN percentage; + END; +$$ +LANGUAGE plpgsql;`); + + await queryRunner.query(`DROP FUNCTION IF EXISTS sum_h3_cropland_area`); + + await queryRunner.query( + `DROP FUNCTION IF EXISTS sum_weighted_deforestation_over_georegion`, + ); + + await queryRunner.query( + `DROP FUNCTION IF EXISTS sum_weighted_carbon_over_georegion`, + ); + + await queryRunner.query(`DROP FUNCTION IF EXISTS get_blfw_impact`); + } + + /** + * @description: Remove procedures that are no longer needed + */ + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DROP FUNCTION IF EXISTS get_annual_landscape_impact_over_georegion`, + ); + + await queryRunner.query( + `DROP FUNCTION IF EXISTS get_indicator_coefficient_impact`, + ); + + await queryRunner.query( + `DROP FUNCTION IF EXISTS get_h3_table_column_for_indicators_by_name_code`, + ); + + await queryRunner.query( + `DROP FUNCTION IF EXISTS get_percentage_water_stress_area`, + ); + } +} diff --git a/api/src/modules/authentication/authentication.controller.ts b/api/src/modules/authentication/authentication.controller.ts index 6ed4862698..4e08993e8b 100644 --- a/api/src/modules/authentication/authentication.controller.ts +++ b/api/src/modules/authentication/authentication.controller.ts @@ -26,6 +26,8 @@ import { ResetPasswordDto } from 'modules/authentication/dto/reset-password.dto' import { GetUser } from 'decorators/get-user.decorator'; import { JSONAPIUserData, User } from 'modules/users/user.entity'; import { UsersService } from 'modules/users/users.service'; +import { IndicatorQueryDependencyManager } from '../indicator-records/services/indicator-dependency-manager.service'; +import { INDICATOR_NAME_CODES } from '../indicators/indicator.entity'; @Controller('/auth') @ApiTags('Authentication') @@ -102,4 +104,16 @@ export class AuthenticationController { ): Promise { return this.authenticationService.login(req.user); } + + @Public() + @Post('/test') + test(): any { + const builder: IndicatorQueryDependencyManager = + new IndicatorQueryDependencyManager(); + + const namecodes: string[] = Object.values(INDICATOR_NAME_CODES); + console.log(namecodes); + + return builder.buildQueryForImport(namecodes as INDICATOR_NAME_CODES[]); + } } diff --git a/api/src/modules/h3-data/h3-data.repository.ts b/api/src/modules/h3-data/h3-data.repository.ts index 02b1c53323..bea425c9a7 100644 --- a/api/src/modules/h3-data/h3-data.repository.ts +++ b/api/src/modules/h3-data/h3-data.repository.ts @@ -17,7 +17,7 @@ import { NotFoundException, ServiceUnavailableException, } from '@nestjs/common'; -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; import { MATERIAL_TO_H3_TYPE } from 'modules/materials/material-to-h3.entity'; import { GetActualVsScenarioImpactMapDto, @@ -237,7 +237,7 @@ export class H3DataRepository extends Repository { * @param year */ async getIndicatorH3ByTypeAndClosestYear( - type: INDICATOR_TYPES, + type: INDICATOR_NAME_CODES, year: number, ): Promise { const queryBuilder: SelectQueryBuilder = this.dataSource diff --git a/api/src/modules/h3-data/h3-data.service.ts b/api/src/modules/h3-data/h3-data.service.ts index df1be5ddd9..6c65930f3e 100644 --- a/api/src/modules/h3-data/h3-data.service.ts +++ b/api/src/modules/h3-data/h3-data.service.ts @@ -4,7 +4,7 @@ import { H3Data, H3IndexValueData } from 'modules/h3-data/h3-data.entity'; import { MaterialsService } from 'modules/materials/materials.service'; import { IndicatorsService } from 'modules/indicators/indicators.service'; import { UnitConversionsService } from 'modules/unit-conversions/unit-conversions.service'; -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; import { SourcingRecordsService } from 'modules/sourcing-records/sourcing-records.service'; import { H3DataYearsService } from 'modules/h3-data/services/h3-data-years.service'; import { MaterialsToH3sService } from 'modules/materials/materials-to-h3s.service'; @@ -107,20 +107,20 @@ export class H3DataService { } getIndicatorH3sByTypeAndClosestYear( - indicatorTypes: INDICATOR_TYPES[], + indicatorTypes: INDICATOR_NAME_CODES[], year: number, - ): Promise> { + ): Promise> { return indicatorTypes.reduce( async ( - previousValue: Promise>, - currentValue: INDICATOR_TYPES, + previousValue: Promise>, + currentValue: INDICATOR_NAME_CODES, ) => { const h3data: H3Data | undefined = await this.h3DataRepository.getIndicatorH3ByTypeAndClosestYear( currentValue, year, ); - const map: Map = await previousValue; + const map: Map = await previousValue; if (h3data) { map.set(currentValue, h3data); diff --git a/api/src/modules/impact/impact.module.ts b/api/src/modules/impact/impact.module.ts index ecefe234be..42a373ff7f 100644 --- a/api/src/modules/impact/impact.module.ts +++ b/api/src/modules/impact/impact.module.ts @@ -12,6 +12,7 @@ import { ScenarioVsScenarioImpactService } from 'modules/impact/comparison/scena import { MaterialsService } from 'modules/materials/materials.service'; import { SourcingLocationsModule } from 'modules/sourcing-locations/sourcing-locations.module'; import { AuthorizationModule } from 'modules/authorization/authorization.module'; +import { ImpactViewUpdater } from 'modules/impact/views/impact-view.updater'; @Module({ imports: [ @@ -29,6 +30,7 @@ import { AuthorizationModule } from 'modules/authorization/authorization.module' ActualVsScenarioImpactService, ScenarioVsScenarioImpactService, MaterialsService, + ImpactViewUpdater, ], controllers: [ImpactController], exports: [ diff --git a/api/src/modules/impact/impact.service.ts b/api/src/modules/impact/impact.service.ts index 8e47f81f19..74f7659024 100644 --- a/api/src/modules/impact/impact.service.ts +++ b/api/src/modules/impact/impact.service.ts @@ -30,8 +30,7 @@ import { ImpactDataTableAuxMap, } from 'modules/impact/base-impact.service'; import { SourcingLocationsService } from 'modules/sourcing-locations/sourcing-locations.service'; -import { IMPACT_VIEW_NAME } from 'modules/impact/views/impact.materialized-view.entity'; -import { DataSource } from 'typeorm'; +import { ImpactViewUpdater } from 'modules/impact/views/impact-view.updater'; @Injectable() export class ImpactService extends BaseImpactService { @@ -45,7 +44,7 @@ export class ImpactService extends BaseImpactService { protected readonly materialsService: MaterialsService, protected readonly sourcingRecordService: SourcingRecordsService, protected readonly sourcingLocationsService: SourcingLocationsService, - private readonly dataSource: DataSource, + private readonly viewUpdater: ImpactViewUpdater, ) { super( indicatorService, @@ -217,19 +216,7 @@ export class ImpactService extends BaseImpactService { } async updateImpactView(): Promise { - const result: any = await this.dataSource.query( - `SELECT * FROM pg_matviews WHERE matviewname = '${IMPACT_VIEW_NAME}'`, - ); - if (!result[0].ispopulated) { - this.logger.warn('Populating Impact View for the first time...'); - return this.dataSource.query( - `REFRESH MATERIALIZED VIEW ${IMPACT_VIEW_NAME} WITH DATA`, - ); - } - this.logger.warn('Refreshing Impact View...'); - return this.dataSource.query( - `REFRESH MATERIALIZED VIEW CONCURRENTLY ${IMPACT_VIEW_NAME} WITH DATA`, - ); + return this.viewUpdater.updateImpactView(); } private buildImpactTable( diff --git a/api/src/modules/impact/views/impact-view.updater.ts b/api/src/modules/impact/views/impact-view.updater.ts new file mode 100644 index 0000000000..b2f9651a73 --- /dev/null +++ b/api/src/modules/impact/views/impact-view.updater.ts @@ -0,0 +1,38 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { DataSource } from 'typeorm'; +import { IMPACT_VIEW_NAME } from 'modules/impact/views/impact.materialized-view.entity'; + +@Injectable() +export class ImpactViewUpdater { + logger: Logger = new Logger(ImpactViewUpdater.name); + + constructor(private readonly dataSource: DataSource) {} + + async updateImpactView(): Promise { + if (await this.isViewEmpty()) { + return this.populateViewForTheFirstTime(); + } + return this.refreshView(); + } + + private async isViewEmpty(): Promise { + const result: any = await this.dataSource.query( + `SELECT * FROM pg_matviews WHERE matviewname = '${IMPACT_VIEW_NAME}'`, + ); + return !result[0].ispopulated; + } + + private async populateViewForTheFirstTime(): Promise { + this.logger.warn('Populating Impact View for the first time...'); + return this.dataSource.query( + `REFRESH MATERIALIZED VIEW ${IMPACT_VIEW_NAME} WITH DATA`, + ); + } + + private async refreshView(): Promise { + this.logger.warn('Refreshing Impact View...'); + return this.dataSource.query( + `REFRESH MATERIALIZED VIEW CONCURRENTLY ${IMPACT_VIEW_NAME} WITH DATA`, + ); + } +} diff --git a/api/src/modules/import-data/sourcing-data/sourcing-data-import.service.ts b/api/src/modules/import-data/sourcing-data/sourcing-data-import.service.ts index 36037c96bd..7fad40a796 100644 --- a/api/src/modules/import-data/sourcing-data/sourcing-data-import.service.ts +++ b/api/src/modules/import-data/sourcing-data/sourcing-data-import.service.ts @@ -185,11 +185,11 @@ export class SourcingDataImportService { // TODO: Current approach calculates Impact for all Sourcing Records present in the DB // Getting H3 data for calculations is done within DB so we need to improve the error handling // TBD: What to do when there is no H3 for a Material + try { await this.impactCalculator.calculateImpactForAllSourcingRecords( activeIndicators, ); - this.logger.log('Indicator Records generated'); await this.impactService.updateImpactView(); } catch (err: any) { diff --git a/api/src/modules/indicator-coefficients/dto/indicator-coefficients.dto.ts b/api/src/modules/indicator-coefficients/dto/indicator-coefficients.dto.ts index fd5efd394a..382f34ee11 100644 --- a/api/src/modules/indicator-coefficients/dto/indicator-coefficients.dto.ts +++ b/api/src/modules/indicator-coefficients/dto/indicator-coefficients.dto.ts @@ -1,4 +1,4 @@ -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; import { IsNotEmpty, IsNumber, IsOptional, Max, Min } from 'class-validator'; import { ApiPropertyOptional } from '@nestjs/swagger'; @@ -8,7 +8,7 @@ export class IndicatorCoefficientsDto { @Max(1000000) @Min(0) @IsNumber() - [INDICATOR_TYPES.WATER_USE]: number; + [INDICATOR_NAME_CODES.WATER_USE]: number; @ApiPropertyOptional() @IsOptional() @@ -16,7 +16,7 @@ export class IndicatorCoefficientsDto { @Min(0) @IsNotEmpty() @IsNumber() - [INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE]: number; + [INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE]: number; @ApiPropertyOptional() @IsOptional() @@ -24,7 +24,7 @@ export class IndicatorCoefficientsDto { @Min(0) @IsNotEmpty() @IsNumber() - [INDICATOR_TYPES.CLIMATE_RISK]: number; + [INDICATOR_NAME_CODES.CLIMATE_RISK]: number; @ApiPropertyOptional() @IsOptional() @@ -32,7 +32,7 @@ export class IndicatorCoefficientsDto { @Min(0) @IsNotEmpty() @IsNumber() - [INDICATOR_TYPES.DEFORESTATION_RISK]: number; + [INDICATOR_NAME_CODES.DEFORESTATION_RISK]: number; @ApiPropertyOptional() @IsOptional() @@ -40,7 +40,7 @@ export class IndicatorCoefficientsDto { @Min(0) @IsNotEmpty() @IsNumber() - [INDICATOR_TYPES.LAND_USE]: number; + [INDICATOR_NAME_CODES.LAND_USE]: number; @ApiPropertyOptional() @IsOptional() @@ -48,7 +48,7 @@ export class IndicatorCoefficientsDto { @Min(0) @IsNotEmpty() @IsNumber() - [INDICATOR_TYPES.SATELLIGENCE_DEFORESTATION]: number; + [INDICATOR_NAME_CODES.SATELLIGENCE_DEFORESTATION]: number; @ApiPropertyOptional() @IsOptional() @@ -56,5 +56,21 @@ export class IndicatorCoefficientsDto { @Min(0) @IsNotEmpty() @IsNumber() - [INDICATOR_TYPES.SATELLIGENCE_DEFORESTATION_RISK]: number; + [INDICATOR_NAME_CODES.SATELLIGENCE_DEFORESTATION_RISK]: number; + + @ApiPropertyOptional() + @IsOptional() + @Max(1000000) + @Min(0) + @IsNotEmpty() + @IsNumber() + [INDICATOR_NAME_CODES.NATURAL_ECOSYSTEM_CONVERSION_RISK]: number; + + @ApiPropertyOptional() + @IsOptional() + @Max(1000000) + @Min(0) + @IsNotEmpty() + @IsNumber() + [INDICATOR_NAME_CODES.WATER_QUALITY]: number; } diff --git a/api/src/modules/indicator-records/dto/indicator-record-calculated-values.dto.ts b/api/src/modules/indicator-records/dto/indicator-record-calculated-values.dto.ts index 2fde6296b8..758852ec4a 100644 --- a/api/src/modules/indicator-records/dto/indicator-record-calculated-values.dto.ts +++ b/api/src/modules/indicator-records/dto/indicator-record-calculated-values.dto.ts @@ -3,7 +3,7 @@ * on the fly * @note: This could be probably done within the DB in the future */ -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; export class IndicatorRecordCalculatedValuesDto { sourcingRecordId: string; @@ -12,5 +12,5 @@ export class IndicatorRecordCalculatedValuesDto { landPerTon: number; landUse: number; - values: Map; + values: Map; } diff --git a/api/src/modules/indicator-records/indicator-records.module.ts b/api/src/modules/indicator-records/indicator-records.module.ts index 5aa2c81cec..29a0dc4e0b 100644 --- a/api/src/modules/indicator-records/indicator-records.module.ts +++ b/api/src/modules/indicator-records/indicator-records.module.ts @@ -9,7 +9,7 @@ import { MaterialsModule } from 'modules/materials/materials.module'; import { SourcingRecordsModule } from 'modules/sourcing-records/sourcing-records.module'; import { CachedDataModule } from 'modules/cached-data/cached-data.module'; import { ImpactCalculator } from 'modules/indicator-records/services/impact-calculator.service'; -import { IndicatorDependencyManager } from 'modules/indicator-records/services/indicator-dependency-manager.service'; +import { IndicatorQueryDependencyManager } from 'modules/indicator-records/services/indicator-dependency-manager.service'; import { IndicatorRecordRepository } from 'modules/indicator-records/indicator-record.repository'; @Module({ @@ -26,13 +26,13 @@ import { IndicatorRecordRepository } from 'modules/indicator-records/indicator-r IndicatorRecordsService, IndicatorRecordRepository, ImpactCalculator, - IndicatorDependencyManager, + IndicatorQueryDependencyManager, ], exports: [ IndicatorRecordsService, IndicatorRecordRepository, ImpactCalculator, - IndicatorDependencyManager, + IndicatorQueryDependencyManager, ], }) export class IndicatorRecordsModule {} diff --git a/api/src/modules/indicator-records/services/impact-calculation.dependencies.ts b/api/src/modules/indicator-records/services/impact-calculation.dependencies.ts new file mode 100644 index 0000000000..52742c4846 --- /dev/null +++ b/api/src/modules/indicator-records/services/impact-calculation.dependencies.ts @@ -0,0 +1,107 @@ +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; + +/** + * @description Database level dependencies for computing raw values for indicators + * + * @note: This could use a second thought, but time is tight + * + */ + +export class QueryPropertyNamesType { + production: 'production'; + harvest: 'harvest'; + rawDeforestation: 'rawDeforestation'; + rawNaturalConversion: 'rawNaturalConversion'; + rawClimateRisk: 'rawClimateRisk'; + rawWaterUse: 'rawWaterUse'; + rawUnsustainableWaterUse: 'rawUnsustainableWaterUse'; + rawWaterQuality: 'rawWaterQuality'; + satDeforestation: 'satDeforestation'; + satDeforestationRisk: 'satDeforestationRisk'; +} + +export class QueryPropertyTypes { + production: number; + harvest: number; + rawDeforestation: number; + rawNaturalConversion: number; + rawClimateRisk: number; + rawWaterUse: number; + rawUnsustainableWaterUse: number; + rawWaterQuality: number; + satDeforestation: number; + satDeforestationRisk: number; +} + +export const QueryPropertyNames: QueryPropertyNamesType = { + production: 'production', + harvest: 'harvest', + rawDeforestation: 'rawDeforestation', + rawNaturalConversion: 'rawNaturalConversion', + rawClimateRisk: 'rawClimateRisk', + rawWaterUse: 'rawWaterUse', + rawUnsustainableWaterUse: 'rawUnsustainableWaterUse', + rawWaterQuality: 'rawWaterQuality', + satDeforestation: 'satDeforestation', + satDeforestationRisk: 'satDeforestationRisk', +} as const; + +export type ImpactQueryPropertyName = + typeof QueryPropertyNames[keyof typeof QueryPropertyNames]; + +export type ImpactQueryExpression = string; + +export type ImpactPropertyToQueryFunction = + | ((nameCode: INDICATOR_NAME_CODES) => ImpactQueryExpression) + | (() => ImpactQueryExpression); + +export const INDICATOR_NAME_CODE_TO_QUERY_MAP: { + [key in INDICATOR_NAME_CODES]: { + [key in ImpactQueryPropertyName]?: ImpactPropertyToQueryFunction; + }; +} = { + [INDICATOR_NAME_CODES.LAND_USE]: { + harvest: () => + `sum_material_over_georegion($1, $2, 'harvest') as "${QueryPropertyNames.harvest}"`, + production: () => + `sum_material_over_georegion($1, $2, 'producer') as "${QueryPropertyNames.production}"`, + }, + [INDICATOR_NAME_CODES.DEFORESTATION_RISK]: { + production: () => + `sum_material_over_georegion($1, $2, 'producer') as "${QueryPropertyNames.production}"`, + rawDeforestation: (nameCode: INDICATOR_NAME_CODES) => + `get_annual_landscape_impact_over_georegion($1, '${nameCode}', $2, 'producer') as "${QueryPropertyNames.rawDeforestation}"`, + }, + [INDICATOR_NAME_CODES.CLIMATE_RISK]: { + production: () => + `sum_material_over_georegion($1, $2, 'producer') as "${QueryPropertyNames.production}"`, + rawClimateRisk: (nameCode: INDICATOR_NAME_CODES) => + `get_annual_landscape_impact_over_georegion($1,'${nameCode}', $2, 'producer') as "${QueryPropertyNames.rawClimateRisk}"`, + }, + [INDICATOR_NAME_CODES.WATER_QUALITY]: { + rawWaterQuality: (nameCode: INDICATOR_NAME_CODES) => + `get_indicator_coefficient_impact('${nameCode}', $3, $2) as "${QueryPropertyNames.rawWaterQuality}"`, + }, + [INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE]: { + rawUnsustainableWaterUse: (nameCode: INDICATOR_NAME_CODES) => + `get_percentage_water_stress_area($1, '${nameCode}') as "${QueryPropertyNames.rawUnsustainableWaterUse}"`, + }, + [INDICATOR_NAME_CODES.NATURAL_ECOSYSTEM_CONVERSION_RISK]: { + production: () => + `sum_material_over_georegion($1, $2, 'producer') as "${QueryPropertyNames.production}"`, + rawNaturalConversion: (nameCode: INDICATOR_NAME_CODES) => + `get_annual_landscape_impact_over_georegion($1, '${nameCode}', $2, 'producer') as "${QueryPropertyNames.rawNaturalConversion}"`, + }, + [INDICATOR_NAME_CODES.SATELLIGENCE_DEFORESTATION]: { + satDeforestation: () => + ` sum_satelligence_deforestation_over_georegion($1) as "${QueryPropertyNames.satDeforestation}"`, + }, + [INDICATOR_NAME_CODES.SATELLIGENCE_DEFORESTATION_RISK]: { + satDeforestationRisk: () => + `sum_satelligence_deforestation_risk_over_georegion($1) as "${QueryPropertyNames.satDeforestationRisk}"`, + }, + [INDICATOR_NAME_CODES.WATER_USE]: { + rawWaterUse: (nameCode: INDICATOR_NAME_CODES) => + `get_indicator_coefficient_impact('${nameCode}', $3, $2) as "${QueryPropertyNames.rawWaterUse}"`, + }, +}; diff --git a/api/src/modules/indicator-records/services/impact-calculator.service.ts b/api/src/modules/indicator-records/services/impact-calculator.service.ts index 36c17c073b..2da7d24b04 100644 --- a/api/src/modules/indicator-records/services/impact-calculator.service.ts +++ b/api/src/modules/indicator-records/services/impact-calculator.service.ts @@ -4,14 +4,11 @@ import { ServiceUnavailableException, } from '@nestjs/common'; import { IndicatorRecordRepository } from 'modules/indicator-records/indicator-record.repository'; -import { - IndicatorRawDataBySourcingRecord, - SourcingRecordsWithIndicatorRawDataDtoV2, -} from 'modules/sourcing-records/dto/sourcing-records-with-indicator-raw-data.dto'; +import { SourcingRecordsWithIndicatorRawData } from 'modules/sourcing-records/dto/sourcing-records-with-indicator-raw-data.dto'; import { Indicator, + INDICATOR_NAME_CODES, INDICATOR_STATUS, - INDICATOR_TYPES, } from 'modules/indicators/indicator.entity'; import { DataSource } from 'typeorm'; import { @@ -26,7 +23,7 @@ import { MaterialsToH3sService } from 'modules/materials/materials-to-h3s.servic import { IndicatorsService } from 'modules/indicators/indicators.service'; import { SourcingRecord } from 'modules/sourcing-records/sourcing-record.entity'; import { H3DataService } from 'modules/h3-data/h3-data.service'; -import { IndicatorDependencyManager } from 'modules/indicator-records/services/indicator-dependency-manager.service'; +import { IndicatorQueryDependencyManager } from 'modules/indicator-records/services/indicator-dependency-manager.service'; import { CachedDataService } from 'modules/cached-data/cached-data.service'; import { CACHED_DATA_TYPE, @@ -40,7 +37,7 @@ import { */ export interface CachedRawData { - rawData: IndicatorRawDataBySourcingRecord; + rawData: SourcingRecordsWithIndicatorRawData; } @Injectable() @@ -51,7 +48,7 @@ export class ImpactCalculator { private readonly indicatorRecordRepository: IndicatorRecordRepository, private readonly materialToH3: MaterialsToH3sService, private readonly indicatorService: IndicatorsService, - private readonly dependencyManager: IndicatorDependencyManager, + private readonly dependencyManager: IndicatorQueryDependencyManager, private readonly h3DataService: H3DataService, private readonly cachedDataService: CachedDataService, private readonly dataSource: DataSource, @@ -59,20 +56,20 @@ export class ImpactCalculator { async calculateImpactForAllSourcingRecords( activeIndicators: Indicator[], - ): Promise { - const rawData: SourcingRecordsWithIndicatorRawDataDtoV2[] = - await this.getIndicatorRawDataForAllSourcingRecordsV2(activeIndicators); + ): Promise { + const rawData: SourcingRecordsWithIndicatorRawData[] = + await this.getImpactRawDataForAllSourcingRecords(activeIndicators); const newImpactToBeSaved: IndicatorRecord[] = []; - rawData.forEach((data: SourcingRecordsWithIndicatorRawDataDtoV2) => { - const indicatorValues: Map = + rawData.forEach((data: SourcingRecordsWithIndicatorRawData) => { + const indicatorValues: Map = this.calculateIndicatorValues(data, data.tonnage); activeIndicators.forEach((indicator: Indicator) => { newImpactToBeSaved.push( IndicatorRecord.merge(new IndicatorRecord(), { - value: indicatorValues.get(indicator.nameCode as INDICATOR_TYPES), + value: indicatorValues.get(indicator.nameCode), indicatorId: indicator.id, status: INDICATOR_RECORD_STATUS.SUCCESS, sourcingRecordId: data.sourcingRecordId, @@ -119,8 +116,8 @@ export class ImpactCalculator { await this.indicatorService.findAllIndicators({ status: INDICATOR_STATUS.ACTIVE, }); - let rawData: IndicatorRawDataBySourcingRecord = - new IndicatorRawDataBySourcingRecord(); + let rawData: SourcingRecordsWithIndicatorRawData = + new SourcingRecordsWithIndicatorRawData(); if (providedCoefficients) { calculatedIndicatorRecordValues = this.useProvidedIndicatorCoefficients( @@ -144,7 +141,7 @@ export class ImpactCalculator { } else { rawData = await this.getImpactRawDataPerSourcingRecordCached( indicatorsToCalculateImpactFor.map( - (i: Indicator) => i.nameCode as INDICATOR_TYPES, + (i: Indicator) => i.nameCode as INDICATOR_NAME_CODES, ), materialId, geoRegionId, @@ -164,7 +161,7 @@ export class ImpactCalculator { indicatorRecords.push( IndicatorRecord.merge(new IndicatorRecord(), { value: calculatedIndicatorRecordValues.values.get( - indicator.nameCode as INDICATOR_TYPES, + indicator.nameCode as INDICATOR_NAME_CODES, ), indicatorId: indicator.id, status: INDICATOR_RECORD_STATUS.SUCCESS, @@ -179,11 +176,11 @@ export class ImpactCalculator { } private async getImpactRawDataPerSourcingRecordCached( - indicators: INDICATOR_TYPES[], + indicators: INDICATOR_NAME_CODES[], materialId: string, geoRegionId: string, adminRegionId: string, - ): Promise { + ): Promise { const cacheKey: any = this.generateIndicatorCalculationCacheKey( indicators, materialId, @@ -220,11 +217,11 @@ export class ImpactCalculator { } private async getImpactRawDataPerSourcingRecord( - indicators: INDICATOR_TYPES[], + indicators: INDICATOR_NAME_CODES[], materialId: string, geoRegionId: string, adminRegionId: string, - ): Promise { + ): Promise { const dynamicQuery: string = this.dependencyManager.buildQueryForIntervention(indicators); @@ -272,25 +269,25 @@ export class ImpactCalculator { new IndicatorRecordCalculatedValuesDto(); calculatedIndicatorValues.sourcingRecordId = sourcingData.sourcingRecordId; calculatedIndicatorValues.materialH3DataId = materialH3DataId; - calculatedIndicatorValues.values = new Map(); + calculatedIndicatorValues.values = new Map(); calculatedIndicatorValues.values.set( - INDICATOR_TYPES.LAND_USE, - newIndicatorCoefficients[INDICATOR_TYPES.LAND_USE] * + INDICATOR_NAME_CODES.LAND_USE, + newIndicatorCoefficients[INDICATOR_NAME_CODES.LAND_USE] * sourcingData.tonnage || 0, ); calculatedIndicatorValues.values.set( - INDICATOR_TYPES.DEFORESTATION_RISK, - newIndicatorCoefficients[INDICATOR_TYPES.DEFORESTATION_RISK] * + INDICATOR_NAME_CODES.DEFORESTATION_RISK, + newIndicatorCoefficients[INDICATOR_NAME_CODES.DEFORESTATION_RISK] * sourcingData.tonnage || 0, ); calculatedIndicatorValues.values.set( - INDICATOR_TYPES.CLIMATE_RISK, - newIndicatorCoefficients[INDICATOR_TYPES.CLIMATE_RISK] * + INDICATOR_NAME_CODES.CLIMATE_RISK, + newIndicatorCoefficients[INDICATOR_NAME_CODES.CLIMATE_RISK] * sourcingData.tonnage || 0, ); calculatedIndicatorValues.values.set( - INDICATOR_TYPES.WATER_USE, - newIndicatorCoefficients[INDICATOR_TYPES.WATER_USE] * + INDICATOR_NAME_CODES.WATER_USE, + newIndicatorCoefficients[INDICATOR_NAME_CODES.WATER_USE] * sourcingData.tonnage || 0, ); @@ -300,12 +297,12 @@ export class ImpactCalculator { // Depends on water use indicator's final value const waterUseValue: number = calculatedIndicatorValues.values.get( - INDICATOR_TYPES.WATER_USE, + INDICATOR_NAME_CODES.WATER_USE, )!; calculatedIndicatorValues.values.set( - INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, + INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, waterUseValue * - newIndicatorCoefficients[INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE] * + newIndicatorCoefficients[INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE] * sourcingData.tonnage, ); @@ -317,47 +314,61 @@ export class ImpactCalculator { } private calculateIndicatorValues( - rawData: - | SourcingRecordsWithIndicatorRawDataDtoV2 - | IndicatorRawDataBySourcingRecord, + rawData: SourcingRecordsWithIndicatorRawData, tonnage: number, - ): Map { + ): Map { const landPerTon: number = Number.isFinite( - rawData.harvestedArea / rawData.production, + rawData.harvest / rawData.production, ) - ? rawData.harvestedArea / rawData.production + ? rawData.harvest / rawData.production : 0; - const weightedTotalCropLandArea: number = Number.isFinite( - rawData.weightedAllHarvest / rawData.production, + const landUse: number = landPerTon * tonnage; + const deforestationPreProcessed: number = Number.isFinite( + rawData.rawDeforestation / rawData.production, ) - ? rawData.weightedAllHarvest / rawData.production + ? rawData.rawDeforestation / rawData.production : 0; - const deforestationPerHarvestLandUse: number = - weightedTotalCropLandArea > 0 - ? rawData.rawDeforestation / weightedTotalCropLandArea - : 0; - const carbonPerHarvestLandUse: number = - weightedTotalCropLandArea > 0 - ? rawData.rawCarbon / weightedTotalCropLandArea - : 0; - const landUse: number = landPerTon * tonnage; - const deforestation: number = deforestationPerHarvestLandUse * landUse; - const carbonLoss: number = carbonPerHarvestLandUse * landUse; - const waterUse: number = rawData.rawWater * tonnage; - const unsustainableWaterUse: number = waterUse * rawData.waterStressPerct; - - const map: Map = new Map(); - map.set(INDICATOR_TYPES.CLIMATE_RISK, carbonLoss); - map.set(INDICATOR_TYPES.DEFORESTATION_RISK, deforestation); - map.set(INDICATOR_TYPES.WATER_USE, waterUse); - map.set(INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, unsustainableWaterUse); - map.set(INDICATOR_TYPES.LAND_USE, landUse); + const deforestation: number = + deforestationPreProcessed > 0 ? deforestationPreProcessed * landUse : 0; + const climateRiskPreProcessed: number = Number.isFinite( + rawData.rawClimateRisk / rawData.production, + ) + ? rawData.rawClimateRisk / rawData.production + : 0; + const climateRisk: number = + climateRiskPreProcessed > 0 ? climateRiskPreProcessed * landUse : 0; + const naturalRiskPreprocessed: number = Number.isFinite( + rawData.rawNaturalConversion / rawData.production, + ) + ? rawData.rawNaturalConversion / rawData.production + : 0; + const naturalRisk: number = + naturalRiskPreprocessed > 0 ? naturalRiskPreprocessed * landUse : 0; + const waterUse: number = rawData.rawWaterUse * tonnage; + const unsustainableWaterUse: number = + waterUse * rawData.rawUnsustainableWaterUse; + const waterQuality: number = rawData.rawWaterQuality * tonnage; + + const map: Map = new Map(); + map.set(INDICATOR_NAME_CODES.DEFORESTATION_RISK, deforestation); + map.set(INDICATOR_NAME_CODES.CLIMATE_RISK, climateRisk); + map.set( + INDICATOR_NAME_CODES.NATURAL_ECOSYSTEM_CONVERSION_RISK, + naturalRisk, + ); + map.set( + INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, + unsustainableWaterUse, + ); + map.set(INDICATOR_NAME_CODES.WATER_USE, waterUse); + map.set(INDICATOR_NAME_CODES.WATER_QUALITY, waterQuality); + map.set(INDICATOR_NAME_CODES.LAND_USE, landUse); map.set( - INDICATOR_TYPES.SATELLIGENCE_DEFORESTATION, + INDICATOR_NAME_CODES.SATELLIGENCE_DEFORESTATION, rawData.satDeforestation, ); map.set( - INDICATOR_TYPES.SATELLIGENCE_DEFORESTATION_RISK, + INDICATOR_NAME_CODES.SATELLIGENCE_DEFORESTATION_RISK, rawData.satDeforestationRisk, ); @@ -365,7 +376,7 @@ export class ImpactCalculator { } private generateIndicatorCalculationCacheKey( - indicators: INDICATOR_TYPES[], + indicators: INDICATOR_NAME_CODES[], materialId: string, geoRegionId: string, adminRegionId: string, @@ -373,8 +384,9 @@ export class ImpactCalculator { return { // Sort the indicator list to guarantee that the same set of indicator types won't result in different keys // because of their order - indicators: indicators.sort((a: INDICATOR_TYPES, b: INDICATOR_TYPES) => - a.toString() > b.toString() ? -1 : 1, + indicators: indicators.sort( + (a: INDICATOR_NAME_CODES, b: INDICATOR_NAME_CODES) => + a.toString() > b.toString() ? -1 : 1, ), materialId, geoRegionId, @@ -382,12 +394,12 @@ export class ImpactCalculator { }; } - async getIndicatorRawDataForAllSourcingRecordsV2( + async getImpactRawDataForAllSourcingRecords( activeIndicators: Indicator[], - ): Promise { + ): Promise { const { params, query } = this.dependencyManager.buildQueryForImport( activeIndicators.map( - (indicator: Indicator) => indicator.nameCode as INDICATOR_TYPES, + (indicator: Indicator) => indicator.nameCode as INDICATOR_NAME_CODES, ), ); try { diff --git a/api/src/modules/indicator-records/services/indicator-dependency-manager.service.ts b/api/src/modules/indicator-records/services/indicator-dependency-manager.service.ts index 29bedf14b1..433abfd320 100644 --- a/api/src/modules/indicator-records/services/indicator-dependency-manager.service.ts +++ b/api/src/modules/indicator-records/services/indicator-dependency-manager.service.ts @@ -1,71 +1,35 @@ import { Injectable } from '@nestjs/common'; -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; import { paramsToQueryInjector } from 'utils/helpers/params-to-query-injector.helper'; +import { + INDICATOR_NAME_CODE_TO_QUERY_MAP, + ImpactQueryPropertyName, + ImpactQueryExpression, + ImpactPropertyToQueryFunction, +} from 'modules/indicator-records/services/impact-calculation.dependencies'; -// TODO: All dependencies below should be ideally translated to queryBuilders - -const dependenciesForInterventions: any = { - production: `sum_material_over_georegion($1, $2, 'producer') as production`, - harvestedArea: `sum_material_over_georegion($1, $2, 'harvest') as "harvestedArea"`, - weightedAllHarvest: `sum_h3_weighted_cropland_area($1, $2, 'producer') as "weightedAllHarvest"`, - rawDeforestation: `sum_weighted_deforestation_over_georegion($1, $2, 'producer') as "rawDeforestation"`, - rawCarbon: `sum_weighted_carbon_over_georegion($1, $2, 'producer') as "rawCarbon"`, - rawWater: `get_blwf_impact($3, $2) as "rawWater"`, - waterStressPerct: `get_percentage_water_stress_area($1) as "waterStressPerct"`, - satDeforestation: ` sum_satelligence_deforestation_over_georegion($1) as "satDeforestation"`, - satDeforestationRisk: `sum_satelligence_deforestation_risk_over_georegion($1) as "satDeforestationRisk"`, -}; - -// landUse needs: landPerTon and tonnage -// deforestation needs weightedAllHarvest + rawDeforestation + tonnage -// carbonLoss needs weightedAllHarvest + rawCarbon + tonnage -// waterUse needs rawData + tonnage -// unsustainable water use needs waterUse(indicator) + waterstreesperct -const indicatorVSRawValueDependencies: any = { - [INDICATOR_TYPES.LAND_USE]: { - production: dependenciesForInterventions['production'], - harvestedArea: dependenciesForInterventions['harvestedArea'], - }, - [INDICATOR_TYPES.DEFORESTATION_RISK]: { - rawDeforestation: dependenciesForInterventions['rawDeforestation'], - weightedAllHarvest: dependenciesForInterventions['weightedAllHarvest'], - }, - [INDICATOR_TYPES.CLIMATE_RISK]: { - rawCarbon: dependenciesForInterventions['rawCarbon'], - weightedAllHarvest: dependenciesForInterventions['weightedAllHarvest'], - }, - [INDICATOR_TYPES.WATER_USE]: { - rawWater: dependenciesForInterventions['rawWater'], - weightedAllHarvest: dependenciesForInterventions['weightedAllHarvest'], - }, - [INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE]: { - waterStressPerct: dependenciesForInterventions['waterStressPerct'], - rawWater: dependenciesForInterventions['rawWater'], - }, - [INDICATOR_TYPES.SATELLIGENCE_DEFORESTATION]: { - satDeforestation: dependenciesForInterventions['satDeforestation'], - }, - [INDICATOR_TYPES.SATELLIGENCE_DEFORESTATION_RISK]: { - satDeforestationRisk: dependenciesForInterventions['satDeforestationRisk'], - }, +type IndicatorNameCodeToQuery = { + [key in ImpactQueryPropertyName]?: ImpactPropertyToQueryFunction; }; @Injectable() -export class IndicatorDependencyManager { - /** - * @description: Returns the query (stored procedure) needed to calculate the given raw value for a indicator - * TODO: This should be (again) translated to api logic as it is in (WIP) https://github.com/Vizzuality/landgriffon/pull/591 - */ +export class IndicatorQueryDependencyManager { + queryMap: typeof INDICATOR_NAME_CODE_TO_QUERY_MAP = + INDICATOR_NAME_CODE_TO_QUERY_MAP; - buildQueryForIntervention(nameCodes: INDICATOR_TYPES[]): any { - const queries: any[] = []; + buildQueryForIntervention(nameCodes: INDICATOR_NAME_CODES[]): string { + const queries: ImpactQueryExpression[] = []; for (const nameCode of nameCodes) { - queries.push(...Object.values(indicatorVSRawValueDependencies[nameCode])); + const queryObject: IndicatorNameCodeToQuery = this.queryMap[nameCode]; + for (const queryFunction of Object.values(queryObject)) { + const querySegment: ImpactQueryExpression = queryFunction(nameCode); + queries.push(querySegment); + } } return [...new Set(queries)].join(', '); } - buildQueryForImport(nameCodes: INDICATOR_TYPES[]): { + buildQueryForImport(nameCodes: INDICATOR_NAME_CODES[]): { params: string; query: string; } { @@ -74,12 +38,18 @@ export class IndicatorDependencyManager { `sourcing_location."materialId"`, `sourcing_location."adminRegionId"`, ]; - const queries: any[] = []; + const queries: ImpactQueryExpression[] = []; const params: string[] = []; for (const nameCode of nameCodes) { - params.push(...Object.keys(indicatorVSRawValueDependencies[nameCode])); - queries.push(...Object.values(indicatorVSRawValueDependencies[nameCode])); + params.push(...Object.keys(this.queryMap[nameCode])); + for (const nameCode of nameCodes) { + const queryObject: IndicatorNameCodeToQuery = this.queryMap[nameCode]; + for (const queryFunction of Object.values(queryObject)) { + const querySegment: ImpactQueryExpression = queryFunction(nameCode); + queries.push(querySegment); + } + } } return { params: [...new Set(params)] diff --git a/api/src/modules/indicators/dto/indicator-computed-raw-data.dto.ts b/api/src/modules/indicators/dto/indicator-computed-raw-data.dto.ts index 39dbdc77b9..b758ae3ae7 100644 --- a/api/src/modules/indicators/dto/indicator-computed-raw-data.dto.ts +++ b/api/src/modules/indicators/dto/indicator-computed-raw-data.dto.ts @@ -2,10 +2,10 @@ * @description Raw indicator data computed in DB using stored functions of migration: XXXXXX * used to calculate impact for a Intervention */ -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; export class IndicatorComputedRawDataDto { production: number; harvestedArea: number; - indicatorValues: Map; + indicatorValues: Map; } diff --git a/api/src/modules/indicators/indicator.entity.ts b/api/src/modules/indicators/indicator.entity.ts index deaf8dd6a3..d60de09270 100644 --- a/api/src/modules/indicators/indicator.entity.ts +++ b/api/src/modules/indicators/indicator.entity.ts @@ -19,12 +19,14 @@ export enum INDICATOR_STATUS { DELETED = 'deleted', } -export enum INDICATOR_TYPES { +export enum INDICATOR_NAME_CODES { LAND_USE = 'LI', DEFORESTATION_RISK = 'DF_LUC_T', CLIMATE_RISK = 'GHG_LUC_T', WATER_USE = 'UWU_T', UNSUSTAINABLE_WATER_USE = 'UWUSR_T', + NATURAL_ECOSYSTEM_CONVERSION_RISK = 'NECR', + WATER_QUALITY = 'WQ', SATELLIGENCE_DEFORESTATION = 'SAT_DF', SATELLIGENCE_DEFORESTATION_RISK = 'SAT_DF_R', } @@ -53,7 +55,7 @@ export class Indicator extends BaseEntity { shortName?: string; @Column({ type: 'text', nullable: false, unique: true }) - nameCode: string; + nameCode: INDICATOR_NAME_CODES; @Column({ type: 'text', nullable: true }) @ApiPropertyOptional() diff --git a/api/src/modules/indicators/indicators.service.ts b/api/src/modules/indicators/indicators.service.ts index 9e7896517b..aa29a9f303 100644 --- a/api/src/modules/indicators/indicators.service.ts +++ b/api/src/modules/indicators/indicators.service.ts @@ -11,7 +11,7 @@ import { import { Indicator, INDICATOR_STATUS, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, indicatorResource, } from 'modules/indicators/indicator.entity'; import { AppInfoDTO } from 'dto/info.dto'; @@ -83,7 +83,7 @@ export class IndicatorsService extends AppBaseService< const deforestationIndicator: Indicator | null = await this.indicatorRepository.findOne({ - where: { nameCode: INDICATOR_TYPES.DEFORESTATION_RISK }, + where: { nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK }, }); if (!deforestationIndicator) throw new NotFoundException( diff --git a/api/src/modules/sourcing-records/dto/sourcing-records-with-indicator-raw-data.dto.ts b/api/src/modules/sourcing-records/dto/sourcing-records-with-indicator-raw-data.dto.ts index 90f7ffa92f..3747617d9d 100644 --- a/api/src/modules/sourcing-records/dto/sourcing-records-with-indicator-raw-data.dto.ts +++ b/api/src/modules/sourcing-records/dto/sourcing-records-with-indicator-raw-data.dto.ts @@ -2,62 +2,12 @@ * @description: Interface for typing the response of the DB that retrieves existing sourcing info with * total production, harvest, and raw indicator data, used for calculating a indicator-record */ +import { QueryPropertyTypes } from 'modules/indicator-records/services/impact-calculation.dependencies'; -export class SourcingRecordsWithIndicatorRawDataDtoV2 { +export class SourcingRecordsWithIndicatorRawData extends QueryPropertyTypes { sourcingRecordId: string; tonnage: number; year: number; - - sourcingLocationId: string; - production: number; - harvestedArea: number; - - // new - weightedAllHarvest: number; - //new - waterStressPerct: number; - - rawDeforestation: number; - rawCarbon: number; - rawWater: number; - materialH3DataId: string; - - satDeforestation: number; - satDeforestationRisk: number; -} - -export class IndicatorRawDataBySourcingRecord { - production: number; - harvestedArea: number; - - // new - weightedAllHarvest: number; - //new - waterStressPerct: number; - - rawDeforestation: number; - rawCarbon: number; - rawWater: number; - - satDeforestation: number; - satDeforestationRisk: number; -} - -// TODO: Delete below class once new methodology is validated -export class SourcingRecordsWithIndicatorRawDataDto { - sourcingRecordId: string; - tonnage: number; - year: number; - sourcingLocationId: string; - production: number; - harvestedArea: number; - - rawDeforestation: number; - rawBiodiversity: number; - rawCarbon: number; - rawWater: number; - - materialH3DataId: string; } diff --git a/api/test/e2e/authorization/authorization.spec.ts b/api/test/e2e/authorization/authorization.spec.ts index 3d8978865f..2a5ac03aa2 100644 --- a/api/test/e2e/authorization/authorization.spec.ts +++ b/api/test/e2e/authorization/authorization.spec.ts @@ -12,7 +12,7 @@ import { } from '../../entity-mocks'; import { Indicator, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { SourcingLocation } from 'modules/sourcing-locations/sourcing-location.entity'; import ApplicationManager, { @@ -83,7 +83,7 @@ describe('Authorization Test (E2E)', () => { .expect(HttpStatus.OK); const indicator = await createIndicator({ - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); await request(testApplication.getHttpServer()) @@ -101,7 +101,7 @@ describe('Authorization Test (E2E)', () => { .expect(HttpStatus.FORBIDDEN); const indicator = await createIndicator({ - nameCode: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, + nameCode: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, }); await request(testApplication.getHttpServer()) diff --git a/api/test/e2e/h3-data/h3-data.spec.ts b/api/test/e2e/h3-data/h3-data.spec.ts index 53c27a31b7..c03127083a 100644 --- a/api/test/e2e/h3-data/h3-data.spec.ts +++ b/api/test/e2e/h3-data/h3-data.spec.ts @@ -17,7 +17,10 @@ import { createSourcingRecord, } from '../../entity-mocks'; import { H3Data } from 'modules/h3-data/h3-data.entity'; -import { Indicator } from 'modules/indicators/indicator.entity'; +import { + Indicator, + INDICATOR_NAME_CODES, +} from 'modules/indicators/indicator.entity'; import { MATERIAL_TO_H3_TYPE } from 'modules/materials/material-to-h3.entity'; import { MaterialsToH3sService } from 'modules/materials/materials-to-h3s.service'; import { h3BasicFixture } from './mocks/h3-fixtures'; @@ -320,7 +323,7 @@ describe('H3-Data Module (e2e) - Get H3 data', () => { test('Given there is material H3 data, When I query available years providing a indicator id, then I should get all available years for that indicator', async () => { const years = [2001, 2001, 2002, 2003, 2007]; const savedIndicator: Indicator = await createIndicator({ - nameCode: 'GAMMA_RADIATION', + nameCode: 'GAMMA_RADIATION' as INDICATOR_NAME_CODES, }); const fakeH3MasterData: Array> = []; for await (const year of years) { diff --git a/api/test/e2e/h3-data/mocks/h3-data.mock.ts b/api/test/e2e/h3-data/mocks/h3-data.mock.ts index 5e207c30f7..6c6bf850d1 100644 --- a/api/test/e2e/h3-data/mocks/h3-data.mock.ts +++ b/api/test/e2e/h3-data/mocks/h3-data.mock.ts @@ -1,6 +1,7 @@ import { DataSource } from 'typeorm'; import { H3Data } from 'modules/h3-data/h3-data.entity'; import { snakeCase, camelCase } from 'typeorm/util/StringUtils'; +import { INDICATOR_NAME_CODES } from '../../../../src/modules/indicators/indicator.entity'; export const h3DataMock = async ( dataSource: DataSource, @@ -58,5 +59,5 @@ export const dropH3DataMock = async ( export const createRandomNamesForH3TableAndColumns = (): string => (Math.random() + 1).toString(36).substring(2); -export const createRandomIndicatorNameCode = (): string => - `${Math.random() + 1}_${Math.random() + 1}`; +export const createRandomIndicatorNameCode = (): INDICATOR_NAME_CODES => + `${Math.random() + 1}_${Math.random() + 1}` as INDICATOR_NAME_CODES; diff --git a/api/test/e2e/h3-data/mocks/h3-impact-map.mock.ts b/api/test/e2e/h3-data/mocks/h3-impact-map.mock.ts index ef23d30d19..9130a16f4f 100644 --- a/api/test/e2e/h3-data/mocks/h3-impact-map.mock.ts +++ b/api/test/e2e/h3-data/mocks/h3-impact-map.mock.ts @@ -2,6 +2,7 @@ import { Unit } from 'modules/units/unit.entity'; import { UnitConversion } from 'modules/unit-conversions/unit-conversion.entity'; import { Indicator, + INDICATOR_NAME_CODES, INDICATOR_STATUS, } from 'modules/indicators/indicator.entity'; import { h3DataMock } from './h3-data.mock'; @@ -81,14 +82,14 @@ export const createImpactMapMockData = async ( const indicator: Indicator = new Indicator(); indicator.name = 'test indicator'; indicator.unit = unit; - indicator.nameCode = 'UWU_T'; + indicator.nameCode = 'UWU_T' as INDICATOR_NAME_CODES; await indicator.save(); const inactiveIndicator: Indicator = new Indicator(); inactiveIndicator.name = 'Inactive Indicator'; inactiveIndicator.unit = unit; inactiveIndicator.status = INDICATOR_STATUS.INACTIVE; - inactiveIndicator.nameCode = 'INA_IN'; + inactiveIndicator.nameCode = 'INA_IN' as INDICATOR_NAME_CODES; await inactiveIndicator.save(); const harvestH3Data = await h3DataMock(dataSource, { diff --git a/api/test/e2e/impact/impact-chart/chart.spec.ts b/api/test/e2e/impact/impact-chart/chart.spec.ts index 83679fb736..4f386d1873 100644 --- a/api/test/e2e/impact/impact-chart/chart.spec.ts +++ b/api/test/e2e/impact/impact-chart/chart.spec.ts @@ -15,7 +15,7 @@ import { H3Data } from 'modules/h3-data/h3-data.entity'; import { Material } from 'modules/materials/material.entity'; import { Indicator, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { Unit } from 'modules/units/unit.entity'; import { BusinessUnit } from 'modules/business-units/business-unit.entity'; @@ -152,13 +152,13 @@ describe('Impact Chart (Ranking) Test Suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const indicator2: Indicator = await createIndicator({ name: 'Fake Indicator 2', unit, - nameCode: INDICATOR_TYPES.CLIMATE_RISK, + nameCode: INDICATOR_NAME_CODES.CLIMATE_RISK, }); const businessUnit: BusinessUnit = await createBusinessUnit({ @@ -359,7 +359,7 @@ describe('Impact Chart (Ranking) Test Suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const businessUnit: BusinessUnit = await createBusinessUnit({ diff --git a/api/test/e2e/impact/impact-table/impact.spec.ts b/api/test/e2e/impact/impact-table/impact.spec.ts index 96f8843fdc..696ea9a9fa 100644 --- a/api/test/e2e/impact/impact-table/impact.spec.ts +++ b/api/test/e2e/impact/impact-table/impact.spec.ts @@ -18,7 +18,7 @@ import { Unit } from 'modules/units/unit.entity'; import { Indicator, INDICATOR_STATUS, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { BusinessUnit } from 'modules/business-units/business-unit.entity'; import { Material, MATERIALS_STATUS } from 'modules/materials/material.entity'; @@ -138,7 +138,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, status: INDICATOR_STATUS.ACTIVE, }); @@ -166,13 +166,13 @@ describe('Impact Table and Charts test suite (e2e)', () => { test('When I query the API for a Impact Table for inactive indicators then I should get a proper error message', async () => { const inactiveIndicator: Indicator = await createIndicator({ name: 'Inactive Indicator 1', - nameCode: 'IN_IND', + nameCode: 'IN_IND' as INDICATOR_NAME_CODES, status: INDICATOR_STATUS.INACTIVE, }); const activeIndicator: Indicator = await createIndicator({ name: 'active Indicator', - nameCode: 'ACT_IND', + nameCode: 'ACT_IND' as INDICATOR_NAME_CODES, status: INDICATOR_STATUS.ACTIVE, }); const response = await request(testApplication.getHttpServer()) @@ -204,7 +204,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const businessUnit: BusinessUnit = await createBusinessUnit({ @@ -334,7 +334,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const businessUnit: BusinessUnit = await createBusinessUnit({ @@ -392,7 +392,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const businessUnit: BusinessUnit = await createBusinessUnit({ @@ -551,7 +551,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const parentMaterial1 = await createMaterial({ @@ -645,7 +645,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const material1: Material = await createMaterial({ @@ -755,7 +755,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const parentMaterial: Material = await createMaterial({ @@ -905,7 +905,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const material: Material = await createMaterial({ @@ -991,7 +991,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const material: Material = await createMaterial({ @@ -1102,7 +1102,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const material: Material = await createMaterial({ @@ -1196,7 +1196,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const material: Material = await createMaterial({ @@ -1297,7 +1297,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const material1: Material = await createMaterial({ @@ -1417,7 +1417,7 @@ describe('Impact Table and Charts test suite (e2e)', () => { const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const material: Material = await createMaterial({ diff --git a/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/mixed-interventions-scenario.preconditions.ts b/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/mixed-interventions-scenario.preconditions.ts index c243b297c6..7855b6fbd0 100644 --- a/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/mixed-interventions-scenario.preconditions.ts +++ b/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/mixed-interventions-scenario.preconditions.ts @@ -28,7 +28,7 @@ import { createSupplier, createUnit, } from '../../../../entity-mocks'; -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; export async function createMultipleInterventionsPreconditions(): Promise<{ indicator: Indicator; @@ -41,7 +41,7 @@ export async function createMultipleInterventionsPreconditions(): Promise<{ const indicator: Indicator = await createIndicator({ name: 'Deforestation', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const textile: Material = await createMaterial({ name: 'Textile' }); diff --git a/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-coefficients-intervention.preconditions.ts b/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-coefficients-intervention.preconditions.ts index dee3657280..6198c1752b 100644 --- a/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-coefficients-intervention.preconditions.ts +++ b/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-coefficients-intervention.preconditions.ts @@ -25,7 +25,7 @@ import { createSupplier, createUnit, } from '../../../../entity-mocks'; -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; import { Scenario } from 'modules/scenarios/scenario.entity'; export async function createNewCoefficientsInterventionPreconditions( @@ -47,7 +47,7 @@ export async function createNewCoefficientsInterventionPreconditions( const indicator: Indicator = await createIndicator({ name: 'Deforestation', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); // Creating Materials diff --git a/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-material-intervention.preconditions.ts b/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-material-intervention.preconditions.ts index b5138d5339..77aa12cbec 100644 --- a/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-material-intervention.preconditions.ts +++ b/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-material-intervention.preconditions.ts @@ -25,7 +25,7 @@ import { createSupplier, createUnit, } from '../../../../entity-mocks'; -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; import { Scenario } from 'modules/scenarios/scenario.entity'; export async function createNewMaterialInterventionPreconditions( @@ -46,7 +46,7 @@ export async function createNewMaterialInterventionPreconditions( : await createIndicator({ name: 'Deforestation', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const textile: Material = await createMaterial({ name: 'Textile' }); diff --git a/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-supplier-intervention.preconditions.ts b/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-supplier-intervention.preconditions.ts index e6e27b650d..94459d9c62 100644 --- a/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-supplier-intervention.preconditions.ts +++ b/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/new-supplier-intervention.preconditions.ts @@ -25,7 +25,7 @@ import { createSupplier, createUnit, } from '../../../../entity-mocks'; -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; import { Scenario } from 'modules/scenarios/scenario.entity'; export async function createNewSupplierInterventionPreconditions( @@ -48,7 +48,7 @@ export async function createNewSupplierInterventionPreconditions( : await createIndicator({ name: 'Deforestation', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const textile: Material = customMaterials diff --git a/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/two-scenarios.preconditions.ts b/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/two-scenarios.preconditions.ts index e7d206d399..0daf6c39cc 100644 --- a/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/two-scenarios.preconditions.ts +++ b/api/test/e2e/impact/mocks/actual-vs-scenario-preconditions/two-scenarios.preconditions.ts @@ -9,7 +9,7 @@ import { createNewSupplierInterventionPreconditions } from './new-supplier-inter import { createNewMaterialInterventionPreconditions } from './new-material-intervention.preconditions'; import { Indicator, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { Unit } from 'modules/units/unit.entity'; import { Material } from 'modules/materials/material.entity'; @@ -30,7 +30,7 @@ export async function createTwoScenariosPreconditions(): Promise<{ name: 'Deforestation', shortName: 'Deforestation', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const textile: Material = await createMaterial({ name: 'Textile' }); diff --git a/api/test/e2e/impact/mocks/scenario-vs-scenario-preconditions/mixed-scenarios.preconditions.ts b/api/test/e2e/impact/mocks/scenario-vs-scenario-preconditions/mixed-scenarios.preconditions.ts index b91b980116..5c44ae4d37 100644 --- a/api/test/e2e/impact/mocks/scenario-vs-scenario-preconditions/mixed-scenarios.preconditions.ts +++ b/api/test/e2e/impact/mocks/scenario-vs-scenario-preconditions/mixed-scenarios.preconditions.ts @@ -27,7 +27,7 @@ import { createSupplier, createUnit, } from '../../../../entity-mocks'; -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; export async function createMixedScenariosPreconditions(): Promise<{ indicator: Indicator; @@ -41,7 +41,7 @@ export async function createMixedScenariosPreconditions(): Promise<{ const indicator: Indicator = await createIndicator({ name: 'Deforestation', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const textile: Material = await createMaterial({ name: 'Textile' }); diff --git a/api/test/e2e/impact/mocks/scenario-vs-scenario-preconditions/same-materials-scenarios.preconditions.ts b/api/test/e2e/impact/mocks/scenario-vs-scenario-preconditions/same-materials-scenarios.preconditions.ts index e90a2b3a70..b14232645a 100644 --- a/api/test/e2e/impact/mocks/scenario-vs-scenario-preconditions/same-materials-scenarios.preconditions.ts +++ b/api/test/e2e/impact/mocks/scenario-vs-scenario-preconditions/same-materials-scenarios.preconditions.ts @@ -28,7 +28,7 @@ import { createSupplier, createUnit, } from '../../../../entity-mocks'; -import { INDICATOR_TYPES } from 'modules/indicators/indicator.entity'; +import { INDICATOR_NAME_CODES } from 'modules/indicators/indicator.entity'; export async function createSameMaterialScenariosPreconditions(): Promise<{ indicator: Indicator; @@ -42,7 +42,7 @@ export async function createSameMaterialScenariosPreconditions(): Promise<{ const indicator: Indicator = await createIndicator({ name: 'Deforestation', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const textile: Material = await createMaterial({ name: 'Textile' }); diff --git a/api/test/e2e/impact/mocks/sorting.preconditions.ts b/api/test/e2e/impact/mocks/sorting.preconditions.ts index b944349a32..15b3cd1b6b 100644 --- a/api/test/e2e/impact/mocks/sorting.preconditions.ts +++ b/api/test/e2e/impact/mocks/sorting.preconditions.ts @@ -15,7 +15,7 @@ import { import { Unit } from 'modules/units/unit.entity'; import { Indicator, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { Material } from 'modules/materials/material.entity'; import { BusinessUnit } from 'modules/business-units/business-unit.entity'; @@ -41,7 +41,7 @@ export async function createImpactTableSortingPreconditions( const indicator: Indicator = await createIndicator({ name: 'Fake Indicator', unit, - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const parentMaterial1 = await createMaterial({ diff --git a/api/test/e2e/indicators/indicators.spec.ts b/api/test/e2e/indicators/indicators.spec.ts index 0022458e34..6605d998c0 100644 --- a/api/test/e2e/indicators/indicators.spec.ts +++ b/api/test/e2e/indicators/indicators.spec.ts @@ -3,7 +3,7 @@ import * as request from 'supertest'; import { Indicator, INDICATOR_STATUS, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { IndicatorRepository } from 'modules/indicators/indicator.repository'; import { setupTestUser } from '../../utils/userAuth'; @@ -51,7 +51,7 @@ describe('IndicatorsModule (e2e)', () => { .set('Authorization', `Bearer ${jwtToken}`) .send({ name: 'test indicator', - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }) .expect(HttpStatus.CREATED); @@ -93,7 +93,7 @@ describe('IndicatorsModule (e2e)', () => { test('Update a indicator should be successful (happy case)', async () => { const indicator: Indicator = new Indicator(); indicator.name = 'test indicator'; - indicator.nameCode = 'Midiclorian'; + indicator.nameCode = 'Midiclorian' as INDICATOR_NAME_CODES; await indicator.save(); const response = await request(testApplication.getHttpServer()) @@ -114,7 +114,7 @@ describe('IndicatorsModule (e2e)', () => { test('Delete a indicator should be successful (happy case)', async () => { const indicator: Indicator = new Indicator(); indicator.name = 'test indicator'; - indicator.nameCode = 'Midiclorian'; + indicator.nameCode = 'Midiclorian' as INDICATOR_NAME_CODES; await indicator.save(); await request(testApplication.getHttpServer()) @@ -134,7 +134,7 @@ describe('IndicatorsModule (e2e)', () => { test('Get all indicators should be successful (happy case)', async () => { const indicator: Indicator = new Indicator(); indicator.name = 'test indicator'; - indicator.nameCode = 'Midiclorian'; + indicator.nameCode = 'Midiclorian' as INDICATOR_NAME_CODES; await indicator.save(); const response = await request(testApplication.getHttpServer()) @@ -149,17 +149,17 @@ describe('IndicatorsModule (e2e)', () => { test('When requesting all indicators then indicators with inactive status should be included in results', async () => { await createIndicator({ name: 'Indicator 1', - nameCode: 'IND_1', + nameCode: 'IND_1' as INDICATOR_NAME_CODES, status: INDICATOR_STATUS.ACTIVE, }); await createIndicator({ name: 'Indicator 2', - nameCode: 'IND_2', + nameCode: 'IND_2' as INDICATOR_NAME_CODES, status: INDICATOR_STATUS.INACTIVE, }); const inactiveIndicator: Indicator = await createIndicator({ name: 'Indicator 3', - nameCode: 'IND_3', + nameCode: 'IND_3' as INDICATOR_NAME_CODES, status: INDICATOR_STATUS.INACTIVE, }); @@ -185,7 +185,7 @@ describe('IndicatorsModule (e2e)', () => { test('Get a indicator by id should be successful (happy case)', async () => { const indicator: Indicator = new Indicator(); indicator.name = 'test indicator'; - indicator.nameCode = 'Midiclorian'; + indicator.nameCode = 'Midiclorian' as INDICATOR_NAME_CODES; await indicator.save(); const response = await request(testApplication.getHttpServer()) @@ -200,7 +200,7 @@ describe('IndicatorsModule (e2e)', () => { test('Get an inactive indicator by id should be successful (happy case)', async () => { const indicator: Indicator = new Indicator(); indicator.name = 'inactive indicator'; - indicator.nameCode = 'IND_INACT'; + indicator.nameCode = 'IND_INACT' as INDICATOR_NAME_CODES; indicator.status = INDICATOR_STATUS.INACTIVE; await indicator.save(); diff --git a/api/test/e2e/scenario-interventions/location-types.spec.ts b/api/test/e2e/scenario-interventions/location-types.spec.ts index 2fc4cd539a..453633bba3 100644 --- a/api/test/e2e/scenario-interventions/location-types.spec.ts +++ b/api/test/e2e/scenario-interventions/location-types.spec.ts @@ -1,7 +1,7 @@ import { Indicator, INDICATOR_STATUS, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import * as request from 'supertest'; @@ -66,8 +66,8 @@ describe('Interventions E2E Tests (Location Types)', () => { 'Then I should get an error', async () => { await createIndicator({ - name: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, - nameCode: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, + name: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, + nameCode: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, status: INDICATOR_STATUS.ACTIVE, }); const response = await request(testApplication.getHttpServer()) @@ -86,7 +86,7 @@ describe('Interventions E2E Tests (Location Types)', () => { newLocationType: LOCATION_TYPES.ADMINISTRATIVE_REGION_OF_PRODUCTION, type: SCENARIO_INTERVENTION_TYPE.NEW_MATERIAL, newIndicatorCoefficients: { - [INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE]: 1, + [INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE]: 1, }, }); diff --git a/api/test/e2e/scenario-interventions/validations/intervention-validations.spec.ts b/api/test/e2e/scenario-interventions/validations/intervention-validations.spec.ts index d5be5875f7..c517f592f7 100644 --- a/api/test/e2e/scenario-interventions/validations/intervention-validations.spec.ts +++ b/api/test/e2e/scenario-interventions/validations/intervention-validations.spec.ts @@ -1,7 +1,7 @@ import { Indicator, INDICATOR_STATUS, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { createIndicator, @@ -69,7 +69,9 @@ describe('Interventions E2E Tests (Controller Validations)', () => { 'But these differs from the ones that are active in the DB' + 'Then I should get and error message', async () => { - for (const [index, data] of Object.entries(INDICATOR_TYPES).entries()) { + for (const [index, data] of Object.entries( + INDICATOR_NAME_CODES, + ).entries()) { if (index % 2 === 0) { await createIndicator({ name: `indicator n ${index}`, @@ -118,7 +120,7 @@ describe('Interventions E2E Tests (Controller Validations)', () => { newLocationCountryInput: 'TestCountry', type: SCENARIO_INTERVENTION_TYPE.CHANGE_PRODUCTION_EFFICIENCY, newIndicatorCoefficients: { - [INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE]: 1, + [INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE]: 1, }, }); @@ -137,12 +139,12 @@ describe('Interventions E2E Tests (Controller Validations)', () => { 'Then the validation should pass', async () => { await createIndicator({ - nameCode: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, - name: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, + nameCode: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, + name: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, }); await createIndicator({ - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, - name: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, + name: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const response = await request(testApplication.getHttpServer()) @@ -160,8 +162,8 @@ describe('Interventions E2E Tests (Controller Validations)', () => { newLocationCountryInput: 'TestCountry', type: SCENARIO_INTERVENTION_TYPE.CHANGE_PRODUCTION_EFFICIENCY, newIndicatorCoefficients: { - [INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE]: 1, - [INDICATOR_TYPES.DEFORESTATION_RISK]: 2, + [INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE]: 1, + [INDICATOR_NAME_CODES.DEFORESTATION_RISK]: 2, }, }); @@ -176,12 +178,12 @@ describe('Interventions E2E Tests (Controller Validations)', () => { async () => { const intervention = await createScenarioIntervention(); await createIndicator({ - nameCode: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, - name: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, + nameCode: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, + name: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, }); await createIndicator({ - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, - name: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, + name: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const response = await request(testApplication.getHttpServer()) @@ -199,8 +201,8 @@ describe('Interventions E2E Tests (Controller Validations)', () => { newLocationCountryInput: 'TestCountry', type: SCENARIO_INTERVENTION_TYPE.CHANGE_PRODUCTION_EFFICIENCY, newIndicatorCoefficients: { - [INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE]: 1, - [INDICATOR_TYPES.DEFORESTATION_RISK]: 2, + [INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE]: 1, + [INDICATOR_NAME_CODES.DEFORESTATION_RISK]: 2, }, }); @@ -214,12 +216,12 @@ describe('Interventions E2E Tests (Controller Validations)', () => { async () => { const intervention = await createScenarioIntervention(); await createIndicator({ - nameCode: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, - name: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, + nameCode: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, + name: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, }); await createIndicator({ - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, - name: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, + name: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const response = await request(testApplication.getHttpServer()) @@ -237,8 +239,8 @@ describe('Interventions E2E Tests (Controller Validations)', () => { newLocationCountryInput: 'TestCountry', type: SCENARIO_INTERVENTION_TYPE.CHANGE_PRODUCTION_EFFICIENCY, newIndicatorCoefficients: { - [INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE]: 1, - [INDICATOR_TYPES.DEFORESTATION_RISK]: 2, + [INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE]: 1, + [INDICATOR_NAME_CODES.DEFORESTATION_RISK]: 2, }, }); @@ -253,7 +255,9 @@ describe('Interventions E2E Tests (Controller Validations)', () => { async () => { const intervention = await createScenarioIntervention(); - for (const [index, data] of Object.entries(INDICATOR_TYPES).entries()) { + for (const [index, data] of Object.entries( + INDICATOR_NAME_CODES, + ).entries()) { if (index % 2 === 0) { await createIndicator({ name: `indicator n ${index}`, @@ -302,7 +306,7 @@ describe('Interventions E2E Tests (Controller Validations)', () => { newLocationCountryInput: 'TestCountry', type: SCENARIO_INTERVENTION_TYPE.CHANGE_PRODUCTION_EFFICIENCY, newIndicatorCoefficients: { - [INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE]: 1, + [INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE]: 1, }, }); diff --git a/api/test/e2e/targets/targets.spec.ts b/api/test/e2e/targets/targets.spec.ts index 203778a0ed..0930212fd6 100644 --- a/api/test/e2e/targets/targets.spec.ts +++ b/api/test/e2e/targets/targets.spec.ts @@ -3,7 +3,10 @@ import * as request from 'supertest'; import { Target } from 'modules/targets/target.entity'; import { TargetsRepository } from 'modules/targets/targets.repository'; import { createIndicator, createTarget } from '../../entity-mocks'; -import { Indicator } from 'modules/indicators/indicator.entity'; +import { + Indicator, + INDICATOR_NAME_CODES, +} from 'modules/indicators/indicator.entity'; import { IndicatorRepository } from 'modules/indicators/indicator.repository'; import { clearTestDataFromDatabase } from '../../utils/database-test-helper'; import { DataSource } from 'typeorm'; @@ -51,7 +54,7 @@ describe('Tasks Module (e2e)', () => { describe('Targets - Create', () => { test('Creating a new target (happy case)', async () => { const indicator: Indicator = await createIndicator({ - nameCode: 'GAMMA_RADIATION', + nameCode: 'GAMMA_RADIATION' as INDICATOR_NAME_CODES, }); const response = await request(testApplication.getHttpServer()) diff --git a/api/test/entity-mocks.ts b/api/test/entity-mocks.ts index c9ac136e03..4bd5670bf6 100644 --- a/api/test/entity-mocks.ts +++ b/api/test/entity-mocks.ts @@ -8,7 +8,10 @@ import { Material, MATERIALS_STATUS } from 'modules/materials/material.entity'; import { Supplier } from 'modules/suppliers/supplier.entity'; import { SourcingRecord } from 'modules/sourcing-records/sourcing-record.entity'; import { IndicatorRecord } from 'modules/indicator-records/indicator-record.entity'; -import { Indicator } from 'modules/indicators/indicator.entity'; +import { + Indicator, + INDICATOR_NAME_CODES, +} from 'modules/indicators/indicator.entity'; import { SourcingLocation } from 'modules/sourcing-locations/sourcing-location.entity'; import { SourcingLocationGroup } from 'modules/sourcing-location-groups/sourcing-location-group.entity'; import { Unit } from 'modules/units/unit.entity'; @@ -426,7 +429,9 @@ async function createTarget( ): Promise { const indicator: Indicator = await createIndicator({ name: (Math.random() + 1).toString(30).substring(6), - nameCode: (Math.random() + 1).toString(30).substring(6), + nameCode: (Math.random() + 1) + .toString(30) + .substring(6) as INDICATOR_NAME_CODES, }); const defaultData: DeepPartial = { baseLineYear: 2020, diff --git a/api/test/integration/import-data/xlsx-uploads/import-mocks.ts b/api/test/integration/import-data/xlsx-uploads/import-mocks.ts index db904c9d41..f9708c1fd4 100644 --- a/api/test/integration/import-data/xlsx-uploads/import-mocks.ts +++ b/api/test/integration/import-data/xlsx-uploads/import-mocks.ts @@ -7,7 +7,7 @@ import { import { Material } from 'modules/materials/material.entity'; import { Indicator, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { snakeCase } from 'typeorm/util/StringUtils'; import { MATERIAL_TO_H3_TYPE } from 'modules/materials/material-to-h3.entity'; @@ -21,19 +21,19 @@ async function createIndicatorsForXLSXImport( const indicatorSpec = [ { name: 'Deforestation loss due to land use change', - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }, { name: 'Carbon emissions due to land use change', - nameCode: INDICATOR_TYPES.CLIMATE_RISK, + nameCode: INDICATOR_NAME_CODES.CLIMATE_RISK, }, { name: 'Biodiversity loss due to land use change', - nameCode: INDICATOR_TYPES.LAND_USE, + nameCode: INDICATOR_NAME_CODES.LAND_USE, }, { name: 'Unsustainable water use', - nameCode: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, + nameCode: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, }, ]; diff --git a/api/test/integration/import-data/xlsx-uploads/sourcing-data-import.spec.ts b/api/test/integration/import-data/xlsx-uploads/sourcing-data-import.spec.ts index 688ee85694..c7e5825c16 100644 --- a/api/test/integration/import-data/xlsx-uploads/sourcing-data-import.spec.ts +++ b/api/test/integration/import-data/xlsx-uploads/sourcing-data-import.spec.ts @@ -50,7 +50,7 @@ import { createWorldToCalculateIndicatorRecords } from '../../../utils/indicator import { GeoCodingAbstractClass } from 'modules/geo-coding/geo-coding-abstract-class'; import { Material, MATERIALS_STATUS } from 'modules/materials/material.entity'; import { ScenarioIntervention } from 'modules/scenario-interventions/scenario-intervention.entity'; -import { SourcingRecordsWithIndicatorRawDataDtoV2 } from 'modules/sourcing-records/dto/sourcing-records-with-indicator-raw-data.dto'; +import { SourcingRecordsWithIndicatorRawData } from 'modules/sourcing-records/dto/sourcing-records-with-indicator-raw-data.dto'; import { ImpactCalculator } from 'modules/indicator-records/services/impact-calculator.service'; import { DataSource } from 'typeorm'; import { TasksRepository } from 'modules/tasks/tasks.repository'; @@ -443,8 +443,8 @@ describe('Sourcing Data import', () => { tonnage: 500, }); - const indicatorRawDataForImport: SourcingRecordsWithIndicatorRawDataDtoV2[] = - await impactCalculatorService.getIndicatorRawDataForAllSourcingRecordsV2( + const indicatorRawDataForImport: SourcingRecordsWithIndicatorRawData[] = + await impactCalculatorService.getImpactRawDataForAllSourcingRecords( indicatorPreconditions.indicators, ); diff --git a/api/test/integration/indicator-record/calculations/indicator-records.service.spec.ts b/api/test/integration/indicator-record/calculations/indicator-records.service.spec.ts index 70442a159b..bf07dc9548 100644 --- a/api/test/integration/indicator-record/calculations/indicator-records.service.spec.ts +++ b/api/test/integration/indicator-record/calculations/indicator-records.service.spec.ts @@ -16,7 +16,7 @@ import { } from '../../../entity-mocks'; import { Indicator, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { @@ -182,9 +182,9 @@ describe('Impact Calculator Tests', () => { }; const providedCoefficients: IndicatorCoefficientsDto = { - [INDICATOR_TYPES.WATER_USE]: 0.1, - [INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE]: 0.4, - [INDICATOR_TYPES.DEFORESTATION_RISK]: 0.35, + [INDICATOR_NAME_CODES.WATER_USE]: 0.1, + [INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE]: 0.4, + [INDICATOR_NAME_CODES.DEFORESTATION_RISK]: 0.35, ...({} as any), }; @@ -199,7 +199,7 @@ describe('Impact Calculator Tests', () => { //ASSERT //await expect(testStatement).rejects.toThrow(NotFoundException); await expect(testStatement).rejects.toThrow( - `Required coefficient for indicator ${INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE} was not provided`, + `Required coefficient for indicator ${INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE} was not provided`, ); }); @@ -237,13 +237,15 @@ describe('Impact Calculator Tests', () => { }; const providedCoefficients: IndicatorCoefficientsDto = { - [INDICATOR_TYPES.CLIMATE_RISK]: 0.1, - [INDICATOR_TYPES.DEFORESTATION_RISK]: 0.4, - [INDICATOR_TYPES.LAND_USE]: 0.35, - [INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE]: 0.2, - [INDICATOR_TYPES.WATER_USE]: 0.6, - [INDICATOR_TYPES.SATELLIGENCE_DEFORESTATION]: 0.3, - [INDICATOR_TYPES.SATELLIGENCE_DEFORESTATION_RISK]: 0.5, + [INDICATOR_NAME_CODES.CLIMATE_RISK]: 0.1, + [INDICATOR_NAME_CODES.DEFORESTATION_RISK]: 0.4, + [INDICATOR_NAME_CODES.LAND_USE]: 0.35, + [INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE]: 0.2, + [INDICATOR_NAME_CODES.WATER_USE]: 0.6, + [INDICATOR_NAME_CODES.SATELLIGENCE_DEFORESTATION]: 0.3, + [INDICATOR_NAME_CODES.SATELLIGENCE_DEFORESTATION_RISK]: 0.5, + [INDICATOR_NAME_CODES.NATURAL_ECOSYSTEM_CONVERSION_RISK]: 0.7, + [INDICATOR_NAME_CODES.WATER_QUALITY]: 0.8, }; //ACT @@ -421,7 +423,7 @@ describe('Impact Calculator Tests', () => { //ASSERT await expect(testStatement).rejects.toThrow(NotFoundException); await expect(testStatement).rejects.toThrow( - `H3 Data of required Indicator of type ${INDICATOR_TYPES.DEFORESTATION_RISK} missing for ${INDICATOR_TYPES.DEFORESTATION_RISK} Indicator Record value calculations`, + `H3 Data of required Indicator of type ${INDICATOR_NAME_CODES.DEFORESTATION_RISK} missing for ${INDICATOR_NAME_CODES.DEFORESTATION_RISK} Indicator Record value calculations`, ); }); @@ -469,7 +471,7 @@ describe('Impact Calculator Tests', () => { indicatorPreconditions.deforestationIndicator, materialH3DataProducer, sourcingData.sourcingRecordId, - 805000, + 80.74534161490683, 1610, calculatedRecords, ); @@ -477,7 +479,7 @@ describe('Impact Calculator Tests', () => { indicatorPreconditions.climateRiskIndicator, materialH3DataProducer, sourcingData.sourcingRecordId, - 805000, + 80.74534161490683, 1610, calculatedRecords, ); @@ -554,7 +556,7 @@ describe('Impact Calculator Tests', () => { indicatorPreconditions.deforestationIndicator, materialH3DataProducer1, indicatorPreconditions.sourcingRecord1.id, - 1610000, + 161.49068322981367, 1610, ); await checkCreatedIndicatorRecord( @@ -568,7 +570,7 @@ describe('Impact Calculator Tests', () => { indicatorPreconditions.climateRiskIndicator, materialH3DataProducer1, indicatorPreconditions.sourcingRecord1.id, - 1610000, + 161.49068322981367, 1610, ); await checkCreatedIndicatorRecord( @@ -583,7 +585,7 @@ describe('Impact Calculator Tests', () => { indicatorPreconditions.deforestationIndicator, materialH3DataProducer2, indicatorPreconditions.sourcingRecord2.id, - 805000, + 80.74534161490683, 1610, ); await checkCreatedIndicatorRecord( @@ -597,7 +599,7 @@ describe('Impact Calculator Tests', () => { indicatorPreconditions.climateRiskIndicator, materialH3DataProducer2, indicatorPreconditions.sourcingRecord2.id, - 805000, + 80.74534161490683, 1610, ); await checkCreatedIndicatorRecord( @@ -654,13 +656,13 @@ describe('Impact Calculator Tests', () => { indicatorRecordServiceAny.generateMaterialCalculationCacheKey; //Prepare Cache Data - const bioMap: Map = new Map(); + const bioMap: Map = new Map(); bioMap.set( - INDICATOR_TYPES.LAND_USE, + INDICATOR_NAME_CODES.LAND_USE, indicatorPreconditions.biodiversityLoss, ); bioMap.set( - INDICATOR_TYPES.DEFORESTATION_RISK, + INDICATOR_NAME_CODES.DEFORESTATION_RISK, indicatorPreconditions.deforestation, ); const materialsMap: Map = new Map(); @@ -669,7 +671,7 @@ describe('Impact Calculator Tests', () => { const bioCacheKey: any = generateIndicatorCacheKey( indicatorPreconditions.sourcingLocation2.geoRegionId, - INDICATOR_TYPES.LAND_USE, + INDICATOR_NAME_CODES.LAND_USE, bioMap, materialsMap, ); @@ -1040,30 +1042,31 @@ describe('Impact Calculator Tests', () => { const h3Data = await createWorldToCalculateIndicatorRecords(dataSource); const climateRiskIndicator = h3Data.indicators.find( - (el: Indicator) => el.nameCode === INDICATOR_TYPES.CLIMATE_RISK, + (el: Indicator) => el.nameCode === INDICATOR_NAME_CODES.CLIMATE_RISK, ); const landUseIndicator = h3Data.indicators.find( - (el: Indicator) => el.nameCode === INDICATOR_TYPES.LAND_USE, + (el: Indicator) => el.nameCode === INDICATOR_NAME_CODES.LAND_USE, ); const deforestationIndicator = h3Data.indicators.find( - (el: Indicator) => el.nameCode === INDICATOR_TYPES.DEFORESTATION_RISK, + (el: Indicator) => + el.nameCode === INDICATOR_NAME_CODES.DEFORESTATION_RISK, ); const waterUseIndicator = h3Data.indicators.find( - (el: Indicator) => el.nameCode === INDICATOR_TYPES.WATER_USE, + (el: Indicator) => el.nameCode === INDICATOR_NAME_CODES.WATER_USE, ); const unsustWaterUseIndicator = h3Data.indicators.find( (el: Indicator) => - el.nameCode === INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, + el.nameCode === INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, ); const satelligenceDeforestation = h3Data.indicators.find( (el: Indicator) => - el.nameCode === INDICATOR_TYPES.SATELLIGENCE_DEFORESTATION, + el.nameCode === INDICATOR_NAME_CODES.SATELLIGENCE_DEFORESTATION, ); const satelligenceDeforestationRisk = h3Data.indicators.find( (el: Indicator) => - el.nameCode === INDICATOR_TYPES.SATELLIGENCE_DEFORESTATION_RISK, + el.nameCode === INDICATOR_NAME_CODES.SATELLIGENCE_DEFORESTATION_RISK, ); return { material1, diff --git a/api/test/integration/indicators/status-changes/indicator-status-changes.spec.ts b/api/test/integration/indicators/status-changes/indicator-status-changes.spec.ts index 11a96f33aa..7e83b034bb 100644 --- a/api/test/integration/indicators/status-changes/indicator-status-changes.spec.ts +++ b/api/test/integration/indicators/status-changes/indicator-status-changes.spec.ts @@ -2,7 +2,7 @@ import { clearTestDataFromDatabase } from '../../../utils/database-test-helper'; import { Indicator, INDICATOR_STATUS, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { IndicatorsService } from 'modules/indicators/indicators.service'; import { createIndicator } from '../../../entity-mocks'; @@ -36,10 +36,10 @@ describe('Indicators - Status (Integration Tests', () => { afterAll(() => testApplication.close()); test('When I provide some NameCodes to activate Indicators, Indicators matching these nameCode should be activated', async () => { - const nameCodeArray: string[] = Object.values(INDICATOR_TYPES); + const nameCodeArray: string[] = Object.values(INDICATOR_NAME_CODES); for (const nameCode of nameCodeArray) { await createIndicator({ - nameCode, + nameCode: nameCode as INDICATOR_NAME_CODES, status: INDICATOR_STATUS.INACTIVE, name: nameCode, }); @@ -73,7 +73,7 @@ describe('Indicators - Status (Integration Tests', () => { test('When I provide some NameCodes to activate Indicators, but there is any match against the ones that are in the DB, Then I should get a error', async () => { for (const n of [1, 2, 3, 4]) { await createIndicator({ - nameCode: `${n}`, + nameCode: `${n}` as INDICATOR_NAME_CODES, status: INDICATOR_STATUS.INACTIVE, name: `${n}`, }); @@ -83,7 +83,7 @@ describe('Indicators - Status (Integration Tests', () => { try { await indicatorService.activateIndicators( - Object.values(INDICATOR_TYPES).map( + Object.values(INDICATOR_NAME_CODES).map( (n: string) => ({ nameCode: n } as CreateIndicatorDto), ), ); @@ -94,10 +94,10 @@ describe('Indicators - Status (Integration Tests', () => { } }); test('When there are some Indicators with status active in the DB, Then I should be able to set them Inactive ', async () => { - const nameCodeArray: string[] = Object.values(INDICATOR_TYPES); + const nameCodeArray: string[] = Object.values(INDICATOR_NAME_CODES); for (const nameCode of nameCodeArray) { await createIndicator({ - nameCode, + nameCode: nameCode as INDICATOR_NAME_CODES, status: INDICATOR_STATUS.ACTIVE, name: nameCode, }); diff --git a/api/test/utils/indicator-records-preconditions.ts b/api/test/utils/indicator-records-preconditions.ts index 77a1abf548..ec31e6c953 100644 --- a/api/test/utils/indicator-records-preconditions.ts +++ b/api/test/utils/indicator-records-preconditions.ts @@ -8,7 +8,7 @@ import { createH3Data, createIndicator } from '../entity-mocks'; import { h3IndicatorExampleDataFixture } from '../e2e/h3-data/mocks/h3-fixtures'; import { Indicator, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { DataSource } from 'typeorm'; @@ -18,24 +18,24 @@ export const createWorldToCalculateIndicatorRecords = async ( // Creating Indicators: const climateRisk: Indicator = await createIndicator({ name: 'climate risk', - nameCode: INDICATOR_TYPES.CLIMATE_RISK, + nameCode: INDICATOR_NAME_CODES.CLIMATE_RISK, }); const waterUse: Indicator = await createIndicator({ name: 'water use', - nameCode: INDICATOR_TYPES.WATER_USE, + nameCode: INDICATOR_NAME_CODES.WATER_USE, }); const unsustainableWaterUse: Indicator = await createIndicator({ name: 'unsust water use', - nameCode: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, + nameCode: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, }); const deforestation: Indicator = await createIndicator({ name: 'def risk', - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); const landUse: Indicator = await createIndicator({ name: 'land use', - nameCode: INDICATOR_TYPES.LAND_USE, + nameCode: INDICATOR_NAME_CODES.LAND_USE, }); // Creating tables with h3Data for the new indicators @@ -43,18 +43,22 @@ export const createWorldToCalculateIndicatorRecords = async ( const croplandAreaH3Data = await createH3Data({ h3columnName: 'spam2010V2R0GlobalHAllA', h3tableName: 'h3_grid_spam2010v2r0_global_ha', + indicatorId: climateRisk.id, }); const weightedCarbonH3Data = await createH3Data({ h3columnName: 'forestGhgBuffered2021', h3tableName: 'h3_grid_ghg_global', + indicatorId: climateRisk.id, }); const weightedDeforestationH3Data = await createH3Data({ h3columnName: 'hansenLossBuffered2021', h3tableName: 'h3_grid_deforestation_global', + indicatorId: deforestation.id, }); const waterStressH3Data = await createH3Data({ h3columnName: 'bwsCat', h3tableName: 'h3_grid_aqueduct_global', + indicatorId: unsustainableWaterUse.id, }); for await (const H3Data of [ diff --git a/api/test/utils/scenario-interventions-preconditions.ts b/api/test/utils/scenario-interventions-preconditions.ts index 927e86d045..051e5971aa 100644 --- a/api/test/utils/scenario-interventions-preconditions.ts +++ b/api/test/utils/scenario-interventions-preconditions.ts @@ -6,7 +6,7 @@ import { SourcingLocation } from 'modules/sourcing-locations/sourcing-location.e import { Supplier } from 'modules/suppliers/supplier.entity'; import { Indicator, - INDICATOR_TYPES, + INDICATOR_NAME_CODES, } from 'modules/indicators/indicator.entity'; import { SourcingRecord } from 'modules/sourcing-records/sourcing-record.entity'; import { @@ -94,24 +94,24 @@ export async function createInterventionPreconditions( const indicator1: Indicator = await createIndicator({ name: 'climate risk', - nameCode: INDICATOR_TYPES.CLIMATE_RISK, + nameCode: INDICATOR_NAME_CODES.CLIMATE_RISK, }); const indicator2: Indicator = await createIndicator({ name: 'water use', - nameCode: INDICATOR_TYPES.WATER_USE, + nameCode: INDICATOR_NAME_CODES.WATER_USE, }); const indicator3: Indicator = await createIndicator({ name: 'unsust water use', - nameCode: INDICATOR_TYPES.UNSUSTAINABLE_WATER_USE, + nameCode: INDICATOR_NAME_CODES.UNSUSTAINABLE_WATER_USE, }); const indicator4: Indicator = await createIndicator({ name: 'def risk', - nameCode: INDICATOR_TYPES.DEFORESTATION_RISK, + nameCode: INDICATOR_NAME_CODES.DEFORESTATION_RISK, }); await createIndicator({ name: 'land use', - nameCode: INDICATOR_TYPES.LAND_USE, + nameCode: INDICATOR_NAME_CODES.LAND_USE, }); // Creating tables with h3Data for the new indicators @@ -119,18 +119,22 @@ export async function createInterventionPreconditions( const croplandAreaH3Data = await createH3Data({ h3columnName: 'spam2010V2R0GlobalHAllA', h3tableName: 'h3_grid_spam2010v2r0_global_ha', + indicatorId: indicator1.id, }); const weightedCarbonH3Data = await createH3Data({ h3columnName: 'forestGhgBuffered2021', h3tableName: 'h3_grid_ghg_global', + indicatorId: indicator4.id, }); const weightedDeforestationH3Data = await createH3Data({ h3columnName: 'hansenLossBuffered2021', h3tableName: 'h3_grid_deforestation_global', + indicatorId: indicator2.id, }); const waterStressH3Data = await createH3Data({ h3columnName: 'bwsCat', h3tableName: 'h3_grid_aqueduct_global', + indicatorId: indicator3.id, }); for await (const H3Data of [