Skip to content

Commit

Permalink
[TM-1652] Add new fields to Project Reports
Browse files Browse the repository at this point in the history
  • Loading branch information
roguenet committed Jan 22, 2025
1 parent 91fe94b commit 430faa0
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ describe("AirtableEntity", () => {
describe("ProjectReportEntity", () => {
let projectUuids: Record<number, string>;
let reports: ProjectReport[];
let calculatedValues: Record<string, Record<string, string | number>>;

beforeAll(async () => {
await ProjectReport.truncate();
Expand All @@ -513,8 +514,50 @@ describe("AirtableEntity", () => {
}
allReports.push(await ProjectReportFactory.create({ projectId: null }));

const ppcReport = await ProjectReportFactory.create({
projectId: faker.helpers.arrayElement(projectIds),
frameworkKey: "ppc"
});
allReports.push(ppcReport);
const ppcSeedlings = (
await TreeSpeciesFactory.forProjectReportTreePlanted.createMany(3, { speciesableId: ppcReport.id })
).reduce((total, { amount }) => total + amount, 0);
// make sure hidden is ignored
await TreeSpeciesFactory.forProjectReportTreePlanted.create({ speciesableId: ppcReport.id, hidden: true });

// TODO this might start causing problems when Task is implemented in this codebase and we have a factory
// that's generating real records
const terrafundReport = await ProjectReportFactory.create({
projectId: faker.helpers.arrayElement(projectIds),
frameworkKey: "terrafund",
taskId: 123
});
allReports.push(terrafundReport);
const terrafundSeedlings = (
await NurseryReportFactory.createMany(2, {
taskId: terrafundReport.taskId,
seedlingsYoungTrees: faker.number.int({ min: 10, max: 100 }),
status: "approved"
})
).reduce((total, { seedlingsYoungTrees }) => total + seedlingsYoungTrees, 0);
// make sure non-approved reports are ignored
await NurseryReportFactory.create({
taskId: terrafundReport.taskId,
seedlingsYoungTrees: faker.number.int({ min: 10, max: 100 }),
status: "due"
});

await allReports[6].destroy();
reports = allReports.filter(report => !report.isSoftDeleted());

calculatedValues = {
[ppcReport.uuid]: {
totalSeedlingsGrown: ppcSeedlings
},
[terrafundReport.uuid]: {
totalSeedlingsGrown: terrafundSeedlings
}
};
});

it("sends all records to airtable", async () => {
Expand All @@ -523,7 +566,8 @@ describe("AirtableEntity", () => {
uuid,
projectUuid: projectUuids[projectId],
status,
dueAt
dueAt,
totalSeedlingsGrown: calculatedValues[uuid]?.totalSeedlingsGrown ?? 0
}
}));
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { Project, ProjectReport } from "@terramatch-microservices/database/entities";
import { NurseryReport, Project, ProjectReport, TreeSpecies } from "@terramatch-microservices/database/entities";
import { AirtableEntity, associatedValueColumn, ColumnMapping, commonEntityColumns } from "./airtable-entity";
import { groupBy, uniq } from "lodash";

type ProjectReportAssociations = {
projectUuid?: string;
associatedNurseryReports: NurseryReport[];
trees: TreeSpecies[];
};

const COLUMNS: ColumnMapping<ProjectReport, ProjectReportAssociations>[] = [
Expand Down Expand Up @@ -63,26 +66,69 @@ const COLUMNS: ColumnMapping<ProjectReport, ProjectReportAssociations>[] = [
"localEngagementDescription",
"equitableOpportunities",
"indirectBeneficiaries",
"indirectBeneficiariesDescription"
"indirectBeneficiariesDescription",
"resilienceProgress",
"localGovernance",
"adaptiveManagement",
"scalabilityReplicability",
"convergenceJobsDescription",
"convergenceSchemes",
"volunteerScstobc",
"beneficiariesScstobc",
"beneficiariesScstobcFarmers",
"communityPartnersAssetsDescription",
"peopleKnowledgeSkillsIncreased",
{
airtableColumn: "totalSeedlingsGrown",
dbColumn: ["frameworkKey", "taskId"],
valueMap: async ({ frameworkKey }, { trees, associatedNurseryReports }) =>
frameworkKey === "ppc"
? trees.reduce((total, { amount }) => total + amount, 0)
: frameworkKey === "terrafund"
? associatedNurseryReports.reduce((total, { seedlingsYoungTrees }) => total + seedlingsYoungTrees, 0)
: 0
},
"technicalNarrative",
"publicNarrative",
"totalUniqueRestorationPartners"
];

export class ProjectReportEntity extends AirtableEntity<ProjectReport, ProjectReportAssociations> {
readonly TABLE_NAME = "Project Reports";
readonly COLUMNS = COLUMNS;
readonly MODEL = ProjectReport;
readonly SUPPORTS_UPDATED_SINCE = false;

protected async loadAssociations(projectReports: ProjectReport[]) {
const projectIds = projectReports.map(({ projectId }) => projectId);
const reportIds = projectReports.map(({ id }) => id);
const projectIds = uniq(projectReports.map(({ projectId }) => projectId));
const projects = await Project.findAll({
where: { id: projectIds },
attributes: ["id", "uuid"]
});
const taskIds = projectReports.map(({ taskId }) => taskId);
const nurseryReportsByTaskId = groupBy(
await NurseryReport.findAll({
where: { taskId: taskIds, status: NurseryReport.APPROVED_STATUSES },
attributes: ["id", "taskId", "seedlingsYoungTrees"]
}),
"taskId"
);
const treesByReportId = groupBy(
await TreeSpecies.findAll({
where: { speciesableType: ProjectReport.LARAVEL_TYPE, speciesableId: reportIds, hidden: false },
attributes: ["id", "speciesableId", "amount"]
}),
"speciesableId"
);

return projectReports.reduce(
(associations, { id, projectId }) => ({
(associations, { id, projectId, taskId }) => ({
...associations,
[id]: {
projectUuid: projects.find(({ id }) => id === projectId)?.uuid
projectUuid: projects.find(({ id }) => id === projectId)?.uuid,
associatedNurseryReports: nurseryReportsByTaskId[taskId] ?? [],
trees: treesByReportId[id] ?? []
}
}),
{} as Record<number, ProjectReportAssociations>
Expand Down
11 changes: 11 additions & 0 deletions libs/database/src/lib/entities/nursery-report.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import { BIGINT, DATE, INTEGER, STRING, UUID } from "sequelize";
import { Nursery } from "./nursery.entity";
import { TreeSpecies } from "./tree-species.entity";
import { ReportStatus, UpdateRequestStatus } from "../constants/status";
import { FrameworkKey } from "../constants/framework";

// Incomplete stub
@Table({ tableName: "v2_nursery_reports", underscored: true, paranoid: true })
export class NurseryReport extends Model<NurseryReport> {
static readonly TREE_ASSOCIATIONS = ["seedlings"];
static readonly APPROVED_STATUSES = ["approved"];
static readonly PARENT_ID = "nurseryId";
static readonly LARAVEL_TYPE = "App\\Models\\V2\\Nurseries\\NurseryReport";

Expand All @@ -31,13 +33,22 @@ export class NurseryReport extends Model<NurseryReport> {
@Column(UUID)
uuid: string;

@AllowNull
@Column(STRING)
frameworkKey: FrameworkKey | null;

@ForeignKey(() => Nursery)
@Column(BIGINT.UNSIGNED)
nurseryId: number;

@BelongsTo(() => Nursery)
nursery: Nursery | null;

// TODO foreign key for task
@AllowNull
@Column(BIGINT.UNSIGNED)
taskId: number;

@Column(STRING)
status: ReportStatus;

Expand Down
66 changes: 66 additions & 0 deletions libs/database/src/lib/entities/project-report.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { BIGINT, DATE, INTEGER, STRING, TEXT, TINYINT, UUID } from "sequelize";
import { TreeSpecies } from "./tree-species.entity";
import { Project } from "./project.entity";
import { FrameworkKey } from "../constants/framework";

// Incomplete stub
@Table({ tableName: "v2_project_reports", underscored: true, paranoid: true })
Expand Down Expand Up @@ -63,13 +64,22 @@ export class ProjectReport extends Model<ProjectReport> {
@Column(UUID)
uuid: string;

@AllowNull
@Column(STRING)
frameworkKey: FrameworkKey | null;

@ForeignKey(() => Project)
@Column(BIGINT.UNSIGNED)
projectId: number;

@BelongsTo(() => Project)
project: Project | null;

// TODO foreign key for task
@AllowNull
@Column(BIGINT.UNSIGNED)
taskId: number;

@Column(STRING)
status: string;

Expand Down Expand Up @@ -294,6 +304,62 @@ export class ProjectReport extends Model<ProjectReport> {
@Column(TEXT)
equitableOpportunities: string | null;

@AllowNull
@Column(TEXT)
resilienceProgress: string | null;

@AllowNull
@Column(TEXT)
localGovernance: string | null;

@AllowNull
@Column(TEXT)
adaptiveManagement: string | null;

@AllowNull
@Column(TEXT)
scalabilityReplicability: string | null;

@AllowNull
@Column(TEXT)
convergenceJobsDescription: string | null;

@AllowNull
@Column(TEXT)
convergenceSchemes: string | null;

@AllowNull
@Column(INTEGER.UNSIGNED)
volunteerScstobc: number | null;

@AllowNull
@Column(INTEGER.UNSIGNED)
beneficiariesScstobc: number | null;

@AllowNull
@Column(INTEGER.UNSIGNED)
beneficiariesScstobcFarmers: number | null;

@AllowNull
@Column(TEXT)
communityPartnersAssetsDescription: string | null;

@AllowNull
@Column(INTEGER)
peopleKnowledgeSkillsIncreased: number | null;

@AllowNull
@Column(TEXT)
technicalNarrative: string | null;

@AllowNull
@Column(TEXT)
publicNarrative: string | null;

@AllowNull
@Column(INTEGER.UNSIGNED)
totalUniqueRestorationPartners: number | null;

@HasMany(() => TreeSpecies, {
foreignKey: "speciesableId",
constraints: false,
Expand Down
10 changes: 10 additions & 0 deletions libs/database/src/lib/entities/site-report.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { BIGINT, DATE, INTEGER, STRING, TEXT, UUID } from "sequelize";
import { TreeSpecies } from "./tree-species.entity";
import { Site } from "./site.entity";
import { Seeding } from "./seeding.entity";
import { FrameworkKey } from "../constants/framework";

// A quick stub for the research endpoints
@Table({ tableName: "v2_site_reports", underscored: true, paranoid: true })
Expand Down Expand Up @@ -44,13 +45,22 @@ export class SiteReport extends Model<SiteReport> {
@Column(UUID)
uuid: string;

@AllowNull
@Column(STRING)
frameworkKey: FrameworkKey | null;

@ForeignKey(() => Site)
@Column(BIGINT.UNSIGNED)
siteId: number;

@BelongsTo(() => Site)
site: Site | null;

// TODO foreign key for task
@AllowNull
@Column(BIGINT.UNSIGNED)
taskId: number;

@Column(STRING)
status: string;

Expand Down

0 comments on commit 430faa0

Please sign in to comment.