diff --git a/api/README.md b/api/README.md index e0a7c303ce..ee143762c1 100644 --- a/api/README.md +++ b/api/README.md @@ -4,9 +4,8 @@ | Technology | Version | Website | Description | | ---------- | ------- | ------------------------------------ | -------------------- | -| node | 10.x.x | https://nodejs.org/en/ | JavaScript Runtime | +| node | 14.x.x | https://nodejs.org/en/ | JavaScript Runtime | | npm | 6.x.x | https://www.npmjs.com/ | Node Package Manager | -| PostgreSQL | 9.6 | https://www.postgresql.org/download/ | PSQL database |
@@ -14,7 +13,9 @@ The root API schema is defined in `./src/openapi/api.ts`. -If this project is running in docker you can view the api docs at: `http://localhost:6100/api/api-docs/`. +If this project is running in docker you can view the beautified api docs at: `http://localhost:6100/api-docs/`. + +- The raw api-docs are available at: `http://localhost:6100/raw-api-docs/`. This project uses npm package `express-openapi` via `./app.ts` to automatically generate the express server and its routes, based on the contents of the `./src/openapi/api.ts` and the `./src/path/` content. diff --git a/api/src/models/survey-create.test.ts b/api/src/models/survey-create.test.ts index 8b28733e5a..5adfcd7e2a 100644 --- a/api/src/models/survey-create.test.ts +++ b/api/src/models/survey-create.test.ts @@ -14,10 +14,6 @@ describe('PostSurveyObject', () => { expect(data.survey_name).to.equal(null); }); - it('sets survey_purpose', () => { - expect(data.survey_purpose).to.equal(null); - }); - it('sets focal_species', () => { expect(data.focal_species).to.eql([]); }); @@ -26,10 +22,6 @@ describe('PostSurveyObject', () => { expect(data.ancillary_species).to.eql([]); }); - it('sets common survey methodology id', () => { - expect(data.common_survey_methodology_id).to.equal(null); - }); - it('sets start_date', () => { expect(data.start_date).to.equal(null); }); @@ -116,10 +108,6 @@ describe('PostSurveyObject', () => { expect(data.survey_name).to.equal(surveyObj.survey_name); }); - it('sets survey_purpose', () => { - expect(data.survey_purpose).to.equal(surveyObj.survey_purpose); - }); - it('sets focal_species', () => { expect(data.focal_species).to.eql(surveyObj.focal_species); }); @@ -128,10 +116,6 @@ describe('PostSurveyObject', () => { expect(data.ancillary_species).to.eql(surveyObj.ancillary_species); }); - it('sets common_survey_methodology_id', () => { - expect(data.common_survey_methodology_id).to.eql(surveyObj.common_survey_methodology_id); - }); - it('sets start_date', () => { expect(data.start_date).to.equal(surveyObj.start_date); }); @@ -205,10 +189,6 @@ describe('PostSurveyObject', () => { expect(data.survey_name).to.equal(surveyObj.survey_name); }); - it('sets survey_purpose', () => { - expect(data.survey_purpose).to.equal(surveyObj.survey_purpose); - }); - it('sets focal_species', () => { expect(data.focal_species).to.eql(surveyObj.focal_species); }); @@ -217,10 +197,6 @@ describe('PostSurveyObject', () => { expect(data.ancillary_species).to.eql(surveyObj.ancillary_species); }); - it('sets common_survey_methodology_id', () => { - expect(data.common_survey_methodology_id).to.eql(surveyObj.common_survey_methodology_id); - }); - it('sets start_date', () => { expect(data.start_date).to.equal(surveyObj.start_date); }); diff --git a/api/src/models/survey-create.ts b/api/src/models/survey-create.ts index 0b30d644ae..5638a4d80d 100644 --- a/api/src/models/survey-create.ts +++ b/api/src/models/survey-create.ts @@ -17,12 +17,15 @@ export class PostSurveyObject { sedis_procedures_accepted: boolean; focal_species: number[]; ancillary_species: number[]; - common_survey_methodology_id: number; + field_method_id: number; + ecological_season_id: number; + vantage_code_ids: number[]; start_date: string; end_date: string; survey_area_name: string; survey_data_proprietary: boolean; - survey_purpose: string; + intended_outcome_id: number; + additional_details: string; geometry: Feature[]; permit_number: string; permit_type: string; @@ -48,7 +51,7 @@ export class PostSurveyObject { this.sedis_procedures_accepted = obj?.sedis_procedures_accepted === 'true' || false; this.focal_species = (obj?.focal_species?.length && obj.focal_species) || []; this.ancillary_species = (obj?.ancillary_species?.length && obj.ancillary_species) || []; - this.common_survey_methodology_id = obj?.common_survey_methodology_id || null; + this.field_method_id = obj?.field_method_id || null; this.start_date = obj?.start_date || null; this.survey_area_name = obj?.survey_area_name || null; this.permit_number = obj?.permit_number || null; @@ -56,7 +59,10 @@ export class PostSurveyObject { this.funding_sources = (obj?.funding_sources?.length && obj.funding_sources) || []; this.survey_data_proprietary = obj?.survey_data_proprietary === 'true' || false; this.survey_name = obj?.survey_name || null; - this.survey_purpose = obj?.survey_purpose || null; + this.intended_outcome_id = obj?.intended_outcome_id || null; + this.ecological_season_id = obj?.ecological_season_id || null; + this.additional_details = obj?.additional_details || null; + this.vantage_code_ids = (obj?.vantage_code_ids?.length && obj.vantage_code_ids) || []; this.geometry = (obj?.geometry?.length && obj.geometry) || []; this.survey_proprietor = (obj && obj.survey_data_proprietary === 'true' && new PostSurveyProprietorData(obj)) || undefined; diff --git a/api/src/models/survey-update.test.ts b/api/src/models/survey-update.test.ts index 355d345dd4..d959730136 100644 --- a/api/src/models/survey-update.test.ts +++ b/api/src/models/survey-update.test.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; import { describe } from 'mocha'; -import { GetUpdateSurveyDetailsData, PutSurveyDetailsData } from './survey-update'; +import { GetUpdateSurveyDetailsData, PutSurveyDetailsData, PutSurveyPurposeAndMethodologyData } from './survey-update'; describe('GetUpdateSurveyDetailsData', () => { describe('No values provided', () => { @@ -14,10 +14,6 @@ describe('GetUpdateSurveyDetailsData', () => { expect(data.survey_name).to.equal(''); }); - it('sets survey_purpose', () => { - expect(data.survey_purpose).to.equal(''); - }); - it('sets focal_species', () => { expect(data.focal_species).to.eql([]); }); @@ -26,10 +22,6 @@ describe('GetUpdateSurveyDetailsData', () => { expect(data.ancillary_species).to.eql([]); }); - it('sets common survey methodology id', () => { - expect(data.common_survey_methodology_id).to.equal(null); - }); - it('sets start_date', () => { expect(data.start_date).to.equal(''); }); @@ -107,10 +99,6 @@ describe('GetUpdateSurveyDetailsData', () => { expect(data.survey_name).to.equal(surveyData.name); }); - it('sets survey_purpose', () => { - expect(data.survey_purpose).to.equal(surveyData.objectives); - }); - it('sets focal_species', () => { expect(data.focal_species).to.eql(surveyData.focal_species); }); @@ -119,10 +107,6 @@ describe('GetUpdateSurveyDetailsData', () => { expect(data.ancillary_species).to.eql(surveyData.ancillary_species); }); - it('sets common survey methodology id', () => { - expect(data.common_survey_methodology_id).to.equal(surveyData.common_survey_methodology_id); - }); - it('sets start_date', () => { expect(data.start_date).to.equal(surveyData.start_date); }); @@ -204,10 +188,6 @@ describe('GetUpdateSurveyDetailsData', () => { expect(data.survey_name).to.equal(surveyData.name); }); - it('sets survey_purpose', () => { - expect(data.survey_purpose).to.equal(surveyData.objectives); - }); - it('sets focal_species', () => { expect(data.focal_species).to.eql(surveyData.focal_species); }); @@ -216,10 +196,6 @@ describe('GetUpdateSurveyDetailsData', () => { expect(data.ancillary_species).to.eql(surveyData.ancillary_species); }); - it('sets common survey methodology id', () => { - expect(data.common_survey_methodology_id).to.equal(surveyData.common_survey_methodology_id); - }); - it('sets start_date', () => { expect(data.start_date).to.equal(surveyData.start_date); }); @@ -274,10 +250,6 @@ describe('PutSurveyData', () => { expect(data.name).to.equal(null); }); - it('sets objectives', () => { - expect(data.objectives).to.equal(null); - }); - it('sets focal_species', () => { expect(data.focal_species).to.eql([]); }); @@ -286,10 +258,6 @@ describe('PutSurveyData', () => { expect(data.ancillary_species).to.eql([]); }); - it('sets common_survey_methodology_id', () => { - expect(data.common_survey_methodology_id).to.equal(null); - }); - it('sets geometry', () => { expect(data.geometry).to.equal(null); }); @@ -363,10 +331,6 @@ describe('PutSurveyData', () => { expect(data.name).to.equal(surveyData.survey_details.survey_name); }); - it('sets objectives', () => { - expect(data.objectives).to.equal(surveyData.survey_details.survey_purpose); - }); - it('sets focal_species', () => { expect(data.focal_species).to.eql(surveyData.survey_details.focal_species); }); @@ -375,10 +339,6 @@ describe('PutSurveyData', () => { expect(data.ancillary_species).to.eql(surveyData.survey_details.ancillary_species); }); - it('sets common_survey_methodology_id', () => { - expect(data.common_survey_methodology_id).to.equal(surveyData.survey_details.common_survey_methodology_id); - }); - it('sets start_date', () => { expect(data.start_date).to.equal(surveyData.survey_details.start_date); }); @@ -408,3 +368,87 @@ describe('PutSurveyData', () => { }); }); }); + +describe('PutSurveyPurposeAndMethodologyData', () => { + describe('No values provided', () => { + let data: PutSurveyPurposeAndMethodologyData; + + before(() => { + data = new PutSurveyPurposeAndMethodologyData(null); + }); + + it('sets id', () => { + expect(data.id).to.equal(null); + }); + + it('sets intended_outcomes_id', () => { + expect(data.intended_outcome_id).to.eql(null); + }); + + it('sets field_method_id', () => { + expect(data.field_method_id).to.eql(null); + }); + + it('sets additional_details', () => { + expect(data.additional_details).to.equal(null); + }); + + it('sets ecological_season_id', () => { + expect(data.ecological_season_id).to.equal(null); + }); + + // it('sets vantage_code_ids', () => { + // expect(data.vantage_code_ids).to.equal([]); + // }); + + it('sets revision_count', () => { + expect(data.revision_count).to.equal(null); + }); + }); + + describe('All values provided', () => { + let data: PutSurveyPurposeAndMethodologyData; + + const purposeAndMethodologyData = { + id: 1, + field_method_id: 1, + additional_details: 'additional details', + vantage_code_ids: [1, 2], + ecological_season_id: 1, + intended_outcome_id: 1, + revision_count: 1 + }; + + before(() => { + data = new PutSurveyPurposeAndMethodologyData(purposeAndMethodologyData); + }); + + it('sets id', () => { + expect(data.id).to.equal(purposeAndMethodologyData.id); + }); + + it('sets intended_outcomes_id', () => { + expect(data.intended_outcome_id).to.eql(purposeAndMethodologyData.intended_outcome_id); + }); + + it('sets additional_details', () => { + expect(data.additional_details).to.eql(purposeAndMethodologyData.additional_details); + }); + + it('sets field_method_id', () => { + expect(data.field_method_id).to.equal(purposeAndMethodologyData.field_method_id); + }); + + it('sets ecological_season_id', () => { + expect(data.ecological_season_id).to.equal(purposeAndMethodologyData.ecological_season_id); + }); + + it('sets vantage_code_ids', () => { + expect(data.vantage_code_ids).to.equal(purposeAndMethodologyData.vantage_code_ids); + }); + + it('sets revision_count', () => { + expect(data.revision_count).to.equal(purposeAndMethodologyData.revision_count); + }); + }); +}); diff --git a/api/src/models/survey-update.ts b/api/src/models/survey-update.ts index 482e242bdf..c408a9d91a 100644 --- a/api/src/models/survey-update.ts +++ b/api/src/models/survey-update.ts @@ -14,10 +14,8 @@ const defaultLog = getLogger('models/survey-update'); export class GetUpdateSurveyDetailsData { id: number; survey_name: string; - survey_purpose: string; focal_species: (string | number)[]; ancillary_species: (string | number)[]; - common_survey_methodology_id: number; start_date: string; end_date: string; biologist_first_name: string; @@ -45,12 +43,10 @@ export class GetUpdateSurveyDetailsData { this.id = surveyDetailsData?.id ?? null; this.survey_name = surveyDetailsData?.name || ''; - this.survey_purpose = surveyDetailsData?.objectives || ''; this.focal_species = surveyDetailsData?.focal_species || []; this.ancillary_species = surveyDetailsData?.ancillary_species || []; this.start_date = surveyDetailsData?.start_date || ''; this.end_date = surveyDetailsData?.end_date || ''; - this.common_survey_methodology_id = surveyDetailsData?.common_survey_methodology_id ?? null; this.biologist_first_name = surveyDetailsData?.lead_first_name || ''; this.biologist_last_name = surveyDetailsData?.lead_last_name || ''; this.survey_area_name = surveyDetailsData?.location_name || ''; @@ -77,10 +73,8 @@ export class GetUpdateSurveyDetailsData { */ export class PutSurveyDetailsData { name: string; - objectives: string; focal_species: number[]; ancillary_species: number[]; - common_survey_methodology_id: number; start_date: string; end_date: string; lead_first_name: string; @@ -105,13 +99,11 @@ export class PutSurveyDetailsData { }); this.name = obj?.survey_details?.survey_name || null; - this.objectives = obj?.survey_details?.survey_purpose || null; this.focal_species = (obj?.survey_details?.focal_species?.length && obj.survey_details?.focal_species) || []; this.ancillary_species = (obj?.survey_details?.ancillary_species?.length && obj.survey_details?.ancillary_species) || []; this.start_date = obj?.survey_details?.start_date || null; this.end_date = obj?.survey_details?.end_date || null; - this.common_survey_methodology_id = obj?.survey_details?.common_survey_methodology_id || null; this.lead_first_name = obj?.survey_details?.biologist_first_name || null; this.lead_last_name = obj?.survey_details?.biologist_last_name || null; this.location_name = obj?.survey_details?.survey_area_name || null; @@ -152,3 +144,31 @@ export class PutSurveyProprietorData { this.revision_count = obj?.revision_count ?? null; } } + +/** + * Pre-processes PUT /project/{projectId}/survey/{surveyId} survey purpose and methodology data for update + * + * @export + * @class PutSurveyPurposeAndMethodologyData + */ +export class PutSurveyPurposeAndMethodologyData { + id: number; + intended_outcome_id: number; + field_method_id: number; + additional_details: string; + ecological_season_id: number; + vantage_code_ids: number[]; + revision_count: number; + + constructor(obj?: any) { + defaultLog.debug({ label: 'PutSurveyPurposeAndMethodologyData', message: 'params', obj }); + + this.id = obj?.id ?? null; + this.intended_outcome_id = obj?.intended_outcome_id || null; + this.field_method_id = obj?.field_method_id || null; + this.additional_details = obj?.additional_details || null; + this.ecological_season_id = obj?.ecological_season_id || null; + this.vantage_code_ids = (obj?.vantage_code_ids?.length && obj.vantage_code_ids) || []; + this.revision_count = obj?.revision_count ?? null; + } +} diff --git a/api/src/models/survey-view-update.ts b/api/src/models/survey-view-update.ts index 4f20d5d3f6..1710a66e54 100644 --- a/api/src/models/survey-view-update.ts +++ b/api/src/models/survey-view-update.ts @@ -39,3 +39,32 @@ export class GetSurveyProprietorData { this.revision_count = data?.revision_count ?? null; } } + +export class GetSurveyPurposeAndMethodologyData { + constructor(responseData?: any) { + defaultLog.debug({ + label: 'GetSurveyPurposeAndMethodologyData', + message: 'params', + data: responseData + }); + + const obj = {}; + + responseData.forEach((item: any) => { + if (!obj[item.id]) { + obj[item.id] = { + id: item.id, + intended_outcome_id: item.intended_outcome_id, + additional_details: item.additional_details, + field_method_id: item.field_method_id, + ecological_season_id: item.ecological_season_id, + revision_count: item.revision_count, + vantage_code_ids: [item.vantage_id] + }; + } else { + obj[item.id].vantage_code_ids.push(item.vantage_id); + } + }); + return Object.values(obj); + } +} diff --git a/api/src/models/survey-view.test.ts b/api/src/models/survey-view.test.ts index 2dfde5144a..307d92479e 100644 --- a/api/src/models/survey-view.test.ts +++ b/api/src/models/survey-view.test.ts @@ -14,10 +14,6 @@ describe('GetViewSurveyDetailsData', () => { expect(data.survey_name).to.equal(''); }); - it('sets survey_purpose', () => { - expect(data.survey_purpose).to.equal(''); - }); - it('sets focal_species', () => { expect(data.focal_species).to.eql([]); }); @@ -26,10 +22,6 @@ describe('GetViewSurveyDetailsData', () => { expect(data.ancillary_species).to.eql([]); }); - it('sets common survey methodology', () => { - expect(data.common_survey_methodology).to.equal(''); - }); - it('sets start_date', () => { expect(data.start_date).to.equal(''); }); @@ -115,10 +107,6 @@ describe('GetViewSurveyDetailsData', () => { expect(data.survey_name).to.equal(surveyData.name); }); - it('sets survey_purpose', () => { - expect(data.survey_purpose).to.equal(surveyData.objectives); - }); - it('sets focal_species', () => { expect(data.focal_species).to.eql(surveyData.focal_species); }); @@ -127,10 +115,6 @@ describe('GetViewSurveyDetailsData', () => { expect(data.ancillary_species).to.eql(surveyData.ancillary_species); }); - it('sets common survey methodology', () => { - expect(data.common_survey_methodology).to.equal(surveyData.common_survey_methodology); - }); - it('sets start_date', () => { expect(data.start_date).to.equal(surveyData.start_date); }); diff --git a/api/src/models/survey-view.ts b/api/src/models/survey-view.ts index bd67c49027..6471d5d970 100644 --- a/api/src/models/survey-view.ts +++ b/api/src/models/survey-view.ts @@ -14,10 +14,8 @@ const defaultLog = getLogger('models/survey-view'); export class GetViewSurveyDetailsData { id: number; survey_name: string; - survey_purpose: string; focal_species: (string | number)[]; ancillary_species: (string | number)[]; - common_survey_methodology: string; start_date: string; end_date: string; biologist_first_name: string; @@ -47,13 +45,11 @@ export class GetViewSurveyDetailsData { this.id = surveyDetailsData?.id ?? null; this.occurrence_submission_id = surveyDetailsData?.occurrence_submission_id ?? null; this.survey_name = surveyDetailsData?.name || ''; - this.survey_purpose = surveyDetailsData?.objectives || ''; this.focal_species = surveyDetailsData?.focal_species || []; this.ancillary_species = surveyDetailsData?.ancillary_species || []; this.start_date = surveyDetailsData?.start_date || ''; this.end_date = surveyDetailsData?.end_date || ''; this.biologist_first_name = surveyDetailsData?.lead_first_name || ''; - this.common_survey_methodology = surveyDetailsData?.common_survey_methodology || ''; this.biologist_last_name = surveyDetailsData?.lead_last_name || ''; this.survey_area_name = surveyDetailsData?.location_name || ''; this.geometry = (surveyDetailsData?.geometry?.length && surveyDetailsData.geometry) || []; diff --git a/api/src/openapi/schemas/survey.test.ts b/api/src/openapi/schemas/survey.test.ts deleted file mode 100644 index 4235a8366c..0000000000 --- a/api/src/openapi/schemas/survey.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import Ajv from 'ajv'; -import { expect } from 'chai'; -import { describe } from 'mocha'; -import { surveyCreatePostRequestObject, surveyIdResponseObject } from './survey'; - -describe('surveyCreatePostRequestObject', () => { - const ajv = new Ajv(); - - it('is valid openapi v3 schema', () => { - expect(ajv.validateSchema(surveyCreatePostRequestObject)).to.be.true; - }); -}); - -describe('surveyIdResponseObject', () => { - const ajv = new Ajv(); - - it('is valid openapi v3 schema', () => { - expect(ajv.validateSchema(surveyIdResponseObject)).to.be.true; - }); -}); diff --git a/api/src/openapi/schemas/survey.ts b/api/src/openapi/schemas/survey.ts deleted file mode 100644 index b957162d9b..0000000000 --- a/api/src/openapi/schemas/survey.ts +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Request Object for survey create POST request - */ -export const surveyCreatePostRequestObject = { - title: 'SurveyProject post request object', - type: 'object', - required: [ - 'survey_name', - 'start_date', - 'end_date', - 'focal_species', - 'ancillary_species', - 'survey_purpose', - 'biologist_first_name', - 'biologist_last_name', - 'survey_area_name', - 'survey_data_proprietary' - ], - properties: { - survey_name: { - type: 'string' - }, - start_date: { - type: 'string', - description: 'ISO 8601 date string' - }, - end_date: { - type: 'string', - description: 'ISO 8601 date string' - }, - focal_species: { - type: 'array', - items: { - type: 'number' - }, - description: 'Selected focal species ids' - }, - ancillary_species: { - type: 'array', - items: { - type: 'number' - }, - description: 'Selected ancillary species ids' - }, - survey_purpose: { - type: 'string' - }, - biologist_first_name: { - type: 'string' - }, - biologist_last_name: { - type: 'string' - }, - survey_area_name: { - type: 'string' - }, - survey_data_proprietary: { - type: 'string' - }, - proprietary_data_category: { - type: 'number' - }, - proprietor_name: { - type: 'string' - }, - category_rationale: { - type: 'string' - }, - first_nations_id: { - type: 'number' - }, - data_sharing_agreement_required: { - type: 'string' - } - } -}; - -/** - * Basic response object for a survey. - */ -export const surveyIdResponseObject = { - title: 'Survey Response Object', - type: 'object', - required: ['id'], - properties: { - id: { - type: 'number' - } - } -}; - -/** - * Response object for survey view GET request - */ -export const surveyViewGetResponseObject = { - title: 'Survey get response object, for view purposes', - type: 'object', - properties: {} -}; - -/** - * Response object for survey update GET request - */ -export const surveyUpdateGetResponseObject = { - title: 'Survey get response object, for update purposes', - type: 'object', - properties: {} -}; - -/** - * Request object for survey update PUT request - */ -export const surveyUpdatePutRequestObject = { - title: 'Survey Put Object', - type: 'object', - properties: { - survey_name: { type: 'string' }, - survey_purpose: { type: 'string' }, - focal_species: { - type: 'array', - items: { - type: 'number' - }, - description: 'Selected focal species ids' - }, - ancillary_species: { - type: 'array', - items: { - type: 'number' - }, - description: 'Selected ancillary species ids' - }, - start_date: { type: 'string' }, - end_date: { type: 'string' }, - biologist_first_name: { type: 'string' }, - biologist_last_name: { type: 'string' }, - survey_area_name: { type: 'string' }, - revision_count: { type: 'number' } - } -}; diff --git a/api/src/paths/codes.ts b/api/src/paths/codes.ts index 3923b64876..c6ceb9ac61 100644 --- a/api/src/paths/codes.ts +++ b/api/src/paths/codes.ts @@ -270,7 +270,49 @@ GET.apiDoc = { } } }, - common_survey_methodologies: { + field_methods: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'number' + }, + name: { + type: 'string' + } + } + } + }, + ecological_seasons: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'number' + }, + name: { + type: 'string' + } + } + } + }, + intended_outcomes: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'number' + }, + name: { + type: 'string' + } + } + } + }, + vantage_codes: { type: 'array', items: { type: 'object', diff --git a/api/src/paths/project/{projectId}/survey/create.ts b/api/src/paths/project/{projectId}/survey/create.ts index a3d45b691d..ac3e546f58 100644 --- a/api/src/paths/project/{projectId}/survey/create.ts +++ b/api/src/paths/project/{projectId}/survey/create.ts @@ -4,7 +4,6 @@ import { PROJECT_ROLE } from '../../../../constants/roles'; import { getDBConnection, IDBConnection } from '../../../../database/db'; import { HTTP400 } from '../../../../errors/custom-error'; import { PostSurveyObject, PostSurveyProprietorData } from '../../../../models/survey-create'; -import { surveyCreatePostRequestObject, surveyIdResponseObject } from '../../../../openapi/schemas/survey'; import { queries } from '../../../../queries/queries'; import { authorizeRequestHandler } from '../../../../request-handlers/security/authorization'; import { getLogger } from '../../../../utils/logger'; @@ -39,7 +38,114 @@ POST.apiDoc = { content: { 'application/json': { schema: { - ...(surveyCreatePostRequestObject as object) + title: 'SurveyProject post request object', + type: 'object', + required: [ + 'survey_name', + 'start_date', + 'end_date', + 'focal_species', + 'ancillary_species', + 'intended_outcome_id', + 'additional_details', + 'field_method_id', + 'vantage_code_ids', + 'ecological_season_id', + 'biologist_first_name', + 'biologist_last_name', + 'survey_area_name', + 'survey_data_proprietary' + ], + properties: { + survey_name: { + type: 'string' + }, + start_date: { + type: 'string', + description: 'ISO 8601 date string' + }, + end_date: { + type: 'string', + description: 'ISO 8601 date string' + }, + focal_species: { + type: 'array', + items: { + type: 'number' + }, + description: 'Selected focal species ids' + }, + ancillary_species: { + type: 'array', + items: { + type: 'number' + }, + description: 'Selected ancillary species ids' + }, + intended_outcome_id: { + type: 'number' + }, + additional_details: { + type: 'string' + }, + field_method_id: { + type: 'number' + }, + vantage_code_ids: { + type: 'array', + items: { + type: 'number' + } + }, + ecological_season_id: { + type: 'number' + }, + biologist_first_name: { + type: 'string' + }, + biologist_last_name: { + type: 'string' + }, + survey_area_name: { + type: 'string' + }, + survey_data_proprietary: { + type: 'string' + }, + proprietary_data_category: { + type: 'number' + }, + proprietor_name: { + type: 'string' + }, + category_rationale: { + type: 'string' + }, + first_nations_id: { + type: 'number' + }, + data_sharing_agreement_required: { + type: 'string' + }, + foippa_requirements_accepted: { + type: 'boolean' + }, + sedis_procedures_accepted: { + type: 'boolean' + }, + funding_sources: { + type: 'array', + items: { + type: 'number' + } + }, + permit_number: { + type: 'string' + }, + permit_type: { + type: 'string' + } + } } } } @@ -50,7 +156,14 @@ POST.apiDoc = { content: { 'application/json': { schema: { - ...(surveyIdResponseObject as object) + title: 'Survey Response Object', + type: 'object', + required: ['id'], + properties: { + id: { + type: 'number' + } + } } } } @@ -169,6 +282,15 @@ export function createSurvey(): RequestHandler { sanitizedPostSurveyData.survey_proprietor && promises.push(insertSurveyProprietor(sanitizedPostSurveyData.survey_proprietor, surveyId, connection)); + //Handle vantage codes associated to this survey + promises.push( + Promise.all( + sanitizedPostSurveyData.vantage_code_ids.map((vantageCode: number) => + insertVantageCodes(vantageCode, surveyId, connection) + ) + ) + ); + await Promise.all(promises); await connection.commit(); @@ -229,6 +351,27 @@ export const insertAncillarySpecies = async ( return result.id; }; +export const insertVantageCodes = async ( + vantage_code_id: number, + survey_id: number, + connection: IDBConnection +): Promise => { + const sqlStatement = queries.survey.postVantageCodesSQL(vantage_code_id, survey_id); + + if (!sqlStatement) { + throw new HTTP400('Failed to build SQL insert statement'); + } + + const response = await connection.query(sqlStatement.text, sqlStatement.values); + const result = (response && response.rows && response.rows[0]) || null; + + if (!result || !result.id) { + throw new HTTP400('Failed to insert ancillary species data'); + } + + return result.id; +}; + export const insertSurveyProprietor = async ( survey_proprietor: PostSurveyProprietorData, survey_id: number, diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/publish.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/publish.ts index e76c47be3a..46c860c35c 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/publish.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/publish.ts @@ -3,7 +3,6 @@ import { Operation } from 'express-openapi'; import { PROJECT_ROLE } from '../../../../../constants/roles'; import { getDBConnection, IDBConnection } from '../../../../../database/db'; import { HTTP400, HTTP500 } from '../../../../../errors/custom-error'; -import { surveyIdResponseObject } from '../../../../../openapi/schemas/survey'; import { queries } from '../../../../../queries/queries'; import { authorizeRequestHandler } from '../../../../../request-handlers/security/authorization'; import { getLogger } from '../../../../../utils/logger'; @@ -69,7 +68,14 @@ PUT.apiDoc = { 'application/json': { schema: { // TODO is there any return value? or is it just an HTTP status with no content? - ...(surveyIdResponseObject as object) + title: 'Survey Response Object', + type: 'object', + required: ['id'], + properties: { + id: { + type: 'number' + } + } } } } diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/update.test.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/update.test.ts index 72bb66a8a6..f96f098fc9 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/update.test.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/update.test.ts @@ -92,10 +92,9 @@ describe('getSurveyForUpdate', () => { const survey_details = { id: 1, name: 'name', - objectives: 'objective', focal_species: [1], ancillary_species: [3], - common_survey_methodology_id: 1, + additional_details: 'details', start_date: '2020-04-04', end_date: '2020-05-05', lead_first_name: 'first', @@ -124,6 +123,7 @@ describe('getSurveyForUpdate', () => { }); sinon.stub(survey_queries, 'getSurveyDetailsForUpdateSQL').returns(SQL`some query`); + sinon.stub(survey_queries, 'getSurveyPurposeAndMethodologyForUpdateSQL').returns(SQL`some query`); sinon.stub(survey_queries, 'getSurveyProprietorForUpdateSQL').returns(SQL`some query`); const requestHandler = update.getSurveyForUpdate(); @@ -134,10 +134,8 @@ describe('getSurveyForUpdate', () => { survey_details: { id: 1, survey_name: survey_details.name, - survey_purpose: survey_details.objectives, focal_species: survey_details.focal_species, ancillary_species: survey_details.ancillary_species, - common_survey_methodology_id: survey_details.common_survey_methodology_id, start_date: survey_details.start_date, end_date: survey_details.end_date, biologist_first_name: survey_details.lead_first_name, @@ -151,6 +149,7 @@ describe('getSurveyForUpdate', () => { publish_date: '', funding_sources: survey_details.pfs_id }, + survey_purpose_and_methodology: null, survey_proprietor: null }); }); @@ -203,6 +202,7 @@ describe('getSurveyForUpdate', () => { expect(mockRes.sendValue).to.eql({ survey_details: null, + survey_purpose_and_methodology: null, survey_proprietor: { category_rationale: survey_proprietor.category_rationale, data_sharing_agreement_required: survey_proprietor.data_sharing_agreement_required, @@ -218,7 +218,7 @@ describe('getSurveyForUpdate', () => { }); }); - it('should return survey details and proprietor info when no entity is specified, on success', async () => { + it('should return survey details, survey purpose and methodology, as well as proprietor info when no entity is specified, on success', async () => { const dbConnectionObj = getMockDBConnection(); const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); @@ -231,10 +231,8 @@ describe('getSurveyForUpdate', () => { const survey_details = { id: 1, name: 'name', - objectives: 'objective', focal_species: [1], ancillary_species: [3], - common_survey_methodology_id: 1, start_date: '2020-04-04', end_date: '2020-05-05', lead_first_name: 'first', @@ -246,6 +244,16 @@ describe('getSurveyForUpdate', () => { pfs_id: [10] }; + const survey_purpose_and_methodology = { + id: 1, + field_method_id: 1, + additional_details: 'details', + ecological_season_id: 1, + intended_outcome_id: 8, + revision_count: 0, + vantage_id: 2 + }; + const survey_proprietor = { category_rationale: '', data_sharing_agreement_required: 'false', @@ -267,6 +275,10 @@ describe('getSurveyForUpdate', () => { rows: [survey_details] }) .onSecondCall() + .resolves({ + rows: [survey_purpose_and_methodology] + }) + .onThirdCall() .resolves({ rows: [survey_proprietor] }); @@ -280,6 +292,7 @@ describe('getSurveyForUpdate', () => { }); sinon.stub(survey_queries, 'getSurveyDetailsForUpdateSQL').returns(SQL`some query`); + sinon.stub(survey_queries, 'getSurveyPurposeAndMethodologyForUpdateSQL').returns(SQL`some query`); sinon.stub(survey_queries, 'getSurveyProprietorForUpdateSQL').returns(SQL`some query`); const requestHandler = update.getSurveyForUpdate(); @@ -290,10 +303,8 @@ describe('getSurveyForUpdate', () => { survey_details: { id: 1, survey_name: survey_details.name, - survey_purpose: survey_details.objectives, focal_species: survey_details.focal_species, ancillary_species: survey_details.ancillary_species, - common_survey_methodology_id: survey_details.common_survey_methodology_id, start_date: survey_details.start_date, end_date: survey_details.end_date, biologist_first_name: survey_details.lead_first_name, @@ -307,6 +318,15 @@ describe('getSurveyForUpdate', () => { publish_date: '', funding_sources: survey_details.pfs_id }, + survey_purpose_and_methodology: { + id: 1, + intended_outcome_id: 8, + field_method_id: 1, + additional_details: 'details', + ecological_season_id: 1, + vantage_code_ids: [2], + revision_count: 0 + }, survey_proprietor: { category_rationale: survey_proprietor.category_rationale, data_sharing_agreement_required: survey_proprietor.data_sharing_agreement_required, @@ -340,7 +360,6 @@ describe('updateSurvey', () => { mockReq.body = { survey_details: { survey_name: 'name', - survey_purpose: 'purpose', species: 'species', start_date: '2020-03-03', end_date: '2020-04-04', @@ -382,7 +401,6 @@ describe('updateSurvey', () => { mockReq.body = { survey_details: { survey_name: 'name', - survey_purpose: 'purpose', species: 'species', start_date: '2020-03-03', end_date: '2020-04-04', @@ -453,7 +471,6 @@ describe('updateSurvey', () => { mockReq.body = { survey_details: { survey_name: 'name', - survey_purpose: 'purpose', species: 'species', start_date: '2020-03-03', end_date: '2020-04-04', @@ -495,7 +512,6 @@ describe('updateSurvey', () => { mockReq.body = { survey_details: { survey_name: 'name', - survey_purpose: 'purpose', species: 'species', start_date: '2020-03-03', end_date: '2020-04-04', @@ -539,7 +555,7 @@ describe('updateSurvey', () => { mockReq.body = { survey_details: { survey_name: 'name', - survey_purpose: 'purpose', + species: 'species', start_date: '2020-03-03', end_date: '2020-04-04', @@ -588,7 +604,6 @@ describe('updateSurvey', () => { mockReq.body = { survey_details: { survey_name: 'name', - survey_purpose: 'purpose', species: 'species', start_date: '2020-03-03', end_date: '2020-04-04', @@ -670,7 +685,6 @@ describe('updateSurvey', () => { mockReq.body = { survey_details: { survey_name: 'name', - survey_purpose: 'purpose', species: 'species', start_date: '2020-03-03', end_date: '2020-04-04', @@ -719,7 +733,6 @@ describe('updateSurvey', () => { mockReq.body = { survey_details: { survey_name: 'name', - survey_purpose: 'purpose', species: 'species', start_date: '2020-03-03', end_date: '2020-04-04', @@ -775,6 +788,7 @@ describe('updateSurveyProprietorData', () => { focal_species: [1], ancillary_species: [2] }, + survey_purpose_and_methodology: {}, survey_proprietor: { id: 0, survey_data_proprietary: 'true' @@ -873,6 +887,7 @@ describe('updateSurveyDetailsData', () => { focal_species: [1], ancillary_species: [2] }, + survey_purpose_and_methodology: null, survey_proprietor: null }; diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts index 18960c9364..fce60ebdce 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/update.ts @@ -2,26 +2,29 @@ import { RequestHandler } from 'express'; import { Operation } from 'express-openapi'; import { PROJECT_ROLE } from '../../../../../constants/roles'; import { getDBConnection, IDBConnection } from '../../../../../database/db'; -import { HTTP400, HTTP409 } from '../../../../../errors/custom-error'; +import { HTTP400, HTTP409, HTTP500 } from '../../../../../errors/custom-error'; import { PostSurveyProprietorData } from '../../../../../models/survey-create'; import { GetUpdateSurveyDetailsData, PutSurveyDetailsData, - PutSurveyProprietorData + PutSurveyProprietorData, + PutSurveyPurposeAndMethodologyData } from '../../../../../models/survey-update'; -import { GetSurveyProprietorData } from '../../../../../models/survey-view-update'; -import { - surveyIdResponseObject, - surveyUpdateGetResponseObject, - surveyUpdatePutRequestObject -} from '../../../../../openapi/schemas/survey'; +import { GetSurveyProprietorData, GetSurveyPurposeAndMethodologyData } from '../../../../../models/survey-view-update'; +import { geoJsonFeature } from '../../../../../openapi/schemas/geoJson'; import { queries } from '../../../../../queries/queries'; import { authorizeRequestHandler } from '../../../../../request-handlers/security/authorization'; import { getLogger } from '../../../../../utils/logger'; -import { insertAncillarySpecies, insertFocalSpecies, insertSurveyFundingSource, insertSurveyPermit } from '../create'; - +import { + insertAncillarySpecies, + insertFocalSpecies, + insertSurveyFundingSource, + insertSurveyPermit, + insertVantageCodes +} from '../create'; export interface IUpdateSurvey { survey_details: object | null; + survey_purpose_and_methodology: object | null; survey_proprietor: object | null; } @@ -59,6 +62,7 @@ export const PUT: Operation = [ export enum GET_SURVEY_ENTITIES { survey_details = 'survey_details', + survey_purpose_and_methodology = 'survey_purpose_and_methodology', survey_proprietor = 'survey_proprietor' } @@ -107,7 +111,185 @@ GET.apiDoc = { content: { 'application/json': { schema: { - ...(surveyUpdateGetResponseObject as object) + title: 'Survey get response object, for update purposes', + type: 'object', + required: ['survey_details', 'survey_purpose_and_methodology', 'survey_proprietor'], + properties: { + survey_details: { + description: 'Survey Details', + type: 'object', + required: [ + 'id', + 'focal_species', + 'ancillary_species', + 'biologist_first_name', + 'biologist_last_name', + 'completion_status', + 'start_date', + 'end_date', + 'funding_sources', + 'geometry', + 'permit_number', + 'permit_type', + 'publish_date', + 'revision_count', + 'survey_area_name', + 'survey_name' + ], + properties: { + id: { + description: 'Survey id', + type: 'number' + }, + ancillary_species: { + type: 'array', + items: { + type: 'string' + } + }, + focal_species: { + type: 'array', + items: { + type: 'string' + } + }, + biologist_first_name: { + type: 'string' + }, + biologist_last_name: { + type: 'string' + }, + completion_status: { + type: 'string' + }, + start_date: { + type: 'string', + format: 'date', + description: 'ISO 8601 date string for the funding end_date' + }, + end_date: { + type: 'string', + format: 'date', + description: 'ISO 8601 date string for the funding end_date' + }, + funding_sources: { + type: 'array', + items: { + title: 'survey funding agency', + type: 'object', + required: ['agency_name', 'funding_amount', 'funding_start_date', 'funding_end_date'], + properties: { + pfs_id: { + type: 'number' + }, + agency_name: { + type: 'string' + }, + funding_amount: { + type: 'number' + }, + funding_start_date: { + type: 'string', + description: 'ISO 8601 date string' + }, + funding_end_date: { + type: 'string', + description: 'ISO 8601 date string' + } + } + } + }, + geometry: { + type: 'array', + items: { + ...(geoJsonFeature as object) + } + }, + permit_number: { + type: 'string' + }, + permit_type: { + type: 'string' + }, + publish_date: { + type: 'string' + }, + revision_count: { + type: 'number' + }, + survey_area_name: { + type: 'string' + }, + survey_name: { + type: 'string' + } + } + }, + survey_purpose_and_methodology: { + description: 'Survey Details', + type: 'object', + properties: { + id: { + type: 'number' + }, + field_method_id: { + type: 'number' + }, + additional_details: { + type: 'string' + }, + intended_outcome_id: { + type: 'number' + }, + ecological_season_id: { + type: 'number' + }, + revision_count: { + type: 'number' + }, + vantage_code_ids: { + type: 'array', + items: { + type: 'number' + } + } + } + }, + survey_proprietor: { + description: 'Survey Details', + type: 'object', + //Note: do not make any of these fields required as the object can be null + properties: { + survey_data_proprietary: { + type: 'string' + }, + id: { + type: 'number' + }, + category_rationale: { + type: 'string' + }, + data_sharing_agreement_required: { + type: 'string' + }, + first_nations_id: { + type: 'number' + }, + first_nations_name: { + type: 'string' + }, + proprietary_data_category: { + type: 'number' + }, + proprietary_data_category_name: { + type: 'string' + }, + revision_count: { + type: 'number' + } + } + } + } } } } @@ -161,7 +343,164 @@ PUT.apiDoc = { content: { 'application/json': { schema: { - ...(surveyUpdatePutRequestObject as object) + title: 'Survey Put Object', + type: 'object', + properties: { + survey_details: { + description: 'Survey Details', + type: 'object', + required: [ + 'id', + 'focal_species', + 'ancillary_species', + 'biologist_first_name', + 'biologist_last_name', + 'completion_status', + 'start_date', + 'end_date', + 'funding_sources', + 'geometry', + 'permit_number', + 'permit_type', + 'publish_date', + 'revision_count', + 'survey_area_name', + 'survey_name' + ], + properties: { + id: { + description: 'Survey id', + type: 'number' + }, + ancillary_species: { + type: 'array', + items: { + type: 'number' + } + }, + focal_species: { + type: 'array', + items: { + type: 'number' + } + }, + biologist_first_name: { + type: 'string' + }, + biologist_last_name: { + type: 'string' + }, + completion_status: { + type: 'string' + }, + start_date: { + type: 'string', + format: 'date', + description: 'ISO 8601 date string for the funding end_date' + }, + end_date: { + type: 'string', + format: 'date', + description: 'ISO 8601 date string for the funding end_date' + }, + funding_sources: { + type: 'array', + items: { + title: 'survey funding agency', + type: 'number' + } + }, + geometry: { + type: 'array', + items: { + ...(geoJsonFeature as object) + } + }, + permit_number: { + type: 'string' + }, + permit_type: { + type: 'string' + }, + publish_date: { + type: 'string' + }, + revision_count: { + type: 'number' + }, + survey_area_name: { + type: 'string' + }, + survey_name: { + type: 'string' + } + } + }, + survey_purpose_and_methodology: { + description: 'Survey Details', + type: 'object', + properties: { + id: { + type: 'number' + }, + field_method_id: { + type: 'number' + }, + additional_details: { + type: 'string' + }, + intended_outcome_id: { + type: 'number' + }, + ecological_season_id: { + type: 'number' + }, + revision_count: { + type: 'number' + }, + vantage_code_ids: { + type: 'array', + items: { + type: 'number' + } + } + } + }, + survey_proprietor: { + description: 'Survey Details', + type: 'object', + //Note: do not make any of these fields required as the object can be null + properties: { + survey_data_proprietary: { + type: 'string' + }, + id: { + type: 'number' + }, + category_rationale: { + type: 'string' + }, + data_sharing_agreement_required: { + type: 'string' + }, + first_nations_id: { + type: 'number' + }, + first_nations_name: { + type: 'string' + }, + proprietary_data_category: { + type: 'number' + }, + proprietary_data_category_name: { + type: 'string' + }, + revision_count: { + type: 'number' + } + } + } + } } } } @@ -172,7 +511,14 @@ PUT.apiDoc = { content: { 'application/json': { schema: { - ...(surveyIdResponseObject as object) + title: 'Survey Response Object', + type: 'object', + required: ['id'], + properties: { + id: { + type: 'number' + } + } } } } @@ -197,6 +543,7 @@ PUT.apiDoc = { export interface IGetSurveyForUpdate { survey_details: GetUpdateSurveyDetailsData | null; + survey_purpose_and_methodology: GetSurveyPurposeAndMethodologyData | null; survey_proprietor: GetSurveyProprietorData | null; } @@ -222,6 +569,7 @@ export function getSurveyForUpdate(): RequestHandler { const results: IGetSurveyForUpdate = { survey_details: null, + survey_purpose_and_methodology: null, survey_proprietor: null }; @@ -235,6 +583,14 @@ export function getSurveyForUpdate(): RequestHandler { ); } + if (entities.includes(GET_SURVEY_ENTITIES.survey_purpose_and_methodology)) { + promises.push( + getSurveyPurposeAndMethodologyData(surveyId, connection).then((value) => { + results.survey_purpose_and_methodology = value; + }) + ); + } + if (entities.includes(GET_SURVEY_ENTITIES.survey_proprietor)) { promises.push( getSurveyProprietorData(surveyId, connection).then((value) => { @@ -278,6 +634,21 @@ export const getSurveyDetailsData = async ( return result; }; +export const getSurveyPurposeAndMethodologyData = async ( + surveyId: number, + connection: IDBConnection +): Promise => { + const sqlStatement = queries.survey.getSurveyPurposeAndMethodologyForUpdateSQL(surveyId); + + if (!sqlStatement) { + throw new HTTP400('Failed to build survey proprietor SQL get statement'); + } + + const response = await connection.query(sqlStatement.text, sqlStatement.values); + + return (response && response.rows && new GetSurveyPurposeAndMethodologyData(response.rows)[0]) || null; +}; + export const getSurveyProprietorData = async ( surveyId: number, connection: IDBConnection @@ -328,6 +699,10 @@ export function updateSurvey(): RequestHandler { promises.push(updateSurveyDetailsData(projectId, surveyId, entities, connection)); } + if (entities.survey_purpose_and_methodology) { + promises.push(updateSurveyPurposeAndMethodologyData(surveyId, entities, connection)); + } + if (entities.survey_proprietor) { promises.push(updateSurveyProprietorData(surveyId, entities, connection)); } @@ -515,3 +890,68 @@ export const unassociatePermitFromSurvey = async (survey_id: number, connection: throw new HTTP400('Failed to update survey permit number data'); } }; + +export const updateSurveyPurposeAndMethodologyData = async ( + surveyId: number, + entities: IUpdateSurvey, + connection: IDBConnection +): Promise => { + const putPurposeAndMethodologyData = + (entities?.survey_purpose_and_methodology && + new PutSurveyPurposeAndMethodologyData(entities.survey_purpose_and_methodology)) || + null; + + const revision_count = putPurposeAndMethodologyData?.revision_count ?? null; + + if (!revision_count && revision_count !== 0) { + throw new HTTP400('Failed to parse request body'); + } + + const updateSurveySQLStatement = queries.survey.putSurveyPurposeAndMethodologySQL( + surveyId, + putPurposeAndMethodologyData, + revision_count + ); + + if (!updateSurveySQLStatement) { + throw new HTTP400('Failed to build SQL update statement'); + } + + const result = await connection.query(updateSurveySQLStatement.text, updateSurveySQLStatement.values); + if (!result || !result.rowCount) { + throw new HTTP409('Failed to update stale survey data'); + } + + const promises: Promise[] = []; + + promises.push(deleteSurveyVantageCodes(surveyId, connection)); + //Handle vantage codes associated to this survey + + if (putPurposeAndMethodologyData?.vantage_code_ids) { + promises.push( + Promise.all( + putPurposeAndMethodologyData.vantage_code_ids.map((vantageCode: number) => + insertVantageCodes(vantageCode, surveyId, connection) + ) + ) + ); + } + + await Promise.all(promises); + + await connection.commit(); +}; + +export const deleteSurveyVantageCodes = async (survey_id: number, connection: IDBConnection): Promise => { + const sqlStatement = queries.survey.deleteSurveyVantageCodesSQL(survey_id); + + if (!sqlStatement) { + throw new HTTP400('Failed to build delete survey vantage codes SQL statement'); + } + + const response = await connection.query(sqlStatement.text, sqlStatement.values); + + if (!response) { + throw new HTTP500('Failed to delete survey vantage codes'); + } +}; diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/view.test.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/view.test.ts index ffd1485f26..1a0c19d1ed 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/view.test.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/view.test.ts @@ -31,6 +31,9 @@ describe('getSurveyForView', () => { survey_details: { id: null }, + survey_purpose_and_methodology: { + id: null + }, survey_proprietor: { id: null } @@ -58,6 +61,7 @@ describe('getSurveyForView', () => { }); sinon.stub(survey_queries, 'getSurveyBasicDataForViewSQL').returns(null); + sinon.stub(survey_queries, 'getSurveyPurposeAndMethodologyForUpdateSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyFundingSourcesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveySpeciesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyProprietorForUpdateSQL').returns(SQL`valid sql`); @@ -89,6 +93,10 @@ describe('getSurveyForView', () => { rows: [{}] }) .onCall(3) + .resolves({ + rows: [{}] + }) + .onCall(4) .resolves({ rows: [{}] }); @@ -102,6 +110,7 @@ describe('getSurveyForView', () => { }); sinon.stub(survey_queries, 'getSurveyBasicDataForViewSQL').returns(SQL`valid sql`); + sinon.stub(survey_queries, 'getSurveyPurposeAndMethodologyForUpdateSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyFundingSourcesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveySpeciesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyProprietorForUpdateSQL').returns(SQL`valid sql`); @@ -128,6 +137,7 @@ describe('getSurveyForView', () => { }); sinon.stub(survey_queries, 'getSurveyBasicDataForViewSQL').returns(SQL`valid sql`); + sinon.stub(survey_queries, 'getSurveyPurposeAndMethodologyForUpdateSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyFundingSourcesDataForViewSQL').returns(null); sinon.stub(survey_queries, 'getSurveySpeciesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyProprietorForUpdateSQL').returns(SQL`valid sql`); @@ -154,6 +164,7 @@ describe('getSurveyForView', () => { }); sinon.stub(survey_queries, 'getSurveyBasicDataForViewSQL').returns(SQL`valid sql`); + sinon.stub(survey_queries, 'getSurveyPurposeAndMethodologyForUpdateSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyFundingSourcesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveySpeciesDataForViewSQL').returns(null); sinon.stub(survey_queries, 'getSurveyProprietorForUpdateSQL').returns(SQL`valid sql`); @@ -182,11 +193,11 @@ describe('getSurveyForView', () => { }) .onCall(2) .resolves({ - rows: [] // empty response + rows: [{}] }) .onCall(3) .resolves({ - rows: [{}] + rows: [] // empty response }); sinon.stub(db, 'getDBConnection').returns({ @@ -198,6 +209,7 @@ describe('getSurveyForView', () => { }); sinon.stub(survey_queries, 'getSurveyBasicDataForViewSQL').returns(SQL`valid sql`); + sinon.stub(survey_queries, 'getSurveyPurposeAndMethodologyForUpdateSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyFundingSourcesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveySpeciesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyProprietorForUpdateSQL').returns(SQL`valid sql`); @@ -224,6 +236,7 @@ describe('getSurveyForView', () => { }); sinon.stub(survey_queries, 'getSurveyBasicDataForViewSQL').returns(SQL`valid sql`); + sinon.stub(survey_queries, 'getSurveyPurposeAndMethodologyForUpdateSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyFundingSourcesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveySpeciesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyProprietorForUpdateSQL').returns(null); @@ -242,7 +255,6 @@ describe('getSurveyForView', () => { const survey_basic_data = { id: 2, name: 'name', - objectives: 'objective', start_date: '2020/04/04', end_date: '2020/05/05', lead_first_name: 'first', @@ -254,9 +266,17 @@ describe('getSurveyForView', () => { publish_timestamp: null, number: '123', type: 'scientific', - common_survey_methodology: 'method', occurrence_submission_id: 3 }; + const survey_purpose_and_methodology = { + id: 17, + field_method_id: 1, + additional_details: 'details', + ecological_season_id: 1, + intended_outcome_id: 8, + revision_count: 0, + vantage_id: 2 + }; const survey_funding_source_data = { pfs_id: 1, @@ -293,13 +313,17 @@ describe('getSurveyForView', () => { }) .onCall(1) .resolves({ - rows: [survey_funding_source_data] + rows: [survey_purpose_and_methodology] }) .onCall(2) .resolves({ - rows: [survey_species_data] + rows: [survey_funding_source_data] }) .onCall(3) + .resolves({ + rows: [survey_species_data] + }) + .onCall(4) .resolves({ rows: [survey_proprietor_data] }); @@ -315,6 +339,7 @@ describe('getSurveyForView', () => { sinon.stub(survey_queries, 'getSurveyBasicDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyFundingSourcesDataForViewSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveySpeciesDataForViewSQL').returns(SQL`valid sql`); + sinon.stub(survey_queries, 'getSurveyPurposeAndMethodologyForUpdateSQL').returns(SQL`valid sql`); sinon.stub(survey_queries, 'getSurveyProprietorForUpdateSQL').returns(SQL`valid sql`); const result = view.getSurveyForView(); @@ -326,10 +351,8 @@ describe('getSurveyForView', () => { id: survey_basic_data.id, occurrence_submission_id: survey_basic_data.occurrence_submission_id, survey_name: survey_basic_data.name, - survey_purpose: survey_basic_data.objectives, focal_species: survey_species_data.focal_species, ancillary_species: survey_species_data.ancillary_species, - common_survey_methodology: survey_basic_data.common_survey_methodology, start_date: survey_basic_data.start_date, end_date: survey_basic_data.end_date, biologist_first_name: survey_basic_data.lead_first_name, @@ -363,5 +386,15 @@ describe('getSurveyForView', () => { data_sharing_agreement_required: 'true', revision_count: survey_proprietor_data.revision_count }); + + expect(actualResult.survey_purpose_and_methodology).to.eql({ + id: survey_purpose_and_methodology.id, + additional_details: survey_purpose_and_methodology.additional_details, + ecological_season_id: survey_purpose_and_methodology.ecological_season_id, + field_method_id: survey_purpose_and_methodology.field_method_id, + intended_outcome_id: survey_purpose_and_methodology.intended_outcome_id, + revision_count: survey_purpose_and_methodology.revision_count, + vantage_code_ids: [survey_purpose_and_methodology.vantage_id] + }); }); }); diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts index cb0640bd85..be8e86e731 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/view.ts @@ -4,8 +4,8 @@ import { PROJECT_ROLE } from '../../../../../constants/roles'; import { getDBConnection, IDBConnection } from '../../../../../database/db'; import { HTTP400 } from '../../../../../errors/custom-error'; import { GetViewSurveyDetailsData } from '../../../../../models/survey-view'; -import { GetSurveyProprietorData } from '../../../../../models/survey-view-update'; -import { surveyViewGetResponseObject } from '../../../../../openapi/schemas/survey'; +import { GetSurveyProprietorData, GetSurveyPurposeAndMethodologyData } from '../../../../../models/survey-view-update'; +import { geoJsonFeature } from '../../../../../openapi/schemas/geoJson'; import { queries } from '../../../../../queries/queries'; import { authorizeRequestHandler } from '../../../../../request-handlers/security/authorization'; import { getLogger } from '../../../../../utils/logger'; @@ -55,11 +55,204 @@ GET.apiDoc = { ], responses: { 200: { - description: 'Survey with matching surveyId.', + description: 'Survey with matching surveyId and projectId.', content: { 'application/json': { schema: { - ...(surveyViewGetResponseObject as object) + title: 'Survey get response object, for view purposes', + type: 'object', + required: ['survey_details', 'survey_purpose_and_methodology', 'survey_proprietor'], + properties: { + survey_details: { + description: 'Survey Details', + type: 'object', + required: [ + 'id', + 'occurrence_submission_id', + 'focal_species', + 'ancillary_species', + 'biologist_first_name', + 'biologist_last_name', + 'completion_status', + 'start_date', + 'end_date', + 'funding_sources', + 'geometry', + 'permit_number', + 'permit_type', + 'publish_date', + 'revision_count', + 'survey_area_name', + 'survey_name' + ], + properties: { + id: { + description: 'Survey id', + type: 'number' + }, + ancillary_species: { + type: 'array', + items: { + type: 'string' + } + }, + focal_species: { + type: 'array', + items: { + type: 'string' + } + }, + biologist_first_name: { + type: 'string' + }, + biologist_last_name: { + type: 'string' + }, + completion_status: { + type: 'string' + }, + start_date: { + type: 'string', + format: 'date', + description: 'ISO 8601 date string for the funding end_date' + }, + end_date: { + type: 'string', + format: 'date', + description: 'ISO 8601 date string for the funding end_date' + }, + funding_sources: { + type: 'array', + items: { + title: 'survey funding agency', + type: 'object', + required: ['agency_name', 'funding_amount', 'funding_start_date', 'funding_end_date'], + properties: { + pfs_id: { + type: 'number' + }, + agency_name: { + type: 'string' + }, + funding_amount: { + type: 'number' + }, + funding_start_date: { + type: 'string', + description: 'ISO 8601 date string' + }, + funding_end_date: { + type: 'string', + description: 'ISO 8601 date string' + } + } + } + }, + geometry: { + type: 'array', + items: { + ...(geoJsonFeature as object) + } + }, + occurrence_submission_id: { + description: 'A survey occurrence submission ID', + type: 'number', + example: 1 + }, + permit_number: { + type: 'string' + }, + permit_type: { + type: 'string' + }, + publish_date: { + type: 'string' + }, + revision_count: { + type: 'number' + }, + survey_area_name: { + type: 'string' + }, + survey_name: { + type: 'string' + } + } + }, + survey_purpose_and_methodology: { + description: 'Survey Details', + type: 'object', + required: [ + 'id', + 'field_method_id', + 'additional_details', + 'intended_outcome_id', + 'ecological_season_id', + 'revision_count', + 'vantage_code_ids' + ], + properties: { + id: { + type: 'number' + }, + field_method_id: { + type: 'number' + }, + additional_details: { + type: 'string' + }, + intended_outcome_id: { + type: 'number' + }, + ecological_season_id: { + type: 'number' + }, + revision_count: { + type: 'number' + }, + vantage_code_ids: { + type: 'array', + items: { + type: 'number' + } + } + } + }, + survey_proprietor: { + description: 'Survey Details', + type: 'object', + //Note: do not make any of these fields required as the object can be null + properties: { + survey_data_proprietary: { + type: 'string' + }, + id: { + type: 'number' + }, + category_rationale: { + type: 'string' + }, + data_sharing_agreement_required: { + type: 'string' + }, + first_nations_id: { + type: 'number' + }, + first_nations_name: { + type: 'string' + }, + proprietary_data_category: { + type: 'number' + }, + proprietary_data_category_name: { + type: 'string' + }, + revision_count: { + type: 'number' + } + } + } + } } } } @@ -100,8 +293,15 @@ export function getSurveyForView(): RequestHandler { try { await connection.open(); - const [surveyBasicData, surveyFundingSourcesData, SurveySpeciesData, surveyProprietorData] = await Promise.all([ + const [ + surveyBasicData, + surveyPurposeAndMethodology, + surveyFundingSourcesData, + SurveySpeciesData, + surveyProprietorData + ] = await Promise.all([ getSurveyBasicDataForView(surveyId, connection), + getSurveyPurposeAndMethodologyDataForView(surveyId, connection), getSurveyFundingSourcesDataForView(surveyId, connection), getSurveySpeciesDataForView(surveyId, connection), getSurveyProprietorDataForView(surveyId, connection) @@ -115,11 +315,15 @@ export function getSurveyForView(): RequestHandler { ...SurveySpeciesData }); + const getSurveyPurposeAndMethodology = + (surveyPurposeAndMethodology && new GetSurveyPurposeAndMethodologyData(surveyPurposeAndMethodology))[0] || null; + const getSurveyProprietorData = (surveyProprietorData && new GetSurveyProprietorData(surveyProprietorData)) || null; const result = { survey_details: getSurveyData, + survey_purpose_and_methodology: getSurveyPurposeAndMethodology, survey_proprietor: getSurveyProprietorData }; @@ -149,6 +353,25 @@ export const getSurveyBasicDataForView = async (surveyId: number, connection: ID return (response && response.rows?.[0]) || null; }; +export const getSurveyPurposeAndMethodologyDataForView = async ( + surveyId: number, + connection: IDBConnection +): Promise => { + const sqlStatement = queries.survey.getSurveyPurposeAndMethodologyForUpdateSQL(surveyId); + + if (!sqlStatement) { + throw new HTTP400('Failed to build SQL get statement'); + } + + const response = await connection.query(sqlStatement.text, sqlStatement.values); + + if (!response || !response?.rows?.[0]) { + throw new HTTP400('Failed to get survey purpose and methodology data'); + } + + return (response && response.rows) || []; +}; + export const getSurveyFundingSourcesDataForView = async ( surveyId: number, connection: IDBConnection diff --git a/api/src/paths/project/{projectId}/surveys.ts b/api/src/paths/project/{projectId}/surveys.ts index e3be057687..9f9ba32830 100644 --- a/api/src/paths/project/{projectId}/surveys.ts +++ b/api/src/paths/project/{projectId}/surveys.ts @@ -6,7 +6,6 @@ import { COMPLETION_STATUS } from '../../../constants/status'; import { getDBConnection } from '../../../database/db'; import { HTTP400 } from '../../../errors/custom-error'; import { GetSurveyListData } from '../../../models/survey-view'; -import { surveyIdResponseObject } from '../../../openapi/schemas/survey'; import { queries } from '../../../queries/queries'; import { authorizeRequestHandler } from '../../../request-handlers/security/authorization'; import { getLogger } from '../../../utils/logger'; @@ -54,7 +53,14 @@ GET.apiDoc = { schema: { type: 'array', items: { - ...(surveyIdResponseObject as object) + title: 'Survey Response Object', + type: 'object', + required: ['id'], + properties: { + id: { + type: 'number' + } + } } } } diff --git a/api/src/paths/xlsx/transform.ts b/api/src/paths/xlsx/transform.ts index d6d86c950f..b69628c8ca 100644 --- a/api/src/paths/xlsx/transform.ts +++ b/api/src/paths/xlsx/transform.ts @@ -138,12 +138,10 @@ export function getTransformationSchema(): RequestHandler { const xlsxCsv = req['xlsx']; const template_id = xlsxCsv.workbook.rawWorkbook.Custprops.sims_template_id; - const species_id = xlsxCsv.workbook.rawWorkbook.Custprops.sims_species_id; - const csm_id = xlsxCsv.workbook.rawWorkbook.Custprops.sims_csm_id; + const field_method_id = xlsxCsv.workbook.rawWorkbook.Custprops.sims_csm_id; const templateMethodologySpeciesRecord = await getTemplateMethodologySpeciesRecord( - Number(species_id), - Number(csm_id), + Number(field_method_id), Number(template_id), connection ); diff --git a/api/src/paths/xlsx/validate.test.ts b/api/src/paths/xlsx/validate.test.ts index 1bee9404e6..89a7412836 100644 --- a/api/src/paths/xlsx/validate.test.ts +++ b/api/src/paths/xlsx/validate.test.ts @@ -135,7 +135,7 @@ describe('getTemplateMethodologySpeciesRecord', () => { sinon.stub(survey_queries, 'getTemplateMethodologySpeciesRecordSQL').returns(null); try { - await validate.getTemplateMethodologySpeciesRecord(1234, 1, 1, { ...dbConnectionObj, systemUserId: () => 20 }); + await validate.getTemplateMethodologySpeciesRecord(1, 1, { ...dbConnectionObj, systemUserId: () => 20 }); expect.fail(); } catch (actualError) { @@ -156,7 +156,7 @@ describe('getTemplateMethodologySpeciesRecord', () => { sinon.stub(survey_queries, 'getTemplateMethodologySpeciesRecordSQL').returns(SQL`something`); try { - await validate.getTemplateMethodologySpeciesRecord(1234, 1, 1, { + await validate.getTemplateMethodologySpeciesRecord(1, 1, { ...dbConnectionObj, systemUserId: () => 20 }); @@ -180,7 +180,7 @@ describe('getTemplateMethodologySpeciesRecord', () => { sinon.stub(survey_queries, 'getTemplateMethodologySpeciesRecordSQL').returns(SQL`something`); - const result = await validate.getTemplateMethodologySpeciesRecord(1234, 1, 1, { + const result = await validate.getTemplateMethodologySpeciesRecord(1, 1, { ...dbConnectionObj, query: mockQuery, systemUserId: () => 20 diff --git a/api/src/paths/xlsx/validate.ts b/api/src/paths/xlsx/validate.ts index 4748d4c2c5..35a0680768 100644 --- a/api/src/paths/xlsx/validate.ts +++ b/api/src/paths/xlsx/validate.ts @@ -108,12 +108,10 @@ export function getValidationSchema(): RequestHandler { const xlsxCsv = req['xlsx']; const template_id = xlsxCsv.workbook.rawWorkbook.Custprops.sims_template_id; - const species_id = xlsxCsv.workbook.rawWorkbook.Custprops.sims_species_id; - const csm_id = xlsxCsv.workbook.rawWorkbook.Custprops.sims_csm_id; + const field_method_id = xlsxCsv.workbook.rawWorkbook.Custprops.sims_csm_id; const templateMethodologySpeciesRecord = await getTemplateMethodologySpeciesRecord( - Number(species_id), - Number(csm_id), + Number(field_method_id), Number(template_id), connection ); @@ -188,17 +186,17 @@ export function validateXLSX(): RequestHandler { /** * Get a template_methodology_species record from the template_methodologies_species table * - * @param {number} surveyId + * @param {number} fieldMethodId + * @param {number} templateId * @param {IDBConnection} connection * @return {*} {Promise} */ export const getTemplateMethodologySpeciesRecord = async ( - speciesId: number, - surveyMethodology: number, + fieldMethodId: number, templateId: number, connection: IDBConnection ): Promise => { - const sqlStatement = queries.survey.getTemplateMethodologySpeciesRecordSQL(speciesId, surveyMethodology, templateId); + const sqlStatement = queries.survey.getTemplateMethodologySpeciesRecordSQL(fieldMethodId, templateId); if (!sqlStatement) { throw new HTTP400('Failed to build SQL get template methodology species record sql statement'); diff --git a/api/src/queries/codes/code-queries.test.ts b/api/src/queries/codes/code-queries.test.ts index 524e7dc7c2..8e6fb1df41 100644 --- a/api/src/queries/codes/code-queries.test.ts +++ b/api/src/queries/codes/code-queries.test.ts @@ -3,7 +3,6 @@ import { describe } from 'mocha'; import { getActivitySQL, getAdministrativeActivityStatusTypeSQL, - getCommonSurveyMethodologiesSQL, getFirstNationsSQL, getFundingSourceSQL, getInvestmentActionCategorySQL, @@ -31,13 +30,6 @@ describe('getFirstNationsSQL', () => { }); }); -describe('getCommonSurveyMethodologiesSQL', () => { - it('returns valid sql statement', () => { - const response = getCommonSurveyMethodologiesSQL(); - expect(response).to.not.be.null; - }); -}); - describe('getFundingSourceSQL', () => { it('returns valid sql statement', () => { const response = getFundingSourceSQL(); diff --git a/api/src/queries/codes/code-queries.ts b/api/src/queries/codes/code-queries.ts index 565d750691..ec17b35443 100644 --- a/api/src/queries/codes/code-queries.ts +++ b/api/src/queries/codes/code-queries.ts @@ -6,7 +6,7 @@ import { SQL, SQLStatement } from 'sql-template-strings'; * @returns {SQLStatement} sql query object */ export const getManagementActionTypeSQL = (): SQLStatement => - SQL`SELECT management_action_type_id as id, name from management_action_type;`; + SQL`SELECT management_action_type_id as id, name from management_action_type where record_end_date is null;`; /** * SQL query to fetch first nation codes. @@ -14,7 +14,7 @@ export const getManagementActionTypeSQL = (): SQLStatement => * @returns {SQLStatement} sql query object */ export const getFirstNationsSQL = (): SQLStatement => - SQL`SELECT first_nations_id as id, name from first_nations ORDER BY name ASC;`; + SQL`SELECT first_nations_id as id, name from first_nations where record_end_date is null ORDER BY name ASC;`; /** * SQL query to fetch funding source codes. @@ -22,7 +22,7 @@ export const getFirstNationsSQL = (): SQLStatement => * @returns {SQLStatement} sql query object */ export const getFundingSourceSQL = (): SQLStatement => - SQL`SELECT funding_source_id as id, name from funding_source ORDER BY name ASC;`; + SQL`SELECT funding_source_id as id, name from funding_source where record_end_date is null ORDER BY name ASC;`; /** * SQL query to fetch proprietor type codes. @@ -30,29 +30,55 @@ export const getFundingSourceSQL = (): SQLStatement => * @returns {SQLStatement} sql query object */ export const getProprietorTypeSQL = (): SQLStatement => - SQL`SELECT proprietor_type_id as id, name, is_first_nation from proprietor_type;`; + SQL`SELECT proprietor_type_id as id, name, is_first_nation from proprietor_type where record_end_date is null;`; /** * SQL query to fetch activity codes. * * @returns {SQLStatement} sql query object */ -export const getActivitySQL = (): SQLStatement => SQL`SELECT activity_id as id, name from activity;`; +export const getActivitySQL = (): SQLStatement => + SQL`SELECT activity_id as id, name from activity where record_end_date is null;`; /** - * SQL query to fetch common survey methodology codes. + * SQL query to fetch field method codes. * * @returns {SQLStatement} sql query object */ -export const getCommonSurveyMethodologiesSQL = (): SQLStatement => - SQL`SELECT common_survey_methodology_id as id, name from common_survey_methodology;`; +export const getFieldMethodsSQL = (): SQLStatement => + SQL`SELECT field_method_id as id, name, description from field_method where record_end_date is null;`; + +/** + * SQL query to fetch ecological season codes. + * + * @returns {SQLStatement} sql query object + */ +export const getEcologicalSeasonsSQL = (): SQLStatement => + SQL`SELECT ecological_season_id as id, name, description from ecological_season where record_end_date is null;`; + +/** + * SQL query to fetch vantage codes. + * + * @returns {SQLStatement} sql query object + */ +export const getVantageCodesSQL = (): SQLStatement => + SQL`SELECT vantage_id as id, name from vantage where record_end_date is null;`; + +/** + * SQL query to intended outcomes codes. + * + * @returns {SQLStatement} sql query object + */ +export const getIntendedOutcomesSQL = (): SQLStatement => + SQL`SELECT intended_outcome_id as id, name, description from intended_outcome where record_end_date is null;`; /** * SQL query to fetch project type codes. * * @returns {SQLStatement} sql query object */ -export const getProjectTypeSQL = (): SQLStatement => SQL`SELECT project_type_id as id, name from project_type;`; +export const getProjectTypeSQL = (): SQLStatement => + SQL`SELECT project_type_id as id, name from project_type where record_end_date is null;`; /** * SQL query to fetch investment action category codes. @@ -60,7 +86,7 @@ export const getProjectTypeSQL = (): SQLStatement => SQL`SELECT project_type_id * @returns {SQLStatement} sql query object */ export const getInvestmentActionCategorySQL = (): SQLStatement => - SQL`SELECT investment_action_category_id as id, funding_source_id as fs_id, name from investment_action_category ORDER BY name ASC;`; + SQL`SELECT investment_action_category_id as id, funding_source_id as fs_id, name from investment_action_category where record_end_date is null ORDER BY name ASC;`; /** * SQL query to fetch IUCN conservation action level 1 classification codes. @@ -68,7 +94,7 @@ export const getInvestmentActionCategorySQL = (): SQLStatement => * @returns {SQLStatement} sql query object */ export const getIUCNConservationActionLevel1ClassificationSQL = (): SQLStatement => - SQL`SELECT iucn_conservation_action_level_1_classification_id as id, name from iucn_conservation_action_level_1_classification;`; + SQL`SELECT iucn_conservation_action_level_1_classification_id as id, name from iucn_conservation_action_level_1_classification where record_end_date is null;`; /** * SQL query to fetch IUCN conservation action level 2 sub-classification codes. @@ -76,7 +102,7 @@ export const getIUCNConservationActionLevel1ClassificationSQL = (): SQLStatement * @returns {SQLStatement} sql query object */ export const getIUCNConservationActionLevel2SubclassificationSQL = (): SQLStatement => - SQL`SELECT iucn_conservation_action_level_2_subclassification_id as id, iucn_conservation_action_level_1_classification_id as iucn1_id, name from iucn_conservation_action_level_2_subclassification;`; + SQL`SELECT iucn_conservation_action_level_2_subclassification_id as id, iucn_conservation_action_level_1_classification_id as iucn1_id, name from iucn_conservation_action_level_2_subclassification where record_end_date is null;`; /** * SQL query to fetch IUCN conservation action level 3 sub-classification codes. @@ -84,21 +110,23 @@ export const getIUCNConservationActionLevel2SubclassificationSQL = (): SQLStatem * @returns {SQLStatement} sql query object */ export const getIUCNConservationActionLevel3SubclassificationSQL = (): SQLStatement => - SQL`SELECT iucn_conservation_action_level_3_subclassification_id as id, iucn_conservation_action_level_2_subclassification_id as iucn2_id, name from iucn_conservation_action_level_3_subclassification;`; + SQL`SELECT iucn_conservation_action_level_3_subclassification_id as id, iucn_conservation_action_level_2_subclassification_id as iucn2_id, name from iucn_conservation_action_level_3_subclassification where record_end_date is null;`; /** * SQL query to fetch system role codes. * * @returns {SQLStatement} sql query object */ -export const getSystemRolesSQL = (): SQLStatement => SQL`SELECT system_role_id as id, name from system_role;`; +export const getSystemRolesSQL = (): SQLStatement => + SQL`SELECT system_role_id as id, name from system_role where record_end_date is null;`; /** * SQL query to fetch project role codes. * * @returns {SQLStatement} sql query object */ -export const getProjectRolesSQL = (): SQLStatement => SQL`SELECT project_role_id as id, name from project_role;`; +export const getProjectRolesSQL = (): SQLStatement => + SQL`SELECT project_role_id as id, name from project_role where record_end_date is null;`; /** * SQL query to fetch administrative activity status type codes. @@ -106,7 +134,7 @@ export const getProjectRolesSQL = (): SQLStatement => SQL`SELECT project_role_id * @returns {SQLStatement} sql query object */ export const getAdministrativeActivityStatusTypeSQL = (): SQLStatement => - SQL`SELECT administrative_activity_status_type_id as id, name FROM administrative_activity_status_type;`; + SQL`SELECT administrative_activity_status_type_id as id, name FROM administrative_activity_status_type where record_end_date is null;`; /** * SQL query to fetch taxon codes. @@ -122,7 +150,7 @@ export const getTaxonsSQL = (): SQLStatement => wldtaxonomic_units WHERE tty_name = 'SPECIES' - and + and end_date is null ORDER BY name;`; diff --git a/api/src/queries/dwc/dwc-queries.ts b/api/src/queries/dwc/dwc-queries.ts index 484f241427..c7cf248696 100644 --- a/api/src/queries/dwc/dwc-queries.ts +++ b/api/src/queries/dwc/dwc-queries.ts @@ -14,12 +14,12 @@ export const getSurveyOccurrenceSubmissionSQL = (dataPackageId: number): SQLStat defaultLog.debug({ label: debugLabel, message: 'params', dataPackageId }); const sqlStatement: SQLStatement = SQL` - SELECT - os.* - from + SELECT + os.* + from occurrence_submission os - , occurrence_submission_data_package osdp - where + , occurrence_submission_data_package osdp + where osdp.data_package_id = ${dataPackageId} and os.occurrence_submission_id = osdp.occurrence_submission_id; `; @@ -45,11 +45,11 @@ export const getDataPackageSQL = (dataPackageId: number): SQLStatement => { defaultLog.debug({ label: debugLabel, message: 'params', dataPackageId }); const sqlStatement: SQLStatement = SQL` - SELECT - * - from + SELECT + * + from data_package - where + where data_package_id = ${dataPackageId}; `; @@ -74,9 +74,9 @@ export const getPublishedSurveyStatusSQL = (occurrenceSubmissionId: number): SQL defaultLog.debug({ label: debugLabel, message: 'params', occurrenceSubmissionId }); const sqlStatement: SQLStatement = SQL` - SELECT + SELECT * - from + from survey_status where survey_status = api_get_character_system_constant('OCCURRENCE_SUBMISSION_STATE_PUBLISHED') @@ -104,10 +104,10 @@ export const getSurveySQL = (surveyId: number): SQLStatement => { defaultLog.debug({ label: debugLabel, message: 'params', surveyId }); const sqlStatement: SQLStatement = SQL` - SELECT + SELECT survey_id, project_id, - common_survey_methodology_id, + field_method_id, uuid, name, objectives, @@ -123,7 +123,7 @@ export const getSurveySQL = (surveyId: number): SQLStatement => { update_date, update_user, revision_count - from + from survey where survey_id = ${surveyId}; `; @@ -149,7 +149,7 @@ export const getProjectSQL = (projectId: number): SQLStatement => { defaultLog.debug({ label: debugLabel, message: 'params', projectId }); const sqlStatement: SQLStatement = SQL` - SELECT + SELECT project_id, project_type_id, uuid, @@ -171,7 +171,7 @@ export const getProjectSQL = (projectId: number): SQLStatement => { update_date, update_user, revision_count - from + from project where project_id = ${projectId}; `; @@ -197,23 +197,23 @@ export const getSurveyFundingSourceSQL = (surveyId: number): SQLStatement => { defaultLog.debug({ label: debugLabel, message: 'params', surveyId }); const sqlStatement: SQLStatement = SQL` - select - a.*, - b.name investment_action_category_name, - c.name funding_source_name - from - project_funding_source a, - investment_action_category b, + select + a.*, + b.name investment_action_category_name, + c.name funding_source_name + from + project_funding_source a, + investment_action_category b, funding_source c - where + where project_funding_source_id in ( - select - project_funding_source_id - from - survey_funding_source - where + select + project_funding_source_id + from + survey_funding_source + where survey_id = ${surveyId}) - and b.investment_action_category_id = a.investment_action_category_id + and b.investment_action_category_id = a.investment_action_category_id and c.funding_source_id = b.funding_source_id; `; @@ -238,17 +238,17 @@ export const getProjectFundingSourceSQL = (projectId: number): SQLStatement => { defaultLog.debug({ label: debugLabel, message: 'params', projectId }); const sqlStatement: SQLStatement = SQL` - select - a.*, - b.name investment_action_category_name, - c.name funding_source_name - from - project_funding_source a, - investment_action_category b, + select + a.*, + b.name investment_action_category_name, + c.name funding_source_name + from + project_funding_source a, + investment_action_category b, funding_source c - where + where project_id = ${projectId} - and b.investment_action_category_id = a.investment_action_category_id + and b.investment_action_category_id = a.investment_action_category_id and c.funding_source_id = b.funding_source_id; `; @@ -281,8 +281,8 @@ export const getGeometryBoundingBoxSQL = ( // TODO: this only provides us with the bounding box of the first polygon const sqlStatement: SQLStatement = SQL` with envelope as ( - select - ST_Envelope(geography::geometry) geom + select + ST_Envelope(geography::geometry) geom from ` .append(targetTable) .append( @@ -290,12 +290,12 @@ export const getGeometryBoundingBoxSQL = ( where ` ) .append(primaryKeyName).append(SQL` = ${primaryKey}) - select + select st_xmax(geom), st_ymax(geom), st_xmin(geom), st_ymin(geom) - from + from envelope; `); @@ -327,11 +327,11 @@ export const getGeometryPolygonsSQL = ( const sqlStatement: SQLStatement = SQL` with polygons as ( - select - (st_dumppoints(g.geom)).* + select + (st_dumppoints(g.geom)).* from ( - select - geography::geometry as geom + select + geography::geometry as geom from ` .append(targetTable) .append( @@ -340,20 +340,20 @@ export const getGeometryPolygonsSQL = ( ) .append(primaryKeyName).append(SQL` = ${primaryKey}) as g), points as ( - select - path[1] polygon, - path[2] point, - jsonb_build_array(st_y(p.geom), st_x(p.geom)) points - from - polygons p - order by - path[1], + select + path[1] polygon, + path[2] point, + jsonb_build_array(st_y(p.geom), st_x(p.geom)) points + from + polygons p + order by + path[1], path[2]) - select + select json_agg(p.points) points - from - points p - group by + from + points p + group by polygon; `); @@ -383,12 +383,12 @@ export const getTaxonomicCoverageSQL = (surveyId: number, isFocal: boolean): SQL focalPredicate = 'and not b.is_focal'; } const sqlStatement: SQLStatement = SQL` - select - a.* - from - wldtaxonomic_units a, + select + a.* + from + wldtaxonomic_units a, study_species b - where + where a.wldtaxonomic_units_id = b.wldtaxonomic_units_id and b.survey_id = ${surveyId} `.append(focalPredicate); @@ -414,19 +414,19 @@ export const getProjectIucnConservationSQL = (projectId: number): SQLStatement = defaultLog.debug({ label: debugLabel, message: 'params', projectId }); const sqlStatement: SQLStatement = SQL` - select - a.name level_1_name, - b.name level_2_name, - c.name level_3_name - from - iucn_conservation_action_level_1_classification a, - iucn_conservation_action_level_2_subclassification b, - iucn_conservation_action_level_3_subclassification c, + select + a.name level_1_name, + b.name level_2_name, + c.name level_3_name + from + iucn_conservation_action_level_1_classification a, + iucn_conservation_action_level_2_subclassification b, + iucn_conservation_action_level_3_subclassification c, project_iucn_action_classification d - where + where d.project_id = ${projectId} - and c.iucn_conservation_action_level_3_subclassification_id = d.iucn_conservation_action_level_3_subclassification_id - and b.iucn_conservation_action_level_2_subclassification_id = c.iucn_conservation_action_level_2_subclassification_id + and c.iucn_conservation_action_level_3_subclassification_id = d.iucn_conservation_action_level_3_subclassification_id + and b.iucn_conservation_action_level_2_subclassification_id = c.iucn_conservation_action_level_2_subclassification_id and a.iucn_conservation_action_level_1_classification_id = b.iucn_conservation_action_level_1_classification_id; `; @@ -451,11 +451,11 @@ export const getProjectStakeholderPartnershipSQL = (projectId: number): SQLState defaultLog.debug({ label: debugLabel, message: 'params', projectId }); const sqlStatement: SQLStatement = SQL` - select - a.name - from + select + a.name + from stakeholder_partnership a - where + where a.project_id = ${projectId}; `; @@ -480,12 +480,12 @@ export const getProjectActivitySQL = (projectId: number): SQLStatement => { defaultLog.debug({ label: debugLabel, message: 'params', projectId }); const sqlStatement: SQLStatement = SQL` - select - a.name - from - activity a, + select + a.name + from + activity a, project_activity b - where + where b.project_id = ${projectId} and a.activity_id = b.activity_id; `; @@ -511,12 +511,12 @@ export const getProjectClimateInitiativeSQL = (projectId: number): SQLStatement defaultLog.debug({ label: debugLabel, message: 'params', projectId }); const sqlStatement: SQLStatement = SQL` - select - a.name - from - climate_change_initiative a, + select + a.name + from + climate_change_initiative a, project_climate_initiative b - where + where b.project_id = ${projectId} and a.climate_change_initiative_id = b.climate_change_initiative_id; `; @@ -542,12 +542,12 @@ export const getProjectFirstNationsSQL = (projectId: number): SQLStatement => { defaultLog.debug({ label: debugLabel, message: 'params', projectId }); const sqlStatement: SQLStatement = SQL` - select - a.name - from - first_nations a, + select + a.name + from + first_nations a, project_first_nation b - where + where b.project_id = ${projectId} and a.first_nations_id = b.first_nations_id; `; @@ -573,12 +573,12 @@ export const getProjectManagementActionsSQL = (projectId: number): SQLStatement defaultLog.debug({ label: debugLabel, message: 'params', projectId }); const sqlStatement: SQLStatement = SQL` - select - a.* - from - management_action_type a, + select + a.* + from + management_action_type a, project_management_actions b - where + where a.management_action_type_id = b.management_action_type_id and b.project_id = ${projectId}; `; @@ -604,15 +604,15 @@ export const getSurveyProprietorSQL = (surveyId: number): SQLStatement => { defaultLog.debug({ label: debugLabel, message: 'params', surveyId }); const sqlStatement: SQLStatement = SQL` - select - a.name proprietor_type_name, - b.name first_nations_name, - c.* - from - proprietor_type a, - first_nations b, + select + a.name proprietor_type_name, + b.name first_nations_name, + c.* + from + proprietor_type a, + first_nations b, survey_proprietor c - where + where c.survey_id = ${surveyId} and b.first_nations_id = c.first_nations_id and a.proprietor_type_id = c.proprietor_type_id; diff --git a/api/src/queries/project/project-view-queries.ts b/api/src/queries/project/project-view-queries.ts index 048c025ce4..6121cdd6aa 100644 --- a/api/src/queries/project/project-view-queries.ts +++ b/api/src/queries/project/project-view-queries.ts @@ -84,7 +84,7 @@ export const getProjectListSQL = ( p.name, p.start_date, p.end_date, - p.coordinator_agency_name, + p.coordinator_agency_name as coordinator_agency, p.publish_timestamp, pt.name as project_type, string_agg(DISTINCT pp.number, ', ') as permits_list diff --git a/api/src/queries/public/project-queries.ts b/api/src/queries/public/project-queries.ts index 1469bf2373..133033b989 100644 --- a/api/src/queries/public/project-queries.ts +++ b/api/src/queries/public/project-queries.ts @@ -109,7 +109,7 @@ export const getPublicProjectListSQL = (): SQLStatement | null => { p.name, p.start_date, p.end_date, - p.coordinator_agency_name, + p.coordinator_agency_name as coordinator_agency, pt.name as project_type, string_agg(DISTINCT pp.number, ', ') as permits_list from @@ -120,9 +120,6 @@ export const getPublicProjectListSQL = (): SQLStatement | null => { on p.project_id = pp.project_id where p.publish_timestamp is not null - `; - - sqlStatement.append(SQL` group by p.project_id, p.name, @@ -130,7 +127,7 @@ export const getPublicProjectListSQL = (): SQLStatement | null => { p.end_date, p.coordinator_agency_name, pt.name; - `); + `; defaultLog.debug({ label: 'getPublicProjectListSQL', diff --git a/api/src/queries/survey/survey-create-queries.ts b/api/src/queries/survey/survey-create-queries.ts index e849747431..a1f945b9bb 100644 --- a/api/src/queries/survey/survey-create-queries.ts +++ b/api/src/queries/survey/survey-create-queries.ts @@ -28,26 +28,30 @@ export const postSurveySQL = (projectId: number, survey: PostSurveyObject): SQLS INSERT INTO survey ( project_id, name, - objectives, + additional_details, + ecological_season_id, + intended_outcome_id, start_date, end_date, lead_first_name, lead_last_name, location_name, geojson, - common_survey_methodology_id, + field_method_id, geography ) VALUES ( ${projectId}, ${survey.survey_name}, - ${survey.survey_purpose}, + ${survey.additional_details}, + ${survey.ecological_season_id}, + ${survey.intended_outcome_id}, ${survey.start_date}, ${survey.end_date}, ${survey.biologist_first_name}, ${survey.biologist_last_name}, ${survey.survey_area_name}, ${JSON.stringify(survey.geometry)}, - ${survey.common_survey_methodology_id} + ${survey.field_method_id} `; if (survey.geometry && survey.geometry.length) { @@ -305,3 +309,37 @@ export const postAncillarySpeciesSQL = (speciesId: number, surveyId: number): SQ return sqlStatement; }; + +/** + * SQL query to insert a ancillary species row into the study_species table. + * + * @param {number} speciesId + * @param {number} surveyId + * @returns {SQLStatement} sql query object + */ +export const postVantageCodesSQL = (vantageCodeId: number, surveyId: number): SQLStatement | null => { + defaultLog.debug({ label: 'postVantageCodesSQL', message: 'params', vantageCodeId, surveyId }); + + if (!vantageCodeId || !surveyId) { + return null; + } + + const sqlStatement: SQLStatement = SQL` + INSERT INTO survey_vantage ( + vantage_id, + survey_id + ) VALUES ( + ${vantageCodeId}, + ${surveyId} + ) RETURNING survey_vantage_id as id; + `; + + defaultLog.debug({ + label: 'postVantageCodesSQL', + message: 'sql', + 'sqlStatement.text': sqlStatement.text, + 'sqlStatement.values': sqlStatement.values + }); + + return sqlStatement; +}; diff --git a/api/src/queries/survey/survey-delete-queries.ts b/api/src/queries/survey/survey-delete-queries.ts index 63123f6003..b7a103681e 100644 --- a/api/src/queries/survey/survey-delete-queries.ts +++ b/api/src/queries/survey/survey-delete-queries.ts @@ -211,3 +211,38 @@ export const deleteSurveySQL = (surveyId: number): SQLStatement | null => { return sqlStatement; }; + +/** + * SQL query to delete survey proprietor rows. + * + * @param {number} surveyId + * @param {number} surveyProprietorId + * @returns {SQLStatement} sql query object + */ +export const deleteSurveyVantageCodesSQL = (surveyId: number): SQLStatement | null => { + defaultLog.debug({ + label: 'deleteSurveyVantageCodeSQL', + message: 'params', + surveyId + }); + + if (!surveyId && surveyId !== 0) { + return null; + } + + const sqlStatement: SQLStatement = SQL` + DELETE + from survey_vantage + WHERE + survey_id = ${surveyId} + `; + + defaultLog.debug({ + label: 'deleteSurveyVantageCodeSQL', + message: 'sql', + 'sqlStatement.text': sqlStatement.text, + 'sqlStatement.values': sqlStatement.values + }); + + return sqlStatement; +}; diff --git a/api/src/queries/survey/survey-occurrence-queries.test.ts b/api/src/queries/survey/survey-occurrence-queries.test.ts index 4735e94c19..7d5991dcfe 100644 --- a/api/src/queries/survey/survey-occurrence-queries.test.ts +++ b/api/src/queries/survey/survey-occurrence-queries.test.ts @@ -245,25 +245,20 @@ describe('getOccurrenceSubmissionMessagesSQL', () => { }); describe('getTemplateMethodologySpeciesRecordSQL', () => { - it('returns null response when null speciesId provided', () => { - const response = getTemplateMethodologySpeciesRecordSQL((null as unknown) as number, 1, 1); - - expect(response).to.be.null; - }); it('returns null response when null methodologyId provided', () => { - const response = getTemplateMethodologySpeciesRecordSQL(1234, (null as unknown) as number, 1); + const response = getTemplateMethodologySpeciesRecordSQL((null as unknown) as number, 1); expect(response).to.be.null; }); it('returns null response when null templateId provided', () => { - const response = getTemplateMethodologySpeciesRecordSQL(1234, 1, (null as unknown) as number); + const response = getTemplateMethodologySpeciesRecordSQL(1, (null as unknown) as number); expect(response).to.be.null; }); it('returns non null response when valid params provided', () => { - const response = getTemplateMethodologySpeciesRecordSQL(1234, 1, 1); + const response = getTemplateMethodologySpeciesRecordSQL(1, 1); expect(response).to.not.be.null; }); diff --git a/api/src/queries/survey/survey-occurrence-queries.ts b/api/src/queries/survey/survey-occurrence-queries.ts index c82e07cbc8..47bb1ec868 100644 --- a/api/src/queries/survey/survey-occurrence-queries.ts +++ b/api/src/queries/survey/survey-occurrence-queries.ts @@ -513,25 +513,22 @@ export const getOccurrenceSubmissionMessagesSQL = (occurrenceSubmissionId: numbe /** * SQL query to get a template methodology species id. * - * @param {number} surveyId - * @param {string} source - * @param {string} inputKey + * @param {number} fieldMethodId + * @param {number} templateId * @return {*} {(SQLStatement | null)} */ export const getTemplateMethodologySpeciesRecordSQL = ( - speciesId: number, - methodologyId: number, + fieldMethodId: number, templateId: number ): SQLStatement | null => { defaultLog.debug({ label: 'getTemplateMethodologySpeciesRecordSQL', message: 'params', - speciesId, - methodologyId, + fieldMethodId, templateId }); - if (!speciesId || !methodologyId || !templateId) { + if (!fieldMethodId || !templateId) { return null; } @@ -540,9 +537,7 @@ export const getTemplateMethodologySpeciesRecordSQL = ( FROM template_methodology_species tms WHERE - tms.common_survey_methodology_id = ${methodologyId} - AND - tms.wldtaxonomic_units_id = ${speciesId} + tms.field_method_id = ${fieldMethodId} AND tms.template_id = ${templateId} ; diff --git a/api/src/queries/survey/survey-update-queries.test.ts b/api/src/queries/survey/survey-update-queries.test.ts index bb74c0ee5f..d21c6b13ce 100644 --- a/api/src/queries/survey/survey-update-queries.test.ts +++ b/api/src/queries/survey/survey-update-queries.test.ts @@ -12,10 +12,8 @@ import { describe('putSurveyDetailsSQL', () => { const surveyData: PutSurveyDetailsData = { name: 'test', - objectives: 'objectives', focal_species: [1, 2], ancillary_species: [3, 4], - common_survey_methodology_id: 1, start_date: '2020/04/04', end_date: '2020/05/05', lead_first_name: 'first', diff --git a/api/src/queries/survey/survey-update-queries.ts b/api/src/queries/survey/survey-update-queries.ts index f915acf139..d02be3abfc 100644 --- a/api/src/queries/survey/survey-update-queries.ts +++ b/api/src/queries/survey/survey-update-queries.ts @@ -1,5 +1,9 @@ import { SQL, SQLStatement } from 'sql-template-strings'; -import { PutSurveyDetailsData, PutSurveyProprietorData } from '../../models/survey-update'; +import { + PutSurveyDetailsData, + PutSurveyProprietorData, + PutSurveyPurposeAndMethodologyData +} from '../../models/survey-update'; import { getLogger } from '../../utils/logger'; import { queries } from '../queries'; @@ -133,14 +137,12 @@ export const putSurveyDetailsSQL = ( UPDATE survey SET name = ${data.name}, - objectives = ${data.objectives}, start_date = ${data.start_date}, end_date = ${data.end_date}, lead_first_name = ${data.lead_first_name}, lead_last_name = ${data.lead_last_name}, location_name = ${data.location_name}, geojson = ${JSON.stringify(data.geometry)}, - common_survey_methodology_id = ${data.common_survey_methodology_id}, geography = `; @@ -262,3 +264,52 @@ export const updateSurveyPublishStatusSQL = (surveyId: number, publish: boolean) return sqlStatement; }; + +/** + * SQL query to update a survey row. + * + * @param {number} projectId + * @param {number} surveyId + * @param {PutSurveyPurposeAndMethodologyData} data + * @returns {SQLStatement} sql query object + */ +export const putSurveyPurposeAndMethodologySQL = ( + surveyId: number, + data: PutSurveyPurposeAndMethodologyData | null, + revision_count: number +): SQLStatement | null => { + defaultLog.debug({ + label: 'putSurveyPurposeAndMethodologySQL', + message: 'params', + surveyId, + data, + revision_count + }); + + if (!surveyId || !data) { + return null; + } + + const sqlStatement = SQL` + UPDATE + survey + SET + field_method_id = ${data.field_method_id}, + additional_details = ${data.additional_details}, + ecological_season_id = ${data.ecological_season_id}, + intended_outcome_id = ${data.intended_outcome_id} + WHERE + survey_id = ${surveyId} + AND + revision_count = ${revision_count}; + `; + + defaultLog.debug({ + label: 'putSurveyPurposeAndMethodologySQL', + message: 'sql', + 'sqlStatement.text': sqlStatement.text, + 'sqlStatement.values': sqlStatement.values + }); + + return sqlStatement; +}; diff --git a/api/src/queries/survey/survey-view-queries.ts b/api/src/queries/survey/survey-view-queries.ts index 66dc564b07..0ba1b15309 100644 --- a/api/src/queries/survey/survey-view-queries.ts +++ b/api/src/queries/survey/survey-view-queries.ts @@ -145,7 +145,10 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n SELECT s.survey_id as id, s.name, - s.objectives, + s.additional_details, + s.field_method_id, + s.ecological_season_id, + s.intended_outcome_id, s.start_date, s.end_date, s.lead_first_name, @@ -156,7 +159,6 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n s.publish_timestamp as publish_date, per.number, per.type, - csm.name as common_survey_methodology, max(os.occurrence_submission_id) as occurrence_submission_id, max(sss.survey_summary_submission_id) as survey_summary_submission_id FROM @@ -166,9 +168,9 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n ON per.survey_id = s.survey_id LEFT OUTER JOIN - common_survey_methodology as csm + field_method as fm ON - csm.common_survey_methodology_id = s.common_survey_methodology_id + fm.field_method_id = s.field_method_id LEFT OUTER JOIN occurrence_submission as os ON @@ -182,7 +184,10 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n GROUP BY s.survey_id, s.name, - s.objectives, + s.field_method_id, + s.additional_details, + s.intended_outcome_id, + s.ecological_season_id, s.start_date, s.end_date, s.lead_first_name, @@ -192,8 +197,7 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n s.revision_count, s.publish_timestamp, per.number, - per.type, - csm.name; + per.type; `; defaultLog.debug({ @@ -212,7 +216,6 @@ export const getSurveyFundingSourcesDataForViewSQL = (surveyId: number): SQLStat message: 'params', surveyId }); - if (!surveyId) { return null; } diff --git a/api/src/queries/survey/survey-view-update-queries.ts b/api/src/queries/survey/survey-view-update-queries.ts index cf125e2437..36276e1a92 100644 --- a/api/src/queries/survey/survey-view-update-queries.ts +++ b/api/src/queries/survey/survey-view-update-queries.ts @@ -24,7 +24,7 @@ export const getSurveyDetailsForUpdateSQL = (surveyId: number): SQLStatement | n SELECT s.survey_id as id, s.name, - s.objectives, + s.additional_details, s.start_date, s.end_date, s.lead_first_name, @@ -32,7 +32,7 @@ export const getSurveyDetailsForUpdateSQL = (surveyId: number): SQLStatement | n s.location_name, s.geojson as geometry, s.revision_count, - s.common_survey_methodology_id, + s.field_method_id, s.publish_timestamp as publish_date, per.number, per.type, @@ -83,7 +83,7 @@ export const getSurveyDetailsForUpdateSQL = (surveyId: number): SQLStatement | n group by s.survey_id, s.name, - s.objectives, + s.additional_details, s.start_date, s.end_date, s.lead_first_name, @@ -91,7 +91,7 @@ export const getSurveyDetailsForUpdateSQL = (surveyId: number): SQLStatement | n s.location_name, s.geojson, s.revision_count, - s.common_survey_methodology_id, + s.field_method_id, s.publish_timestamp, per.number, per.type; @@ -158,3 +158,85 @@ export const getSurveyProprietorForUpdateSQL = (surveyId: number): SQLStatement return sqlStatement; }; + +/** + * SQL query to retrieve a survey_proprietor row. + * + * @param {number} surveyId + * @returns {SQLStatement} sql query object + */ +export const getSurveyPurposeAndMethodologyForUpdateSQL = (surveyId: number): SQLStatement | null => { + defaultLog.debug({ + label: 'getSurveyPurposeAndMethodologyForUpdateSQL', + message: 'params', + surveyId + }); + + if (!surveyId) { + return null; + } + + const sqlStatement = SQL` + SELECT + s.survey_id as id, + s.field_method_id, + s.additional_details, + s.ecological_season_id, + s.intended_outcome_id, + s.revision_count, + sv.vantage_id + FROM + survey s + LEFT OUTER JOIN + survey_vantage sv + ON + sv.survey_id = s.survey_id + WHERE + s.survey_id = ${surveyId}; + `; + + defaultLog.debug({ + label: 'getSurveyPurposeAndMethodologyForUpdateSQL', + message: 'sql', + 'sqlStatement.text': sqlStatement.text, + 'sqlStatement.values': sqlStatement.values + }); + + return sqlStatement; +}; + +/** + * SQL query to retrieve a survey_proprietor row. + * + * @param {number} surveyId + * @returns {SQLStatement} sql query object + */ +export const getSurveyVantageCodesSQL = (surveyId: number): SQLStatement | null => { + defaultLog.debug({ + label: 'getSurveyVantageCodesSQL', + message: 'params', + surveyId + }); + + if (!surveyId) { + return null; + } + + const sqlStatement = SQL` + SELECT + vantage_id + FROM + survey_vantage + WHERE + survey_id = ${surveyId}; + `; + + defaultLog.debug({ + label: 'getSurveyVantageCodesSQL', + message: 'sql', + 'sqlStatement.text': sqlStatement.text, + 'sqlStatement.values': sqlStatement.values + }); + + return sqlStatement; +}; diff --git a/api/src/services/code-service.test.ts b/api/src/services/code-service.test.ts index 537139d6b0..bbbed1f2ee 100644 --- a/api/src/services/code-service.test.ts +++ b/api/src/services/code-service.test.ts @@ -43,7 +43,10 @@ describe('CodeService', () => { 'project_roles', 'regional_offices', 'administrative_activity_status_type', - 'common_survey_methodologies' + 'ecological_seasons', + 'field_methods', + 'intended_outcomes', + 'vantage_codes' ); }); }); diff --git a/api/src/services/code-service.ts b/api/src/services/code-service.ts index 7c3e63dc57..ceca3793b0 100644 --- a/api/src/services/code-service.ts +++ b/api/src/services/code-service.ts @@ -39,7 +39,10 @@ export interface IAllCodeSets { project_roles: CodeSet; regional_offices: CodeSet; administrative_activity_status_type: CodeSet; - common_survey_methodologies: CodeSet; + field_methods: CodeSet<{ id: number; name: string; description: string }>; + ecological_seasons: CodeSet<{ id: number; name: string; description: string }>; + intended_outcomes: CodeSet<{ id: number; name: string; description: string }>; + vantage_codes: CodeSet; } export class CodeService extends DBService { @@ -67,7 +70,10 @@ export class CodeService extends DBService { project_roles, administrative_activity_status_type, species, - common_survey_methodologies + field_methods, + ecological_seasons, + intended_outcomes, + vantage_codes ] = await Promise.all([ await this.connection.query(queries.codes.getManagementActionTypeSQL().text), await this.connection.query(queries.codes.getFirstNationsSQL().text), @@ -83,7 +89,12 @@ export class CodeService extends DBService { await this.connection.query(queries.codes.getProjectRolesSQL().text), await this.connection.query(queries.codes.getAdministrativeActivityStatusTypeSQL().text), await this.connection.query(queries.codes.getTaxonsSQL().text), - await this.connection.query(queries.codes.getCommonSurveyMethodologiesSQL().text) + await this.connection.query(queries.codes.getFieldMethodsSQL().text), + await this.connection.query(queries.codes.getEcologicalSeasonsSQL().text), + + await this.connection.query(queries.codes.getIntendedOutcomesSQL().text), + + await this.connection.query(queries.codes.getVantageCodesSQL().text) ]); return { @@ -109,7 +120,11 @@ export class CodeService extends DBService { administrative_activity_status_type: (administrative_activity_status_type && administrative_activity_status_type.rows) || [], species: (species && species.rows) || [], - common_survey_methodologies: (common_survey_methodologies && common_survey_methodologies.rows) || [], + field_methods: (field_methods && field_methods.rows) || [], + ecological_seasons: (ecological_seasons && ecological_seasons.rows) || [], + intended_outcomes: (intended_outcomes && intended_outcomes.rows) || [], + vantage_codes: (vantage_codes && vantage_codes.rows) || [], + // TODO Temporarily hard coded list of code values below coordinator_agency, region, diff --git a/api/src/services/project-service.test.ts b/api/src/services/project-service.test.ts index fc6eae11ee..db178a2ab9 100644 --- a/api/src/services/project-service.test.ts +++ b/api/src/services/project-service.test.ts @@ -285,4 +285,179 @@ describe('ProjectService', () => { expect(mockQuery).to.have.been.calledOnce; }); }); + + describe('getPublicProjectsList', () => { + afterEach(() => { + sinon.restore(); + }); + + it('should throw a 400 error when no sql statement produced', async () => { + const mockDBConnection = getMockDBConnection(); + + sinon.stub(queries.public, 'getPublicProjectListSQL').returns(null); + + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getPublicProjectsList(); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to build SQL get statement'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); + + it('returns empty array if there are no rows', async () => { + const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + + sinon.stub(queries.public, 'getPublicProjectListSQL').returns(SQL`valid sql`); + + const projectService = new ProjectService(mockDBConnection); + + const result = await projectService.getPublicProjectsList(); + + expect(result).to.eql([]); + }); + + it('returns rows on success', async () => { + const mockRowObj = [ + { + id: 123, + name: 'Project 1', + start_date: '1900-01-01', + end_date: '2000-10-10', + coordinator_agency: 'Agency 1', + permits_list: '3, 100', + project_type: 'Aquatic Habitat' + }, + { + id: 456, + name: 'Project 2', + start_date: '1900-01-01', + end_date: '2000-12-31', + coordinator_agency: 'Agency 2', + permits_list: '1, 4', + project_type: 'Terrestrial Habitat' + } + ]; + const mockQueryResponse = ({ rows: mockRowObj } as unknown) as QueryResult; + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + + sinon.stub(queries.public, 'getPublicProjectListSQL').returns(SQL`valid sql`); + + const projectService = new ProjectService(mockDBConnection); + + const result = await projectService.getPublicProjectsList(); + + expect(result[0].id).to.equal(123); + expect(result[0].name).to.equal('Project 1'); + expect(result[0].completion_status).to.equal('Completed'); + + expect(result[1].id).to.equal(456); + expect(result[1].name).to.equal('Project 2'); + expect(result[1].completion_status).to.equal('Completed'); + }); + }); + + describe('getProjectList', () => { + afterEach(() => { + sinon.restore(); + }); + + it('should throw a 400 error when no sql statement produced', async () => { + const mockDBConnection = getMockDBConnection(); + + sinon.stub(queries.project, 'getProjectListSQL').returns(null); + + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getProjectList(true, 1, {}); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to build SQL select statement'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); + + it('returns empty array if there are no rows', async () => { + const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + + sinon.stub(queries.project, 'getProjectListSQL').returns(SQL`valid sql`); + + const projectService = new ProjectService(mockDBConnection); + + const result = await projectService.getProjectList(true, 1, {}); + + expect(result).to.eql([]); + }); + + it('returns rows on success', async () => { + const mockRowObj = [ + { + id: 123, + name: 'Project 1', + start_date: '1900-01-01', + end_date: '2200-10-10', + coordinator_agency: 'Agency 1', + publish_timestamp: '2010-01-01', + permits_list: '3, 100', + project_type: 'Aquatic Habitat' + }, + { + id: 456, + name: 'Project 2', + start_date: '1900-01-01', + end_date: '2000-12-31', + coordinator_agency: 'Agency 2', + publish_timestamp: '', + permits_list: '1, 4', + project_type: 'Terrestrial Habitat' + } + ]; + const mockQueryResponse = ({ rows: mockRowObj } as unknown) as QueryResult; + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + + sinon.stub(queries.project, 'getProjectListSQL').returns(SQL`valid sql`); + + const projectService = new ProjectService(mockDBConnection); + + const result = await projectService.getProjectList(true, 1, {}); + + expect(result[0].id).to.equal(123); + expect(result[0].name).to.equal('Project 1'); + expect(result[0].completion_status).to.equal('Active'); + expect(result[0].publish_status).to.equal('Published'); + + expect(result[1].id).to.equal(456); + expect(result[1].name).to.equal('Project 2'); + expect(result[1].completion_status).to.equal('Completed'); + expect(result[1].publish_status).to.equal('Unpublished'); + }); + }); + + describe('getPublicProjectById', () => { + afterEach(() => { + sinon.restore(); + }); + + it('should throw a 400 error when no sql statement produced', async () => { + const mockDBConnection = getMockDBConnection(); + + sinon.stub(queries.public, 'getPublicProjectSQL').returns(null); + sinon.stub(queries.public, 'getActivitiesByPublicProjectSQL').returns(null); + + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getPublicProjectById(1); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to build SQL get statement'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); + }); }); diff --git a/api/src/services/project-service.ts b/api/src/services/project-service.ts index 0d1dd43f57..5de1979c61 100644 --- a/api/src/services/project-service.ts +++ b/api/src/services/project-service.ts @@ -21,14 +21,14 @@ import { PutProjectData } from '../models/project-update'; import { - GetIUCNClassificationData, - GetPermitData, - GetProjectData, GetCoordinatorData, + GetFundingData, + GetIUCNClassificationData, GetLocationData, GetObjectivesData, GetPartnershipsData, - GetFundingData, + GetPermitData, + GetProjectData, IGetProject } from '../models/project-view'; import { GetPublicCoordinatorData, GetPublicProjectData } from '../models/public/project'; @@ -162,7 +162,7 @@ export class ProjectService extends DBService { name: row.name, start_date: row.start_date, end_date: row.end_date, - coordinator_agency: row.coordinator_agency_name, + coordinator_agency: row.coordinator_agency, completion_status: (row.end_date && moment(row.end_date).endOf('day').isBefore(moment()) && COMPLETION_STATUS.COMPLETED) || COMPLETION_STATUS.ACTIVE, diff --git a/app/README.md b/app/README.md index f9847b4a48..7976b303be 100644 --- a/app/README.md +++ b/app/README.md @@ -1,6 +1,13 @@ # bcgov/biohubbc/app -A standard React web-app for SIMS management activities. +## Technologies Used + +| Technology | Version | Website | Description | +| ---------- | ------- | ------------------------------------ | -------------------- | +| node | 14.x.x | https://nodejs.org/en/ | JavaScript Runtime | +| npm | 6.x.x | https://www.npmjs.com/ | Node Package Manager | + +
## Documenation diff --git a/app/src/components/fields/SelectWithSubtext.tsx b/app/src/components/fields/SelectWithSubtext.tsx new file mode 100644 index 0000000000..116973785d --- /dev/null +++ b/app/src/components/fields/SelectWithSubtext.tsx @@ -0,0 +1,107 @@ +import FormControl from '@material-ui/core/FormControl'; +import FormHelperText from '@material-ui/core/FormHelperText'; +import InputLabel from '@material-ui/core/InputLabel'; +import ListItemText from '@material-ui/core/ListItemText'; +import MenuItem from '@material-ui/core/MenuItem'; +import Select from '@material-ui/core/Select'; +import { ThemeProvider } from '@material-ui/styles'; +import { createMuiTheme } from '@material-ui/core'; +import { useFormikContext } from 'formik'; +import get from 'lodash-es/get'; +import React from 'react'; +import appTheme from 'themes/appTheme'; + +export interface ISelectWithSubtextFieldOption { + value: string | number; + label: string; + subText?: string; +} + +export interface ISelectWithSubtextField { + id: string; + name: string; + label: string; + options: ISelectWithSubtextFieldOption[]; + required?: boolean; +} + +const selectWithSubtextTheme = createMuiTheme({ + ...appTheme, + overrides: { + ...(appTheme?.overrides || {}), + MuiMenu: { + paper: { + minWidth: '72ch !important', + maxWidth: '72ch !important', + maxHeight: 500 + } + }, + MuiMenuItem: { + root: { + whiteSpace: 'break-spaces', + borderBottom: '1px solid rgba(0, 0, 0, 0.12)' + } + }, + MuiListItemText: { + primary: { + fontSize: '14px', + fontWeight: 700 + }, + secondary: { + marginTop: appTheme.spacing(0.5) + } + }, + MuiInputLabel: { + root: { + paddingRight: '20px' + } + } + } +}); + +const SelectWithSubtextField: React.FC = (props) => { + const { values, touched, errors, handleChange } = useFormikContext(); + + return ( + + + {props.label} + + {get(touched, props.name) && get(errors, props.name)} + + + ); +}; + +export default SelectWithSubtextField; diff --git a/app/src/constants/i18n.ts b/app/src/constants/i18n.ts index 0ecb599366..0f510e8e8d 100644 --- a/app/src/constants/i18n.ts +++ b/app/src/constants/i18n.ts @@ -91,6 +91,13 @@ export const EditSurveyProprietorI18N = { 'An error has occurred while attempting to edit your survey proprietor information, please try again. If the error persists, please contact your system administrator.' }; +export const EditSurveyPurposeAndMethodologyI18N = { + editTitle: 'Edit Survey Purpose and Methodology', + editErrorTitle: 'Error Editing Survey Purpose and Methodology', + editErrorText: + 'An error has occurred while attempting to edit your survey purpose and methodology information, please try again. If the error persists, please contact your system administrator.' +}; + export const EditLocationBoundaryI18N = { editTitle: 'Edit Project Location', editErrorTitle: 'Error Editing Project Location', diff --git a/app/src/features/surveys/CreateSurveyPage.test.tsx b/app/src/features/surveys/CreateSurveyPage.test.tsx index cd8ae13dd9..c9b721521a 100644 --- a/app/src/features/surveys/CreateSurveyPage.test.tsx +++ b/app/src/features/surveys/CreateSurveyPage.test.tsx @@ -8,6 +8,7 @@ import CreateSurveyPage from './CreateSurveyPage'; import { MemoryRouter, Router } from 'react-router'; import { createMemoryHistory } from 'history'; import { DialogContextProvider } from 'contexts/dialogContext'; +import { codes } from 'test-helpers/code-helpers'; const history = createMemoryHistory(); @@ -60,9 +61,7 @@ describe('CreateSurveyPage', () => { it('renders correctly when codes and project data are loaded', async () => { mockBiohubApi().project.getProjectForView.mockResolvedValue(getProjectForViewResponse); - mockBiohubApi().codes.getAllCodeSets.mockResolvedValue({ - species: [{ id: 1, name: 'species 1' }] - } as any); + mockBiohubApi().codes.getAllCodeSets.mockResolvedValue(codes); mockBiohubApi().survey.getSurveyPermits.mockResolvedValue([ { number: '123', type: 'Scientific' }, @@ -89,9 +88,7 @@ describe('CreateSurveyPage', () => { it('calls history.push() if the user clicks `Yes`', async () => { mockBiohubApi().project.getProjectForView.mockResolvedValue(getProjectForViewResponse); - mockBiohubApi().codes.getAllCodeSets.mockResolvedValue({ - species: [{ id: 1, name: 'species 1' }] - } as any); + mockBiohubApi().codes.getAllCodeSets.mockResolvedValue(codes); mockBiohubApi().survey.getSurveyPermits.mockResolvedValue([ { number: '123', type: 'Scientific' }, @@ -140,9 +137,7 @@ describe('CreateSurveyPage', () => { it('does nothing if the user clicks `No` or away from the dialog', async () => { mockBiohubApi().project.getProjectForView.mockResolvedValue(getProjectForViewResponse); - mockBiohubApi().codes.getAllCodeSets.mockResolvedValue({ - species: [{ id: 1, name: 'species 1' }] - } as any); + mockBiohubApi().codes.getAllCodeSets.mockResolvedValue(codes); mockBiohubApi().survey.getSurveyPermits.mockResolvedValue([ { number: '123', type: 'Scientific' }, diff --git a/app/src/features/surveys/CreateSurveyPage.tsx b/app/src/features/surveys/CreateSurveyPage.tsx index 09346c992e..86a6cb8d22 100644 --- a/app/src/features/surveys/CreateSurveyPage.tsx +++ b/app/src/features/surveys/CreateSurveyPage.tsx @@ -10,15 +10,23 @@ import { Theme } from '@material-ui/core/styles/createMuiTheme'; import makeStyles from '@material-ui/core/styles/makeStyles'; import Typography from '@material-ui/core/Typography'; import { IErrorDialogProps } from 'components/dialog/ErrorDialog'; +import HorizontalSplitFormComponent from 'components/fields/HorizontalSplitFormComponent'; +import { DATE_FORMAT, DATE_LIMIT } from 'constants/dateTimeFormats'; import { CreateSurveyI18N } from 'constants/i18n'; +import { DialogContext } from 'contexts/dialogContext'; import { Formik, FormikProps } from 'formik'; +import * as History from 'history'; +import { APIError } from 'hooks/api/useAxios'; import { useBiohubApi } from 'hooks/useBioHubApi'; import { IGetAllCodeSetsResponse } from 'interfaces/useCodesApi.interface'; import { IGetProjectForViewResponse } from 'interfaces/useProjectApi.interface'; import { ICreateSurveyRequest, SurveyFundingSources, SurveyPermits } from 'interfaces/useSurveyApi.interface'; +import moment from 'moment'; import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { Prompt, useHistory, useParams } from 'react-router'; import { validateFormFieldsAndReportCompletion } from 'utils/customValidation'; +import { getFormattedAmount, getFormattedDate, getFormattedDateRangeString } from 'utils/Utils'; +import yup from 'utils/YupSchema'; import AgreementsForm, { AgreementsInitialValues, AgreementsYupSchema } from './components/AgreementsForm'; import GeneralInformationForm, { GeneralInformationInitialValues, @@ -28,15 +36,11 @@ import ProprietaryDataForm, { ProprietaryDataInitialValues, ProprietaryDataYupSchema } from './components/ProprietaryDataForm'; +import PurposeAndMethodologyForm, { + PurposeAndMethodologyInitialValues, + PurposeAndMethodologyYupSchema +} from './components/PurposeAndMethodologyForm'; import StudyAreaForm, { StudyAreaInitialValues, StudyAreaYupSchema } from './components/StudyAreaForm'; -import HorizontalSplitFormComponent from 'components/fields/HorizontalSplitFormComponent'; -import * as History from 'history'; -import { APIError } from 'hooks/api/useAxios'; -import { DialogContext } from 'contexts/dialogContext'; -import yup from 'utils/YupSchema'; -import { DATE_FORMAT, DATE_LIMIT } from 'constants/dateTimeFormats'; -import moment from 'moment'; -import { getFormattedAmount, getFormattedDate, getFormattedDateRangeString } from 'utils/Utils'; const useStyles = makeStyles((theme: Theme) => ({ actionButton: { @@ -117,6 +121,7 @@ const CreateSurveyPage = () => { const [surveyInitialValues] = useState({ ...GeneralInformationInitialValues, ...StudyAreaInitialValues, + ...PurposeAndMethodologyInitialValues, ...ProprietaryDataInitialValues, ...AgreementsInitialValues }); @@ -158,6 +163,7 @@ const CreateSurveyPage = () => { ) }) .concat(StudyAreaYupSchema) + .concat(PurposeAndMethodologyYupSchema) .concat(ProprietaryDataYupSchema) .concat(AgreementsYupSchema); @@ -358,11 +364,6 @@ const CreateSurveyPage = () => { return { value: item.id, label: item.name }; }) || [] } - common_survey_methodologies={ - codes?.common_survey_methodologies?.map((item) => { - return { value: item.id, label: item.name }; - }) || [] - } permit_numbers={ surveyPermits?.map((item) => { return { value: item.number, label: `${item.number} - ${item.type}` }; @@ -389,6 +390,36 @@ const CreateSurveyPage = () => { + { + return { value: item.id, label: item.name, subText: item.description }; + }) || [] + } + field_methods={ + codes?.field_methods.map((item) => { + return { value: item.id, label: item.name, subText: item.description }; + }) || [] + } + ecological_seasons={ + codes?.ecological_seasons.map((item) => { + return { value: item.id, label: item.name, subText: item.description }; + }) || [] + } + vantage_codes={ + codes?.vantage_codes.map((item) => { + return { value: item.id, label: item.name }; + }) || [] + } + /> + }> + + + -
-
- -
- - -
-
-
@@ -1099,6 +938,11 @@ exports[`General Information Form renders correctly the filled component correct
+ + Species +
-
-
- -
-
- Recruitment -
- - - -
-

-

-
-
-
- -
- - -
-

- error on survey purpose field -

-
-
@@ -1997,6 +1716,11 @@ exports[`General Information Form renders correctly when errors exist 1`] = `
+ + Species +
-
-
- -
-
- Recruitment -
- - - -
-

-

-
= (props) => { refresh={refresh} /> + { + + + + } -
-

- survey purpose -

-
-
-
- Survey Methodology -
-
- method -
-
@@ -168,7 +145,7 @@ exports[`SurveyDetails renders correctly 1`] = `
+
+
+
+
+
+
+
+ Intended Outcome +
+
+ Intended Outcome 1 +
+
+
+
+ Additional Details +
+
+ details +
+
+
+
+ Field Method +
+
+ Recruitment +
+
+
+
+
+ Ecological Season +
+
+ Season 1 +
+
+
+
+ Vantage Code +
+
+ Vantage Code 1 +
+
+ Vantage Code 2 +
+
+
+
+
+ +