diff --git a/admin/datasource.ts b/admin/datasource.ts index e731ada1..161ef3d4 100644 --- a/admin/datasource.ts +++ b/admin/datasource.ts @@ -29,12 +29,16 @@ import { ImplementationLaborCost } from "@shared/entities/cost-inputs/implementa import { BaseSize } from "@shared/entities/base-size.entity.js"; import { BaseIncrease } from "@shared/entities/base-increase.entity.js"; import { ModelAssumptions } from "@shared/entities/model-assumptions.entity.js"; -import { UserUploadCostInputs } from "@shared/entities/user-project-data.entity.js"; +import { UserUploadCostInputs } from "@shared/entities/users/user-upload-cost-inputs.entity.js"; +import { UserUploadRestorationInputs } from "@shared/entities/users/user-upload-restoration-inputs.entity.js"; +import { UserUploadConservationInputs } from "@shared/entities/users/user-upload-conservation-inputs.entity.js"; // TODO: If we import the COMMON_DATABASE_ENTITIES from shared, we get an error where DataSouce is not set for a given entity export const ADMINJS_ENTITIES = [ User, UserUploadCostInputs, + UserUploadRestorationInputs, + UserUploadConservationInputs, ApiEventsEntity, Country, ProjectSize, diff --git a/admin/index.ts b/admin/index.ts index 19e53ce4..585e839d 100644 --- a/admin/index.ts +++ b/admin/index.ts @@ -33,7 +33,9 @@ import { ImplementationLaborCostResource } from "./resources/implementation-labo import { BaseSizeResource } from "./resources/base-size/base-size.resource.js"; import { BaseIncreaseResource } from "./resources/base-increase/base-increase.resource.js"; import { ModelAssumptionResource } from "./resources/model-assumptions/model-assumptions.resource.js"; -import { UserUploadCostInputs } from "@shared/entities/user-project-data.entity.js"; +import { UserUploadCostInputs } from "@shared/entities/users/user-upload-cost-inputs.entity.js"; +import { UserUploadConservationInputs } from "@shared/entities/users/user-upload-conservation-inputs.entity.js"; +import { UserUploadRestorationInputs } from "@shared/entities/users/user-upload-restoration-inputs.entity.js"; AdminJS.registerAdapter({ Database: AdminJSTypeorm.Database, @@ -70,6 +72,26 @@ const start = async () => { }, }, }, + { + resource: UserUploadConservationInputs, + name: "UserUploadConservationInputs", + options: { + navigation: { + name: "User Data", + icon: "File", + }, + }, + }, + { + resource: UserUploadRestorationInputs, + name: "UserUploadRestorationInputs", + options: { + navigation: { + name: "User Data", + icon: "File", + }, + }, + }, ProjectSizeResource, FeasibilityAnalysisResource, ConservationAndPlanningAdminResource, @@ -100,7 +122,6 @@ const start = async () => { resource: Country, name: "Country", options: { - id: "Countries", parent: databaseNavigation, icon: "Globe", }, diff --git a/api/src/modules/import/import.controller.ts b/api/src/modules/import/import.controller.ts index cd0b4d28..9a4292fd 100644 --- a/api/src/modules/import/import.controller.ts +++ b/api/src/modules/import/import.controller.ts @@ -20,7 +20,6 @@ import { Multer } from 'multer'; import { GetUser } from '@api/modules/auth/decorators/get-user.decorator'; import { User } from '@shared/entities/users/user.entity'; import { usersContract } from '@shared/contracts/users.contract'; -import { Public } from '@api/modules/auth/decorators/is-public.decorator'; @Controller() @UseGuards(JwtAuthGuard, RolesGuard) @@ -45,7 +44,6 @@ export class ImportController { }); } - //@Public() @UseInterceptors(FilesInterceptor('files', 2)) @RequiredRoles(ROLES.PARTNER, ROLES.ADMIN) @TsRestHandler(usersContract.uploadData) @@ -54,7 +52,6 @@ export class ImportController { @UploadedFiles() files: Array, ): Promise { return tsRestHandler(usersContract.uploadData, async () => { - console.log(files); const [file1, file2] = files; const [file1Buffer, file2Buffer] = [file1.buffer, file2.buffer]; const data = await this.service.importDataProvidedByPartner( diff --git a/api/src/modules/import/import.service.ts b/api/src/modules/import/import.service.ts index 42ccc4e3..b4f5c57f 100644 --- a/api/src/modules/import/import.service.ts +++ b/api/src/modules/import/import.service.ts @@ -10,10 +10,13 @@ import { API_EVENT_TYPES } from '@api/modules/api-events/events.enum'; import { ImportEvent } from '@api/modules/import/events/import.event'; import { DataSource } from 'typeorm'; import { - userDataInputJson, - userDataMapJsonToEntity, + userDataConservationInputMapJsonToEntity, + userDataCostInputsMapJsonToEntity, + userDataRestorationInputMapJsonToEntity, } from '@api/modules/import/services/user-data-parser'; -import { UserUploadCostInputs } from '@shared/entities/user-project-data.entity'; +import { UserUploadCostInputs } from '@shared/entities/users/user-upload-cost-inputs.entity'; +import { UserUploadRestorationInputs } from '@shared/entities/users/user-upload-restoration-inputs.entity'; +import { UserUploadConservationInputs } from '@shared/entities/users/user-upload-conservation-inputs.entity'; @Injectable() export class ImportService { @@ -53,11 +56,34 @@ export class ImportService { } async importDataProvidedByPartner(fileBuffers: Buffer[], userId: string) { - const { costInputs } = await this.excelParser.parseUserExcels(fileBuffers); - const mapped = userDataMapJsonToEntity(userDataInputJson, userId); - const savedData = await this.dataSource - .getRepository(UserUploadCostInputs) - .save(mapped); - return savedData; + // TODO: Debt, add event handling + const { costInputs, carbonInputs } = + await this.excelParser.parseUserExcels(fileBuffers); + const mappedCostInputs = userDataCostInputsMapJsonToEntity( + costInputs, + userId, + ); + const mappedRestorationInputs = userDataRestorationInputMapJsonToEntity( + carbonInputs.restoration, + userId, + ); + const mappedConservationInputs = userDataConservationInputMapJsonToEntity( + carbonInputs.conservation, + userId, + ); + await this.dataSource.transaction(async (manager) => { + const userCostInputsRepo = manager.getRepository(UserUploadCostInputs); + const userRestorationInputsRepo = manager.getRepository( + UserUploadRestorationInputs, + ); + const userConservationInputsRepo = manager.getRepository( + UserUploadConservationInputs, + ); + await userCostInputsRepo.save(mappedCostInputs); + await userRestorationInputsRepo.save(mappedRestorationInputs); + await userConservationInputsRepo.save(mappedConservationInputs); + }); + // + return carbonInputs; } } diff --git a/api/src/modules/import/services/user-data-parser.ts b/api/src/modules/import/services/user-data-parser.ts index 0cc68e10..edc711fa 100644 --- a/api/src/modules/import/services/user-data-parser.ts +++ b/api/src/modules/import/services/user-data-parser.ts @@ -1,60 +1,10 @@ // I feel dirty doing this... -import { UserUploadCostInputs } from '@shared/entities/user-project-data.entity'; +import { UserUploadCostInputs } from '@shared/entities/users/user-upload-cost-inputs.entity'; +import { UserUploadRestorationInputs } from '@shared/entities/users/user-upload-restoration-inputs.entity'; +import { UserUploadConservationInputs } from '@shared/entities/users/user-upload-conservation-inputs.entity'; -export const userDataInputJson = { - 'Program name (if willing to share)': 'test name', - 'Intended length of project': 2000, - Country: 'Basque Country', - Currency: 'Euro', - 'Project start year': 1, - 'Project activity': 'Conservation', - Ecosystem: 'Mangrove', - 'Project size': 'something', - 'Validation standard / accrediting organization': 'Verra', - 'Number of local individuals who own, work, and/or live in the project site (e.g., land tenure)': - 'land tenure', - 'City / province / region / state of project': 'Azpeiti', - 'Intended alternative use of land': 'commercial', - 'Land ownership before project': 'private', - 'SDGs benefitted / co-benefitted': 'sdg', - 'Project eligible for voluntary carbon credits?': 'no', - 'Are you willing to speak with us about your carbon credit pricing?': 'yes', - 'Are you able to provide additional detailed cost documentation for the project?': - 'yes', - 'Cost categories ': 'Detailed activities...', - 'Establishing community engagement / buy-in': 1, - 'Conservation project planning & administration ': 2, - 'Carbon project planning & administration': 3, - 'Land cost': 4, - 'Financing cost': 5, - 'Materials (e.g., seeds, fertilizer, seedlings)': 6, - 'Materials (e.g., machinery, equipment, etc.)': 7, - 'Project labor / activity': 8, - 'Engineering / construction intervention': 9, - 'Ongoing community engagement': 10, - 'Other project running cost': 11, - 'Project monitoring': 12, - '1) Other cost (please specify activities)': 13, - '2) Other cost (please specify activities)': 14, - '3) Other cost (please specify activities)': 15, - 'Project site cumulative sequestration / carbon stock': 'something', - 'Please describe in detail the project activity (e.g., planted mangrove seedlings, set up perimeter around conservation area)': - 'question 1', - 'When you kicked off the project, how did you spend to engage the community...': - 'question 2', - 'How did you acquire the rights to establish the project on the land?...': - 'question 3', - 'What was the hourly wage rate paid for labor? How many hours worked for each activity?': - 'question 4', - 'Please describe the ongoing community engagement for your project.': - 'question 5', - 'Did you undertake any engineering / construction interventions for your project?': - 'question 6', -}; - -// Función para transformar el JSON -export function userDataMapJsonToEntity( +export function userDataCostInputsMapJsonToEntity( inputJson: Record, userId: string, ): Partial { @@ -138,3 +88,63 @@ export function userDataMapJsonToEntity( user: { id: userId } as any, }; } + +export function userDataRestorationInputMapJsonToEntity( + data: Record, + userId: string, +): Partial { + return { + projectName: data['Project name'], + country: data['Country'], + cityOrRegion: data['City / province / region / state of project'], + projectStartYear: data['Project start year'], + mostRecentYearOfData: data['Most recent year of data collection'], + ecosystem: data['Ecosystem'], + projectActivity: data['Project activity']?.toString(), // Convertir a string si es numérico + projectSizeAreaStudied: data['Project size / area studied'], + categories: data['Categories'], + projectArea: data['Project area '], + abovegroundBiomassStock: data['Aboveground biomass stock'], + belowgroundBiomassStock: data['Belowground biomass stock '], + soilOrganicCarbonStock: data['Soil organic carbon stock '], + methaneEmissions: data['Methane emissions '], + nitrousOxideEmissions: data['Nitrous oxide emissions '], + abovegroundBiomassEmissionsFactor: + data['Aboveground biomass emissions factor'], + belowgroundBiomassEmissionsFactor: + data['Belowground biomass emissions factor'], + soilOrganicCarbonEmissionsFactor: + data['Soil organic carbon emissions factor '], + user: { id: userId } as any, + }; +} + +export function userDataConservationInputMapJsonToEntity( + data: Record, + userId: string, +): Partial { + return { + projectName: data['Project name'], + country: data['Country'], + cityOrRegion: data['City / province / region / state of project'], + projectStartYear: data['Project start year'], + mostRecentYearOfData: data['Most recent year of data collection'], + ecosystem: data['Ecosystem'], + projectActivity: data['Project activity']?.toString(), // Convertir a string si es numérico + projectSizeAreaStudied: data['Project size / area studied'], + categories: data['Categories'], + projectArea: data['Project area '], + abovegroundBiomassStock: data['Aboveground biomass stock'], + belowgroundBiomassStock: data['Belowground biomass stock '], + soilOrganicCarbonStock: data['Soil organic carbon stock '], + methaneEmissions: data['Methane emissions '], + nitrousOxideEmissions: data['Nitrous oxide emissions '], + abovegroundBiomassEmissionsFactor: + data['Aboveground biomass emissions factor'], + belowgroundBiomassEmissionsFactor: + data['Belowground biomass emissions factor'], + soilOrganicCarbonEmissionsFactor: + data['Soil organic carbon emissions factor '], + user: { id: userId } as any, + }; +} diff --git a/api/src/modules/import/services/xlsx.parser.ts b/api/src/modules/import/services/xlsx.parser.ts index 33510e66..caf2d698 100644 --- a/api/src/modules/import/services/xlsx.parser.ts +++ b/api/src/modules/import/services/xlsx.parser.ts @@ -25,35 +25,24 @@ export class XlsxParser implements ExcelParserInterface { async parseUserExcels(data: Buffer[]) { const carbonInputs: WorkBook = read(data[0]); const costInputs: WorkBook = read(data[1]); - const CARBON_INPUTS_SHEETS = ['Restoration', 'Conservation']; - const COST_INPUTS_SHEETS = ['Input']; - const parsedCarbonInputs: any = {}; - let parsedCostInputs: WorkSheet; - // - // for (const sheetName of CARBON_INPUTS_SHEETS) { - // const sheet: WorkSheet = carbonInputs.Sheets[sheetName]; - // const parsedSheet = utils.sheet_to_json(sheet, { - // raw: true, - // }); - // parsedCarbonInputs[sheetName] = parsedSheet; - // } - - for (const sheetName of COST_INPUTS_SHEETS) { - parsedCostInputs = costInputs.Sheets[sheetName]; - //= utils.sheet_to_json(sheet, { header: 4 }); - //parsedCostInputs[sheetName] = parsedSheet; - } - const result: Record = {}; + + const restorationSheet: WorkSheet = carbonInputs.Sheets['Restoration']; + const conservationSheet: WorkSheet = carbonInputs.Sheets['Conservation']; + const restoration = parseRestorationSheet(restorationSheet); + const costInputSheet = costInputs.Sheets['Input']; + const conservation = parseConservationSheet(conservationSheet); + + const costInput: Record = {}; const keysToIgnore = [ 'Input data into blue shade cells', 'General information', 'Project information', ]; - Object.keys(parsedCostInputs).forEach((cellKey) => { + Object.keys(costInputSheet).forEach((cellKey) => { if (!cellKey.startsWith('B')) return; // Ignore cells that are not in column B - const questionCell = parsedCostInputs[cellKey]; + const questionCell = costInputSheet[cellKey]; const question = questionCell?.v; if (question && !keysToIgnore.includes(question)) { @@ -61,16 +50,70 @@ export class XlsxParser implements ExcelParserInterface { const rowIndex = cellKey.match(/\d+/)?.[0]; // extract row number from cell key const answerCellKey = `C${rowIndex}`; const answerCell = - parsedCostInputs[answerCellKey] || parsedCostInputs[`D${rowIndex}`]; + costInputSheet[answerCellKey] || costInputSheet[`D${rowIndex}`]; const answer = answerCell?.v || 'No value provided'; - result[question] = answer; + costInput[question] = answer; } }); return { - //carbonInputs: parsedCarbonInputs, - costInputs: result, + carbonInputs: { restoration, conservation }, + costInputs: costInput, }; } } + +function parseRestorationSheet(sheet: WorkSheet): Record { + const result: Record = {}; + + const keysToIgnore = [ + 'Sub-national / project sequestration information', + 'General information', + ]; + + Object.keys(sheet).forEach((cellKey) => { + if (!cellKey.startsWith('B')) return; + + const questionCell = sheet[cellKey]; + const question = questionCell?.v; + + if (question && !keysToIgnore.includes(question)) { + const rowIndex = cellKey.match(/\d+/)?.[0]; + const answerCellKey = `C${rowIndex}`; + const answerCell = sheet[answerCellKey]; + + const answer = answerCell?.v || 'No value provided'; + result[question] = answer; + } + }); + + return result; +} + +function parseConservationSheet(sheet: WorkSheet): Record { + const result: Record = {}; + + const keysToIgnore = [ + 'Sub-national / project sequestration information', + 'General information', + ]; + + Object.keys(sheet).forEach((cellKey) => { + if (!cellKey.startsWith('B')) return; + + const questionCell = sheet[cellKey]; + const question = questionCell?.v; + + if (question && !keysToIgnore.includes(question)) { + const rowIndex = cellKey.match(/\d+/)?.[0]; + const answerCellKey = `C${rowIndex}`; + const answerCell = sheet[answerCellKey]; + + const answer = answerCell?.v || 'No value provided'; + result[question] = answer; + } + }); + + return result; +} diff --git a/api/src/modules/users/users.module.ts b/api/src/modules/users/users.module.ts index 075802af..9810333c 100644 --- a/api/src/modules/users/users.module.ts +++ b/api/src/modules/users/users.module.ts @@ -4,11 +4,18 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { User } from '@shared/entities/users/user.entity'; import { UsersController } from '@api/modules/users/users.controller'; import { AuthModule } from '@api/modules/auth/auth.module'; -import { UserUploadCostInputs } from '@shared/entities/user-project-data.entity'; +import { UserUploadCostInputs } from '@shared/entities/users/user-upload-cost-inputs.entity'; +import { UserUploadRestorationInputs } from '@shared/entities/users/user-upload-restoration-inputs.entity'; +import { UserUploadConservationInputs } from '@shared/entities/users/user-upload-conservation-inputs.entity'; @Module({ imports: [ - TypeOrmModule.forFeature([User, UserUploadCostInputs]), + TypeOrmModule.forFeature([ + User, + UserUploadCostInputs, + UserUploadRestorationInputs, + UserUploadConservationInputs, + ]), forwardRef(() => AuthModule), ], providers: [UsersService], diff --git a/shared/entities/users/user-upload-conservation-inputs.entity.ts b/shared/entities/users/user-upload-conservation-inputs.entity.ts new file mode 100644 index 00000000..429065bd --- /dev/null +++ b/shared/entities/users/user-upload-conservation-inputs.entity.ts @@ -0,0 +1,73 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + BaseEntity, + ManyToOne, + JoinColumn, +} from "typeorm"; +import { User } from "@shared/entities/users/user.entity"; + +@Entity("user_upload_conservation_inputs") +export class UserUploadConservationInputs extends BaseEntity { + @PrimaryGeneratedColumn() + id: number; + + @ManyToOne(() => User, (user) => user.userUploadConservationInputs) + @JoinColumn({ name: "user_id" }) + user: User; + + @Column({ type: "varchar", length: 255, nullable: true }) + projectName: string; + + @Column({ type: "varchar", length: 255, nullable: true }) + country: string; + + @Column({ type: "varchar", length: 255, nullable: true }) + cityOrRegion: string; + + @Column({ type: "int", nullable: true }) + projectStartYear: number; + + @Column({ type: "int", nullable: true }) + mostRecentYearOfData: number; + + @Column({ type: "varchar", length: 255, nullable: true }) + ecosystem: string; + + @Column({ type: "varchar", length: 255, nullable: true }) + projectActivity: string; + + @Column({ type: "int", nullable: true }) + projectSizeAreaStudied: number; + + @Column({ type: "varchar", length: 255, nullable: true }) + categories: string; + + @Column({ type: "int", nullable: true }) + projectArea: number; + + @Column({ type: "int", nullable: true }) + abovegroundBiomassStock: number; + + @Column({ type: "int", nullable: true }) + belowgroundBiomassStock: number; + + @Column({ type: "int", nullable: true }) + soilOrganicCarbonStock: number; + + @Column({ type: "int", nullable: true }) + methaneEmissions: number; + + @Column({ type: "int", nullable: true }) + nitrousOxideEmissions: number; + + @Column({ type: "int", nullable: true }) + abovegroundBiomassEmissionsFactor: number; + + @Column({ type: "int", nullable: true }) + belowgroundBiomassEmissionsFactor: number; + + @Column({ type: "int", nullable: true }) + soilOrganicCarbonEmissionsFactor: number; +} diff --git a/shared/entities/user-project-data.entity.ts b/shared/entities/users/user-upload-cost-inputs.entity.ts similarity index 98% rename from shared/entities/user-project-data.entity.ts rename to shared/entities/users/user-upload-cost-inputs.entity.ts index 48e015c5..16e97e66 100644 --- a/shared/entities/user-project-data.entity.ts +++ b/shared/entities/users/user-upload-cost-inputs.entity.ts @@ -13,7 +13,7 @@ export class UserUploadCostInputs extends BaseEntity { @PrimaryGeneratedColumn("uuid") id: string; - @ManyToOne(() => User, (user) => user.uploadedData) + @ManyToOne(() => User, (user) => user.uploadedCostInputs) @JoinColumn({ name: "user_id" }) user: User; diff --git a/shared/entities/users/user-upload-restoration-inputs.entity.ts b/shared/entities/users/user-upload-restoration-inputs.entity.ts new file mode 100644 index 00000000..be43501a --- /dev/null +++ b/shared/entities/users/user-upload-restoration-inputs.entity.ts @@ -0,0 +1,73 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + BaseEntity, + ManyToOne, + JoinColumn, +} from "typeorm"; +import { User } from "@shared/entities/users/user.entity"; + +@Entity("user_upload_restoration_inputs") +export class UserUploadRestorationInputs extends BaseEntity { + @PrimaryGeneratedColumn() + id: number; + + @ManyToOne(() => User, (user) => user.userUploadRestorationInputs) + @JoinColumn({ name: "user_id" }) + user: User; + + @Column({ type: "varchar", length: 255, nullable: true }) + projectName: string; + + @Column({ type: "varchar", length: 255, nullable: true }) + country: string; + + @Column({ type: "varchar", length: 255, nullable: true }) + cityOrRegion: string; + + @Column({ type: "int", nullable: true }) + projectStartYear: number; + + @Column({ type: "int", nullable: true }) + mostRecentYearOfData: number; + + @Column({ type: "varchar", length: 255, nullable: true }) + ecosystem: string; + + @Column({ type: "varchar", length: 255, nullable: true }) + projectActivity: string; + + @Column({ type: "int", nullable: true }) + projectSizeAreaStudied: number; + + @Column({ type: "varchar", length: 255, nullable: true }) + categories: string; + + @Column({ type: "int", nullable: true }) + projectArea: number; + + @Column({ type: "int", nullable: true }) + abovegroundBiomassStock: number; + + @Column({ type: "int", nullable: true }) + belowgroundBiomassStock: number; + + @Column({ type: "int", nullable: true }) + soilOrganicCarbonStock: number; + + @Column({ type: "int", nullable: true }) + methaneEmissions: number; + + @Column({ type: "int", nullable: true }) + nitrousOxideEmissions: number; + + @Column({ type: "int", nullable: true }) + abovegroundBiomassEmissionsFactor: number; + + @Column({ type: "int", nullable: true }) + belowgroundBiomassEmissionsFactor: number; + + @Column({ type: "int", nullable: true }) + soilOrganicCarbonEmissionsFactor: number; +} diff --git a/shared/entities/users/user.entity.ts b/shared/entities/users/user.entity.ts index 72d7f7f2..16727524 100644 --- a/shared/entities/users/user.entity.ts +++ b/shared/entities/users/user.entity.ts @@ -8,7 +8,9 @@ import { } from "typeorm"; import { Exclude } from "class-transformer"; import { ROLES } from "@shared/entities/users/roles.enum"; -import { UserUploadCostInputs } from "@shared/entities/user-project-data.entity"; +import { UserUploadCostInputs } from "@shared/entities/users/user-upload-cost-inputs.entity"; +import { UserUploadRestorationInputs } from "@shared/entities/users/user-upload-restoration-inputs.entity"; +import { UserUploadConservationInputs } from "@shared/entities/users/user-upload-conservation-inputs.entity"; // TODO: For future reference: // https://github.com/typeorm/typeorm/issues/2897 @@ -46,5 +48,11 @@ export class User extends BaseEntity { createdAt: Date; @OneToMany("UserUploadCostInputs", "user") - uploadedData: UserUploadCostInputs[]; + uploadedCostInputs: UserUploadCostInputs[]; + + @OneToMany("UserUploadRestorationInputs", "user") + userUploadRestorationInputs: UserUploadRestorationInputs[]; + + @OneToMany("UserUploadConservationInputs", "user") + userUploadConservationInputs: UserUploadConservationInputs[]; } diff --git a/shared/lib/db-entities.ts b/shared/lib/db-entities.ts index 2f44e734..dbc802fc 100644 --- a/shared/lib/db-entities.ts +++ b/shared/lib/db-entities.ts @@ -30,7 +30,9 @@ import { BaseSize } from "@shared/entities/base-size.entity"; import { BaseIncrease } from "@shared/entities/base-increase.entity"; import { ModelAssumptions } from "@shared/entities/model-assumptions.entity"; import { CustomProject } from "@shared/entities/custom-project.entity"; -import { UserUploadCostInputs } from "@shared/entities/user-project-data.entity"; +import { UserUploadCostInputs } from "@shared/entities/users/user-upload-cost-inputs.entity"; +import { UserUploadRestorationInputs } from "@shared/entities/users/user-upload-restoration-inputs.entity"; +import { UserUploadConservationInputs } from "@shared/entities/users/user-upload-conservation-inputs.entity"; export const COMMON_DATABASE_ENTITIES = [ User, @@ -66,4 +68,6 @@ export const COMMON_DATABASE_ENTITIES = [ ModelAssumptions, CustomProject, UserUploadCostInputs, + UserUploadRestorationInputs, + UserUploadConservationInputs, ];