diff --git a/api/src/models/project-create.ts b/api/src/models/project-create.ts
index 0c8aea4e7f..266535426a 100644
--- a/api/src/models/project-create.ts
+++ b/api/src/models/project-create.ts
@@ -238,13 +238,13 @@ export class PostFundingSource {
* @class PostFundingData
*/
export class PostFundingData {
- funding_agencies: PostFundingSource[];
+ funding_sources: PostFundingSource[];
constructor(obj?: any) {
defaultLog.debug({ label: 'PostFundingData', message: 'params', obj });
- this.funding_agencies =
- (obj?.funding_agencies.length && obj.funding_agencies.map((item: any) => new PostFundingSource(item))) || [];
+ this.funding_sources =
+ (obj?.funding_sources.length && obj.funding_sources.map((item: any) => new PostFundingSource(item))) || [];
}
}
diff --git a/api/src/models/project-update.ts b/api/src/models/project-update.ts
index 64f0fb9d08..5192901507 100644
--- a/api/src/models/project-update.ts
+++ b/api/src/models/project-update.ts
@@ -273,3 +273,27 @@ export class GetProjectData {
this.revision_count = projectData?.revision_count ?? null;
}
}
+
+export class PutFundingSource {
+ id: number;
+ investment_action_category: number;
+ agency_project_id: string;
+ funding_amount: number;
+ start_date: string;
+ end_date: string;
+ revision_count: number;
+
+ constructor(obj?: any) {
+ defaultLog.debug({ label: 'PutFundingSource', message: 'params', obj });
+
+ const fundingSource = obj?.fundingSources?.length && obj.fundingSources[0];
+
+ this.id = fundingSource?.id || null;
+ this.investment_action_category = fundingSource?.investment_action_category || null;
+ this.agency_project_id = fundingSource?.agency_project_id || null;
+ this.funding_amount = fundingSource?.funding_amount || null;
+ this.start_date = fundingSource?.start_date || null;
+ this.end_date = fundingSource?.end_date || null;
+ this.revision_count = fundingSource?.revision_count || null;
+ }
+}
diff --git a/api/src/models/project-view-update.test.ts b/api/src/models/project-view-update.test.ts
index 39fc153f6b..5298e0f718 100644
--- a/api/src/models/project-view-update.test.ts
+++ b/api/src/models/project-view-update.test.ts
@@ -1,6 +1,6 @@
import { expect } from 'chai';
import { describe } from 'mocha';
-import { GetSpeciesData } from './project-view-update';
+import { GetSpeciesData, GetFundingData } from './project-view-update';
describe('GetSpeciesData', () => {
describe('No values provided', () => {
@@ -75,4 +75,45 @@ describe('GetSpeciesData', () => {
expect(data.ancillary_species).to.eql(['species 3']);
});
});
+
+ describe('GetFundingData', () => {
+ describe('No values provided', () => {
+ let fundingData: GetFundingData;
+
+ before(() => {
+ fundingData = new GetFundingData([]);
+ });
+
+ it('sets project funding sources', function () {
+ expect(fundingData.fundingSources).to.eql([]);
+ });
+ });
+
+ describe('All values provided', () => {
+ let fundingData: GetFundingData;
+
+ const fundingDataObj = [
+ {
+ id: 1,
+ agency_id: '123',
+ agency_name: 'Agency name',
+ agency_project_id: 'Agency123',
+ investment_action_category: 'Investment',
+ investment_action_category_name: 'Investment name',
+ start_date: '01/01/2020',
+ end_date: '01/01/2021',
+ funding_amount: 123,
+ revision_count: 0
+ }
+ ];
+
+ before(() => {
+ fundingData = new GetFundingData(fundingDataObj);
+ });
+
+ it('sets project funding sources', function () {
+ expect(fundingData.fundingSources).to.eql(fundingDataObj);
+ });
+ });
+ });
});
diff --git a/api/src/models/project-view-update.ts b/api/src/models/project-view-update.ts
index 0aff35cd3c..acb0a13b40 100644
--- a/api/src/models/project-view-update.ts
+++ b/api/src/models/project-view-update.ts
@@ -19,3 +19,46 @@ export class GetSpeciesData {
this.ancillary_species = (ancillary_species?.length && ancillary_species.map((item: any) => item.name)) || [];
}
}
+
+interface IGetFundingSource {
+ id: number;
+ agency_id: number;
+ investment_action_category: number;
+ investment_action_category_name: string;
+ agency_name: string;
+ funding_amount: number;
+ start_date: string;
+ end_date: string;
+ agency_project_id: string;
+ revision_count: number;
+}
+
+export class GetFundingData {
+ fundingSources: IGetFundingSource[];
+
+ constructor(fundingData?: any[]) {
+ defaultLog.debug({
+ label: 'GetFundingData',
+ message: 'params',
+ fundingData: fundingData
+ });
+
+ this.fundingSources =
+ (fundingData &&
+ fundingData.map((item: any) => {
+ return {
+ id: item.id,
+ agency_id: item.agency_id,
+ investment_action_category: item.investment_action_category,
+ investment_action_category_name: item.investment_action_category_name,
+ agency_name: item.agency_name,
+ funding_amount: item.funding_amount,
+ start_date: item.start_date,
+ end_date: item.end_date,
+ agency_project_id: item.agency_project_id,
+ revision_count: item.revision_count
+ };
+ })) ||
+ [];
+ }
+}
diff --git a/api/src/models/project-view.test.ts b/api/src/models/project-view.test.ts
index 05abfdc3ea..12d0984010 100644
--- a/api/src/models/project-view.test.ts
+++ b/api/src/models/project-view.test.ts
@@ -2,7 +2,6 @@ import { expect } from 'chai';
import { describe } from 'mocha';
import {
GetCoordinatorData,
- GetFundingData,
GetIUCNClassificationData,
GetLocationData,
GetObjectivesData,
@@ -201,43 +200,6 @@ describe('GetIUCNClassificationData', () => {
});
});
-describe('GetFundingData', () => {
- describe('No values provided', () => {
- let fundingData: GetFundingData;
-
- before(() => {
- fundingData = new GetFundingData([]);
- });
-
- it('sets funding agencies', function () {
- expect(fundingData.fundingAgencies).to.eql([]);
- });
- });
-
- describe('All values provided', () => {
- let fundingData: GetFundingData;
-
- const fundingDataObj = [
- {
- agency_id: '123',
- agency_name: 'Agency name',
- investment_action_category: 'investment',
- start_date: '01/01/2020',
- end_date: '01/01/2021',
- funding_amount: 123
- }
- ];
-
- before(() => {
- fundingData = new GetFundingData(fundingDataObj);
- });
-
- it('sets funding agencies', function () {
- expect(fundingData.fundingAgencies).to.eql(fundingDataObj);
- });
- });
-});
-
describe('GetObjectivesData', () => {
describe('No values provided', () => {
let projectObjectivesData: GetObjectivesData;
diff --git a/api/src/models/project-view.ts b/api/src/models/project-view.ts
index 6f3c0d4082..3c7f45cad2 100644
--- a/api/src/models/project-view.ts
+++ b/api/src/models/project-view.ts
@@ -140,47 +140,6 @@ export class GetIUCNClassificationData {
}
}
-interface IGetFundingSource {
- agency_id: string;
- investment_action_category: string;
- agency_name: string;
- funding_amount: number;
- start_date: string;
- end_date: string;
-}
-
-/**
- * Pre-processes GET /projects/{id} funding data
- *
- * @export
- * @class GetFundingData
- */
-export class GetFundingData {
- fundingAgencies: IGetFundingSource[];
-
- constructor(fundingData?: any[]) {
- defaultLog.debug({
- label: 'GetFundingData',
- message: 'params',
- fundingData: fundingData
- });
-
- this.fundingAgencies =
- (fundingData &&
- fundingData.map((item: any) => {
- return {
- agency_id: item.agency_id,
- investment_action_category: item.investment_action_category,
- agency_name: item.agency_name,
- funding_amount: item.funding_amount,
- start_date: item.start_date,
- end_date: item.end_date
- };
- })) ||
- [];
- }
-}
-
/**
* Pre-processes GET /projects/{id} partnerships data
*
diff --git a/api/src/openapi/schemas/project.ts b/api/src/openapi/schemas/project.ts
index 91f15531e2..c42e57a41b 100644
--- a/api/src/openapi/schemas/project.ts
+++ b/api/src/openapi/schemas/project.ts
@@ -149,7 +149,7 @@ export const projectCreatePostRequestObject = {
title: 'Project funding sources',
type: 'object',
properties: {
- funding_agencies: {
+ funding_sources: {
type: 'array',
items: {
title: 'Project funding agency',
diff --git a/api/src/paths/project.ts b/api/src/paths/project.ts
index 4c0fb68676..83f9d9a239 100644
--- a/api/src/paths/project.ts
+++ b/api/src/paths/project.ts
@@ -144,10 +144,10 @@ function createProject(): RequestHandler {
)
);
- // Handle funding agencies
+ // Handle funding sources
promises.push(
Promise.all(
- sanitizedProjectPostData.funding.funding_agencies.map((fundingSource: PostFundingSource) =>
+ sanitizedProjectPostData.funding.funding_sources.map((fundingSource: PostFundingSource) =>
insertFundingSource(fundingSource, projectId, connection)
)
)
diff --git a/api/src/paths/project/{projectId}/update.ts b/api/src/paths/project/{projectId}/update.ts
index db897e1a9a..56f861bcb5 100644
--- a/api/src/paths/project/{projectId}/update.ts
+++ b/api/src/paths/project/{projectId}/update.ts
@@ -17,9 +17,10 @@ import {
PutIUCNData,
PutSpeciesData,
IGetPutIUCN,
- GetLocationData
+ GetLocationData,
+ PutFundingSource
} from '../../../models/project-update';
-import { GetSpeciesData } from '../../../models/project-view-update';
+import { GetSpeciesData, GetFundingData } from '../../../models/project-view-update';
import {
projectIdResponseObject,
projectUpdateGetResponseObject,
@@ -31,6 +32,7 @@ import {
getIUCNActionClassificationByProjectSQL,
getObjectivesByProjectSQL,
getProjectByProjectSQL,
+ putProjectFundingSourceSQL,
putProjectSQL
} from '../../../queries/project/project-update-queries';
import {
@@ -41,7 +43,8 @@ import {
deleteAncillarySpeciesSQL,
deleteIndigenousPartnershipsSQL,
deleteStakeholderPartnershipsSQL,
- deleteRegionsSQL
+ deleteRegionsSQL,
+ deleteFundingSQL
} from '../../../queries/project/project-delete-queries';
import {
getStakeholderPartnershipsByProjectSQL,
@@ -149,7 +152,7 @@ export interface IGetProjectForUpdate {
location: any;
species: any;
iucn: GetIUCNClassificationData | null;
- funding: any;
+ funding: GetFundingData | null;
partnerships: GetPartnershipsData | null;
}
@@ -242,6 +245,13 @@ function getProjectForUpdate(): RequestHandler {
})
);
}
+ if (entities.includes(GET_ENTITIES.funding)) {
+ promises.push(
+ getProjectData(projectId, connection).then((value) => {
+ results.project = value;
+ })
+ );
+ }
await Promise.all(promises);
@@ -529,6 +539,10 @@ function updateProject(): RequestHandler {
promises.push(updateProjectSpeciesData(projectId, entities, connection));
}
+ if (entities?.funding) {
+ promises.push(updateProjectFundingData(projectId, entities, connection));
+ }
+
await Promise.all(promises);
await connection.commit();
@@ -776,3 +790,35 @@ export const updateProjectData = async (
await Promise.all([...insertActivityPromises, ...insertClimateInitiativesPromises]);
};
+
+export const updateProjectFundingData = async (
+ projectId: number,
+ entities: IUpdateProject,
+ connection: IDBConnection
+): Promise => {
+ const putFundingSource = entities?.funding && new PutFundingSource(entities.funding);
+
+ const sqlDeleteStatement = deleteFundingSQL(putFundingSource?.id);
+
+ if (!sqlDeleteStatement) {
+ throw new HTTP400('Failed to build SQL delete statement');
+ }
+
+ const deleteResult = await connection.query(sqlDeleteStatement.text, sqlDeleteStatement.values);
+
+ if (!deleteResult) {
+ throw new HTTP409('Failed to delete project funding source');
+ }
+
+ const sqlInsertStatement = putProjectFundingSourceSQL(putFundingSource, projectId);
+
+ if (!sqlInsertStatement) {
+ throw new HTTP400('Failed to build SQL insert statement');
+ }
+
+ const insertResult = await connection.query(sqlInsertStatement.text, sqlInsertStatement.values);
+
+ if (!insertResult) {
+ throw new HTTP409('Failed to put (insert) project funding source with incremented revision count');
+ }
+};
diff --git a/api/src/paths/project/{projectId}/view.ts b/api/src/paths/project/{projectId}/view.ts
index 196cdb082e..23a56f5037 100644
--- a/api/src/paths/project/{projectId}/view.ts
+++ b/api/src/paths/project/{projectId}/view.ts
@@ -5,17 +5,15 @@ import { getDBConnection } from '../../../database/db';
import { HTTP400 } from '../../../errors/CustomError';
import {
GetCoordinatorData,
- GetFundingData,
GetIUCNClassificationData,
GetObjectivesData,
GetPartnershipsData,
GetProjectData,
GetLocationData
} from '../../../models/project-view';
-import { GetSpeciesData } from '../../../models/project-view-update';
+import { GetSpeciesData, GetFundingData } from '../../../models/project-view-update';
import { projectViewGetResponseObject } from '../../../openapi/schemas/project';
import {
- getFundingSourceByProjectSQL,
getIndigenousPartnershipsByProjectSQL,
getIUCNActionClassificationByProjectSQL,
getProjectSQL
@@ -26,7 +24,8 @@ import {
getAncillarySpeciesByProjectSQL,
getLocationByProjectSQL,
getClimateInitiativesByProjectSQL,
- getActivitiesByProjectSQL
+ getActivitiesByProjectSQL,
+ getFundingSourceByProjectSQL
} from '../../../queries/project/project-view-update-queries';
import { getLogger } from '../../../utils/logger';
import { logRequest } from '../../../utils/path-utils';
diff --git a/api/src/queries/project/project-create-queries.test.ts b/api/src/queries/project/project-create-queries.test.ts
index 0b89f99136..b6d59936a0 100644
--- a/api/src/queries/project/project-create-queries.test.ts
+++ b/api/src/queries/project/project-create-queries.test.ts
@@ -225,6 +225,8 @@ describe('postProjectFundingSourceSQL', () => {
333
);
+ console.log(response?.values);
+
expect(response).to.not.be.null;
expect(response?.values).to.deep.include(333);
expect(response?.values).to.deep.include(222);
diff --git a/api/src/queries/project/project-create-queries.ts b/api/src/queries/project/project-create-queries.ts
index b2870797ab..ffa15fa7aa 100644
--- a/api/src/queries/project/project-create-queries.ts
+++ b/api/src/queries/project/project-create-queries.ts
@@ -216,7 +216,6 @@ export const postProjectFundingSourceSQL = (
return null;
}
- // TODO model is missing agency name
const sqlStatement: SQLStatement = SQL`
INSERT INTO project_funding_source (
p_id,
diff --git a/api/src/queries/project/project-delete-queries.test.ts b/api/src/queries/project/project-delete-queries.test.ts
index bf465418b6..0778ac7d4c 100644
--- a/api/src/queries/project/project-delete-queries.test.ts
+++ b/api/src/queries/project/project-delete-queries.test.ts
@@ -8,7 +8,8 @@ import {
deleteIndigenousPartnershipsSQL,
deleteIUCNSQL,
deleteRegionsSQL,
- deleteStakeholderPartnershipsSQL
+ deleteStakeholderPartnershipsSQL,
+ deleteFundingSQL
} from './project-delete-queries';
describe('deleteIUCNSQL', () => {
@@ -122,3 +123,17 @@ describe('deleteClimateInitiativesSQL', () => {
expect(response).to.not.be.null;
});
});
+
+describe('deleteFundingSQL', () => {
+ it('returns null response when null pfsId (project funding source) provided', () => {
+ const response = deleteFundingSQL((null as unknown) as number);
+
+ expect(response).to.be.null;
+ });
+
+ it('returns non null response when valid projectId provided', () => {
+ const response = deleteFundingSQL(1);
+
+ expect(response).to.not.be.null;
+ });
+});
diff --git a/api/src/queries/project/project-delete-queries.ts b/api/src/queries/project/project-delete-queries.ts
index 1f5a594375..6457db9fbd 100644
--- a/api/src/queries/project/project-delete-queries.ts
+++ b/api/src/queries/project/project-delete-queries.ts
@@ -274,3 +274,37 @@ export const deleteClimateInitiativesSQL = (projectId: number): SQLStatement | n
return sqlStatement;
};
+
+/**
+ * SQL query to delete the specific project funding source record.
+ *
+ * @param {pfsId} pfsId
+ * @returns {SQLStatement} sql query object
+ */
+export const deleteFundingSQL = (pfsId: number | undefined): SQLStatement | null => {
+ defaultLog.debug({
+ label: 'deleteFundingSQL',
+ message: 'params',
+ pfsId
+ });
+
+ if (!pfsId) {
+ return null;
+ }
+
+ const sqlStatement: SQLStatement = SQL`
+ DELETE
+ from project_funding_source
+ WHERE
+ id = ${pfsId};
+ `;
+
+ defaultLog.debug({
+ label: 'deleteFundingSQL',
+ message: 'sql',
+ 'sqlStatement.text': sqlStatement.text,
+ 'sqlStatement.values': sqlStatement.values
+ });
+
+ return sqlStatement;
+};
diff --git a/api/src/queries/project/project-update-queries.test.ts b/api/src/queries/project/project-update-queries.test.ts
index 709f7ad7c5..d3a10e9393 100644
--- a/api/src/queries/project/project-update-queries.test.ts
+++ b/api/src/queries/project/project-update-queries.test.ts
@@ -1,13 +1,20 @@
import { expect } from 'chai';
import { describe } from 'mocha';
-import { PutCoordinatorData, PutLocationData, PutObjectivesData, PutProjectData } from '../../models/project-update';
+import {
+ PutCoordinatorData,
+ PutLocationData,
+ PutObjectivesData,
+ PutProjectData,
+ PutFundingSource
+} from '../../models/project-update';
import {
getIndigenousPartnershipsByProjectSQL,
getCoordinatorByProjectSQL,
getIUCNActionClassificationByProjectSQL,
getObjectivesByProjectSQL,
getProjectByProjectSQL,
- putProjectSQL
+ putProjectSQL,
+ putProjectFundingSourceSQL
} from './project-update-queries';
describe('getIndigenousPartnershipsByProjectSQL', () => {
@@ -207,3 +214,47 @@ describe('getObjectivesByProjectSQL', () => {
expect(response).to.not.be.null;
});
});
+
+describe('putProjectFundingSourceSQL', () => {
+ describe('with invalid parameters', () => {
+ it('returns null when funding source is null', () => {
+ const response = putProjectFundingSourceSQL((null as unknown) as PutFundingSource, 1);
+
+ expect(response).to.be.null;
+ });
+
+ it('returns null when project id is null', () => {
+ const response = putProjectFundingSourceSQL(new PutFundingSource({}), (null as unknown) as number);
+
+ expect(response).to.be.null;
+ });
+ });
+
+ describe('with valid parameters', () => {
+ it('returns a SQLStatement when all fields are passed in as expected', () => {
+ const response = putProjectFundingSourceSQL(
+ new PutFundingSource({
+ fundingSources: [
+ {
+ investment_action_category: 222,
+ agency_project_id: 'funding source name',
+ funding_amount: 10000,
+ start_date: '2020-02-02',
+ end_date: '2020-03-02',
+ revision_count: 11
+ }
+ ]
+ }),
+ 1
+ );
+
+ expect(response).to.not.be.null;
+ expect(response?.values).to.deep.include(222);
+ expect(response?.values).to.deep.include('funding source name');
+ expect(response?.values).to.deep.include(10000);
+ expect(response?.values).to.deep.include('2020-02-02');
+ expect(response?.values).to.deep.include('2020-03-02');
+ expect(response?.values).to.deep.include(12);
+ });
+ });
+});
diff --git a/api/src/queries/project/project-update-queries.ts b/api/src/queries/project/project-update-queries.ts
index 6ab867d967..d4f0709d75 100644
--- a/api/src/queries/project/project-update-queries.ts
+++ b/api/src/queries/project/project-update-queries.ts
@@ -1,5 +1,11 @@
import { SQL, SQLStatement } from 'sql-template-strings';
-import { PutCoordinatorData, PutLocationData, PutObjectivesData, PutProjectData } from '../../models/project-update';
+import {
+ PutCoordinatorData,
+ PutLocationData,
+ PutObjectivesData,
+ PutProjectData,
+ PutFundingSource
+} from '../../models/project-update';
import { getLogger } from '../../utils/logger';
import { generateGeometryCollectionSQL } from '../generate-geometry-collection';
@@ -305,3 +311,51 @@ export const getObjectivesByProjectSQL = (projectId: number): SQLStatement | nul
return sqlStatement;
};
+
+/**
+ * SQL query to put (insert) a project funding source row with incremented revision count.
+ *
+ * @param {PutFundingSource} fundingSource
+ * @returns {SQLStatement} sql query object
+ */
+export const putProjectFundingSourceSQL = (
+ fundingSource: PutFundingSource | null,
+ projectId: number
+): SQLStatement | null => {
+ defaultLog.debug({ label: 'putProjectFundingSourceSQL', message: 'params', fundingSource, projectId });
+
+ if (!fundingSource || !projectId) {
+ return null;
+ }
+
+ const sqlStatement: SQLStatement = SQL`
+ INSERT INTO project_funding_source (
+ p_id,
+ iac_id,
+ funding_source_project_id,
+ funding_amount,
+ funding_start_date,
+ funding_end_date,
+ revision_count
+ ) VALUES (
+ ${projectId},
+ ${fundingSource.investment_action_category},
+ ${fundingSource.agency_project_id},
+ ${fundingSource.funding_amount},
+ ${fundingSource.start_date},
+ ${fundingSource.end_date},
+ ${fundingSource.revision_count + 1}
+ )
+ RETURNING
+ id;
+ `;
+
+ defaultLog.debug({
+ label: 'putProjectFundingSourceSQL',
+ message: 'sql',
+ 'sqlStatement.text': sqlStatement.text,
+ 'sqlStatement.values': sqlStatement.values
+ });
+
+ return sqlStatement;
+};
diff --git a/api/src/queries/project/project-view-queries.test.ts b/api/src/queries/project/project-view-queries.test.ts
index 066a2af8da..fe830eed58 100644
--- a/api/src/queries/project/project-view-queries.test.ts
+++ b/api/src/queries/project/project-view-queries.test.ts
@@ -1,7 +1,6 @@
import { expect } from 'chai';
import { describe } from 'mocha';
import {
- getFundingSourceByProjectSQL,
getIndigenousPartnershipsByProjectSQL,
getIUCNActionClassificationByProjectSQL,
getProjectListSQL,
@@ -49,20 +48,6 @@ describe('getIUCNActionClassificationByProjectSQL', () => {
});
});
-describe('getFundingSourceByProjectSQL', () => {
- it('returns null response when null projectId provided', () => {
- const response = getFundingSourceByProjectSQL((null as unknown) as number);
-
- expect(response).to.be.null;
- });
-
- it('returns non null response when valid projectId provided', () => {
- const response = getFundingSourceByProjectSQL(1);
-
- expect(response).to.not.be.null;
- });
-});
-
describe('getIndigenousPartnershipsByProjectSQL', () => {
it('Null projectId', () => {
const response = getIndigenousPartnershipsByProjectSQL((null as unknown) as number);
diff --git a/api/src/queries/project/project-view-queries.ts b/api/src/queries/project/project-view-queries.ts
index 6c37ab3858..8048b35b4d 100644
--- a/api/src/queries/project/project-view-queries.ts
+++ b/api/src/queries/project/project-view-queries.ts
@@ -150,58 +150,6 @@ export const getIUCNActionClassificationByProjectSQL = (projectId: number): SQLS
return sqlStatement;
};
-/**
- * SQL query to get funding source data
- *
- * @param {number} projectId
- * @returns {SQLStatement} sql query object
- */
-export const getFundingSourceByProjectSQL = (projectId: number): SQLStatement | null => {
- defaultLog.debug({ label: 'getFundingSourceByProjectSQL', message: 'params', projectId });
-
- if (!projectId) {
- return null;
- }
-
- const sqlStatement = SQL`
- SELECT
- pfs.funding_source_project_id as agency_id,
- pfs.funding_amount::numeric::int,
- pfs.funding_start_date as start_date,
- pfs.funding_end_date as end_date,
- iac.name as investment_action_category,
- fs.name as agency_name
- FROM
- project_funding_source as pfs
- LEFT OUTER JOIN
- investment_action_category as iac
- ON
- pfs.iac_id = iac.id
- LEFT OUTER JOIN
- funding_source as fs
- ON
- iac.fs_id = fs.id
- WHERE
- pfs.p_id = ${projectId}
- GROUP BY
- pfs.funding_source_project_id,
- pfs.funding_amount,
- pfs.funding_start_date,
- pfs.funding_end_date,
- iac.name,
- fs.name
- `;
-
- defaultLog.debug({
- label: 'getFundingSourceByProjectSQL',
- message: 'sql',
- 'sqlStatement.text': sqlStatement.text,
- 'sqlStatement.values': sqlStatement.values
- });
-
- return sqlStatement;
-};
-
/**
* SQL query to get project indigenous partnerships.
* @param {number} projectId
diff --git a/api/src/queries/project/project-view-update-queries.test.ts b/api/src/queries/project/project-view-update-queries.test.ts
index 7cd438687d..cdbe7995cc 100644
--- a/api/src/queries/project/project-view-update-queries.test.ts
+++ b/api/src/queries/project/project-view-update-queries.test.ts
@@ -6,7 +6,8 @@ import {
getAncillarySpeciesByProjectSQL,
getActivitiesByProjectSQL,
getClimateInitiativesByProjectSQL,
- getLocationByProjectSQL
+ getLocationByProjectSQL,
+ getFundingSourceByProjectSQL
} from './project-view-update-queries';
describe('getLocationByProjectSQL', () => {
@@ -92,3 +93,17 @@ describe('getClimateInitiativesByProjectSQL', () => {
expect(response).to.not.be.null;
});
});
+
+describe('getFundingSourceByProjectSQL', () => {
+ it('returns null response when null projectId provided', () => {
+ const response = getFundingSourceByProjectSQL((null as unknown) as number);
+
+ expect(response).to.be.null;
+ });
+
+ it('returns non null response when valid projectId provided', () => {
+ const response = getFundingSourceByProjectSQL(1);
+
+ expect(response).to.not.be.null;
+ });
+});
diff --git a/api/src/queries/project/project-view-update-queries.ts b/api/src/queries/project/project-view-update-queries.ts
index ce9eb765dd..45f0aca9b4 100644
--- a/api/src/queries/project/project-view-update-queries.ts
+++ b/api/src/queries/project/project-view-update-queries.ts
@@ -203,3 +203,63 @@ export const getClimateInitiativesByProjectSQL = (projectId: number): SQLStateme
return sqlStatement;
};
+
+/**
+ * SQL query to get funding source data
+ *
+ * @param {number} projectId
+ * @returns {SQLStatement} sql query object
+ */
+export const getFundingSourceByProjectSQL = (projectId: number): SQLStatement | null => {
+ defaultLog.debug({ label: 'getFundingSourceByProjectSQL', message: 'params', projectId });
+
+ if (!projectId) {
+ return null;
+ }
+
+ const sqlStatement = SQL`
+ SELECT
+ pfs.id as id,
+ fs.id as agency_id,
+ pfs.funding_amount::numeric::int,
+ pfs.funding_start_date as start_date,
+ pfs.funding_end_date as end_date,
+ iac.id as investment_action_category,
+ iac.name as investment_action_category_name,
+ fs.name as agency_name,
+ pfs.funding_source_project_id as agency_project_id,
+ pfs.revision_count as revision_count
+ FROM
+ project_funding_source as pfs
+ LEFT OUTER JOIN
+ investment_action_category as iac
+ ON
+ pfs.iac_id = iac.id
+ LEFT OUTER JOIN
+ funding_source as fs
+ ON
+ iac.fs_id = fs.id
+ WHERE
+ pfs.p_id = ${projectId}
+ GROUP BY
+ pfs.id,
+ fs.id,
+ pfs.funding_source_project_id,
+ pfs.funding_amount,
+ pfs.funding_start_date,
+ pfs.funding_end_date,
+ iac.id,
+ iac.name,
+ fs.name,
+ pfs.revision_count
+ `;
+
+ defaultLog.debug({
+ label: 'getFundingSourceByProjectSQL',
+ message: 'sql',
+ 'sqlStatement.text': sqlStatement.text,
+ 'sqlStatement.values': sqlStatement.values
+ });
+
+ return sqlStatement;
+};
diff --git a/app/src/constants/i18n.ts b/app/src/constants/i18n.ts
index 3bac6dbf3d..bf9d470c4a 100644
--- a/app/src/constants/i18n.ts
+++ b/app/src/constants/i18n.ts
@@ -62,3 +62,17 @@ export const EditSpeciesI18N = {
editErrorText:
'An error has occurred while attempting to edit your species, please try again. If the error persists, please contact your system administrator.'
};
+
+export const AddFundingI18N = {
+ addTitle: 'Add Funding Source',
+ addErrorTitle: 'Error Adding Funding Source',
+ addErrorText:
+ 'An error has occurred while attempting to add your funding source details, please try again. If the error persists, please contact your system administrator.'
+};
+
+export const EditFundingI18N = {
+ editTitle: 'Edit Funding Source',
+ editErrorTitle: 'Error Editing Funding Source',
+ editErrorText:
+ 'An error has occurred while attempting to edit your funding source details, please try again. If the error persists, please contact your system administrator.'
+};
diff --git a/app/src/features/projects/components/ProjectDetailsForm.test.tsx b/app/src/features/projects/components/ProjectDetailsForm.test.tsx
index 763729db66..1038f2f2bb 100644
--- a/app/src/features/projects/components/ProjectDetailsForm.test.tsx
+++ b/app/src/features/projects/components/ProjectDetailsForm.test.tsx
@@ -10,15 +10,15 @@ import ProjectDetailsForm, {
const project_type: IMultiAutocompleteFieldOption[] = [
{
- value: 'type_1',
+ value: 1,
label: 'type 1'
},
{
- value: 'type_2',
+ value: 2,
label: 'type 2'
},
{
- value: 'type_3',
+ value: 3,
label: 'type 3'
}
];
@@ -78,7 +78,7 @@ describe('ProjectDetailsForm', () => {
it('renders correctly with existing details values', () => {
const existingFormValues: IProjectDetailsForm = {
project_name: 'name 1',
- project_type: 'type_1',
+ project_type: 2,
project_activities: [2, 3],
climate_change_initiatives: [1, 2],
start_date: '2021-03-14',
diff --git a/app/src/features/projects/components/ProjectFundingForm.test.tsx b/app/src/features/projects/components/ProjectFundingForm.test.tsx
index 05d2eb794d..f2fd5b5618 100644
--- a/app/src/features/projects/components/ProjectFundingForm.test.tsx
+++ b/app/src/features/projects/components/ProjectFundingForm.test.tsx
@@ -8,6 +8,8 @@ import ProjectFundingForm, {
ProjectFundingFormInitialValues,
ProjectFundingFormYupSchema
} from './ProjectFundingForm';
+import { codes } from 'test-helpers/code-helpers';
+import ProjectStepComponents from 'utils/ProjectStepComponents';
const funding_sources: IMultiAutocompleteFieldOption[] = [
{
@@ -65,14 +67,17 @@ describe('ProjectFundingForm', () => {
it('renders correctly with existing funding values', () => {
const existingFormValues: IProjectFundingForm = {
- funding_agencies: [
+ funding_sources: [
{
+ id: 11,
agency_id: 1,
investment_action_category: 1,
+ investment_action_category_name: 'Action 23',
agency_project_id: '111',
funding_amount: 222,
start_date: '2021-03-14',
- end_date: '2021-04-14'
+ end_date: '2021-04-14',
+ revision_count: 23
}
]
};
@@ -84,12 +89,7 @@ describe('ProjectFundingForm', () => {
validateOnBlur={true}
validateOnChange={false}
onSubmit={async () => {}}>
- {() => (
-
- )}
+ {() => }
);
diff --git a/app/src/features/projects/components/ProjectFundingForm.tsx b/app/src/features/projects/components/ProjectFundingForm.tsx
index 3c806a2257..650f641996 100644
--- a/app/src/features/projects/components/ProjectFundingForm.tsx
+++ b/app/src/features/projects/components/ProjectFundingForm.tsx
@@ -7,18 +7,21 @@ import Icon from '@mdi/react';
import { mdiPlus, mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js';
import React, { useState } from 'react';
import { getFormattedDateRangeString, getFormattedAmount } from 'utils/Utils';
+import EditDialog from 'components/dialog/EditDialog';
import yup from 'utils/YupSchema';
import ProjectFundingItemForm, {
IProjectFundingFormArrayItem,
- ProjectFundingFormArrayItemInitialValues
+ ProjectFundingFormArrayItemInitialValues,
+ ProjectFundingFormArrayItemYupSchema
} from './ProjectFundingItemForm';
+import { AddFundingI18N } from 'constants/i18n';
export interface IProjectFundingForm {
- funding_agencies: IProjectFundingFormArrayItem[];
+ funding_sources: IProjectFundingFormArrayItem[];
}
export const ProjectFundingFormInitialValues: IProjectFundingForm = {
- funding_agencies: []
+ funding_sources: []
};
export const ProjectFundingFormYupSchema = yup.object().shape({});
@@ -68,10 +71,11 @@ const useStyles = makeStyles((theme) => ({
*/
const ProjectFundingForm: React.FC = (props) => {
const classes = useStyles();
+
const formikProps = useFormikContext();
const { values } = formikProps;
- // Tracks information about the current funding source item that is being added/edited
+ //Tracks information about the current funding source item that is being added/edited
const [currentProjectFundingFormArrayItem, setCurrentProjectFundingFormArrayItem] = useState({
index: 0,
values: ProjectFundingFormArrayItemInitialValues
@@ -83,7 +87,7 @@ const ProjectFundingForm: React.FC = (props) => {
);
};
diff --git a/app/src/features/projects/components/__snapshots__/ProjectDetailsForm.test.tsx.snap b/app/src/features/projects/components/__snapshots__/ProjectDetailsForm.test.tsx.snap
index c3fde93747..cb72e5a6da 100644
--- a/app/src/features/projects/components/__snapshots__/ProjectDetailsForm.test.tsx.snap
+++ b/app/src/features/projects/components/__snapshots__/ProjectDetailsForm.test.tsx.snap
@@ -516,7 +516,7 @@ exports[`ProjectDetailsForm renders correctly with existing details values 1`] =
role="button"
tabindex="0"
>
- type 1
+ type 2
-
-
-
-
-
+
+
+
-
+
+
+ End Date *
+
+
+
-
-
+
+
+
+
+
+
+
+
+`;
+
+exports[`ProjectFundingItemForm renders correctly with agency 2 1`] = `
+
+
-
-
-
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
+
+ End Date *
+
+
+
-
-
+
+
+
+
+
+
+
+
+`;
+
+exports[`ProjectFundingItemForm renders correctly with any agency other than 1 or 2 1`] = `
+
+
-
-
-
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
+
+ End Date *
+
+
+
-
-
+
+
+
+
+
+
+
+
+`;
+
+exports[`ProjectFundingItemForm renders correctly with default empty values 1`] = `
+
+