diff --git a/questionnaire/questionnaire/questionnaire.js b/questionnaire/questionnaire/questionnaire.js
index 11cd2b7d..3b4f0f62 100644
--- a/questionnaire/questionnaire/questionnaire.js
+++ b/questionnaire/questionnaire/questionnaire.js
@@ -264,36 +264,16 @@ function createQuestionnaire({
return createSection({id: sectionId, sectionDefinition});
}
- // TODO: remove this and implement allOf / describedBy properly
- function removeDeclarationSectionIds(sectionIds) {
- const sectionIdBlacklist = [
- 'p-applicant-declaration',
- 'p-applicant-declaration-deceased',
- 'p-mainapplicant-declaration-under-12',
- 'p-mainapplicant-declaration-under-12-deceased',
- 'p-mainapplicant-declaration-12-and-over',
- 'p-mainapplicant-declaration-12-and-over-deceased',
- 'p-rep-declaration-under-12',
- 'p-rep-declaration-under-12-deceased',
- 'p-rep-declaration-12-and-over',
- 'p-rep-declaration-12-and-over-deceased'
- ];
-
- return sectionIds.filter(sectionId => sectionIdBlacklist.includes(sectionId) === false);
- }
-
function getDataAttributes({
progress = getProgress(),
dataAttributeTransformer,
includeMetadata = true
} = {}) {
const allDataAttributes = [];
- // TODO: remove this and implement allOf / describedBy properly
- const sectionIds = removeDeclarationSectionIds(progress);
+ const sectionIds = progress;
sectionIds.forEach(sectionId => {
const sectionAnswers = getSectionAnswers(sectionId);
-
if (sectionAnswers !== undefined) {
const section = getSection(sectionId, false);
const sectionDataAttributes = section.getAttributesByData({
@@ -305,7 +285,6 @@ function createQuestionnaire({
allDataAttributes.push(...sectionDataAttributes);
}
});
-
return allDataAttributes;
}
@@ -380,8 +359,6 @@ function createQuestionnaire({
getOrderedAnswers,
getDataAttributes,
getNormalisedDetailsForAttribute,
- getProgress, // TODO: remove this when declaration is handled correctly
- getAnswers, // TODO: remove this when declaration is handled correctly
getPermittedActions
});
}
diff --git a/questionnaire/questionnaire/section/index.js b/questionnaire/questionnaire/section/index.js
index 79cc2ec7..a5bf53f2 100644
--- a/questionnaire/questionnaire/section/index.js
+++ b/questionnaire/questionnaire/section/index.js
@@ -1,5 +1,7 @@
'use strict';
+const pointer = require('jsonpointer');
+
function createSection({id, sectionDefinition}) {
function getId() {
return id;
@@ -50,37 +52,86 @@ function createSection({id, sectionDefinition}) {
return attributeSchema.meta.compositeId;
}
- function getAttributeLabel(valueSchemas, value) {
- const foundValueSchema = valueSchemas.find(valueSchema => valueSchema.const === value);
+ function getAttributeSchemaTitle(attributeSchemas, value) {
+ const foundAttributeSchema = attributeSchemas.find(
+ attributeSchema => attributeSchema.const === value
+ );
+
+ return foundAttributeSchema.title;
+ }
- return foundValueSchema.title;
+ function getAttributeSchemaTitles(attributeSchemas, values) {
+ return values.map(value => getAttributeSchemaTitle(attributeSchemas, value));
}
- function getAttributeLabels(valueSchemas, values) {
- return values.map(value => getAttributeLabel(valueSchemas, value));
+ function getAttributeSchemaDescribedBy(attributeSchemas, value, sectionSchema) {
+ const foundAttributeSchema = attributeSchemas.find(
+ attributeSchema => attributeSchema.const === value
+ );
+ const describedBy = foundAttributeSchema?.meta?.describedBy;
+ if (describedBy && '$ref' in describedBy) {
+ const describedByPointerValue = pointer.get(
+ sectionSchema,
+ foundAttributeSchema?.meta?.describedBy.$ref
+ );
+ if (describedByPointerValue === undefined) {
+ return '';
+ }
+ return describedByPointerValue;
+ }
+ return foundAttributeSchema?.meta?.describedBy;
}
function getValueLabel(attributeSchema, value) {
- const {oneOf, items} = attributeSchema;
+ const {oneOf, anyOf, items} = attributeSchema;
if (oneOf !== undefined) {
- return getAttributeLabel(oneOf, value);
+ return getAttributeSchemaTitle(oneOf, value);
+ }
+
+ if (anyOf !== undefined) {
+ return getAttributeSchemaTitle(anyOf, value);
}
if (items !== undefined) {
- return getAttributeLabels(items.anyOf, value);
+ return getAttributeSchemaTitles(items.anyOf, value);
}
return undefined;
}
- function createSimpleAttribute(attributeId, attributeSchema, data, includeMetadata) {
+ function getLabel(attributeSchema, value, sectionSchema) {
+ const {oneOf, anyOf, items} = attributeSchema;
+
+ if (oneOf !== undefined) {
+ return getAttributeSchemaDescribedBy(oneOf, value, sectionSchema);
+ }
+
+ if (anyOf !== undefined) {
+ return getAttributeSchemaDescribedBy(anyOf, value, sectionSchema);
+ }
+
+ if (items !== undefined) {
+ return getAttributeSchemaDescribedBy(items.anyOf, value, sectionSchema);
+ }
+
+ return attributeSchema.title;
+ }
+
+ function createSimpleAttribute(
+ attributeId,
+ attributeSchema,
+ data,
+ includeMetadata,
+ sectionSchema
+ ) {
const value = data[attributeId];
const valueLabel = getValueLabel(attributeSchema, value);
+ const label = getLabel(attributeSchema, value, sectionSchema);
const simpleAttribute = {
id: attributeId,
type: 'simple',
- label: attributeSchema.title
+ label
};
if (value !== undefined) {
@@ -139,7 +190,8 @@ function createSection({id, sectionDefinition}) {
attributeId,
questionSchema,
data,
- includeMetadata
+ includeMetadata,
+ schema
);
if (mapAttribute !== undefined) {
diff --git a/questionnaire/questionnaire/utils/taskRunner/tasks/test-fixtures/questionnaireCompleteForCheckYourAnswers.json b/questionnaire/questionnaire/utils/taskRunner/tasks/test-fixtures/questionnaireCompleteForCheckYourAnswers.json
index 31a21386..4952c4c7 100644
--- a/questionnaire/questionnaire/utils/taskRunner/tasks/test-fixtures/questionnaireCompleteForCheckYourAnswers.json
+++ b/questionnaire/questionnaire/utils/taskRunner/tasks/test-fixtures/questionnaireCompleteForCheckYourAnswers.json
@@ -6314,35 +6314,37 @@
},
"p-applicant-declaration": {
"schema": {
+ "$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
- "allOf": [
- {
- "properties": {
- "applicant-declaration": {
- "description": "
You have told us that you are ||/answers/p-applicant-enter-your-name/q-applicant-title|| ||/answers/p-applicant-enter-your-name/q-applicant-first-name|| ||/answers/p-applicant-enter-your-name/q-applicant-last-name|| and you are applying on behalf of yourself.
By submitting this application, you confirm that you understand the following:
- the information given in this application for compensation is true
- Criminal Injuries Compensation Authority (CICA) may share and receive information with the following parties for the purposes of processing this application for compensation or verifying information provided:
- police, prosecutors and ACRO Criminal Records Office, including for the purposes of obtaining a report of the crime and a record of any criminal convictions you may have
- medical organisations, practitioners, and police medical staff to obtain medical evidence - including medical records and expert reports. CICA will let you know if this is required
- any other individuals or organisations where necessary to process this application
- any representative appointed to act for you in the course of this application
- CICA must be notified immediately of any change in circumstances relevant to this application, including any change of address and information about any other claim or proceedings which may give rise to a separate award or payment in respect of your injuries
Providing wrong or misleading information
If untrue or misleading information is deliberately provided, compensation may be refused and the person(s) responsible may be prosecuted.
Read our privacy notice to see how we use your data (opens in new tab).
Information about appointing a legal or another representative
It is not necessary to appoint a legal or other representative to act on a victim’s behalf. If a representative is appointed at any stage, please be aware that:
- CICA cannot meet their costs
- we will only communicate directly with any appointed representative
If we make an award, we will pay it only to the victim or their legal representative. This is unless the application has been made on behalf of:
- an adult who cannot manage their own financial affairs
- a child who is under 18 years of age
It is our general policy to put an award for a child in an interest-earning deposit account until they reach the age of 18.
If a monetary award is to be made and there is a dispute about outstanding legal fees, it is our policy to retain the disputed amount until the dispute has been resolved.
If it is decided that a representative’s services are no longer required, CICA must be notified in writing as soon as possible.
"
- }
- }
+ "required": ["q-applicant-declaration"],
+ "propertyNames": {
+ "enum": ["q-applicant-declaration"]
+ },
+ "properties": {
+ "applicant-declaration": {
+ "title": "Declaration",
+ "description": " You have told us that you are ||/answers/p-applicant-enter-your-name/q-applicant-title|| ||/answers/p-applicant-enter-your-name/q-applicant-first-name|| ||/answers/p-applicant-enter-your-name/q-applicant-last-name|| and you are applying on behalf of yourself.
By submitting this application, you confirm that you understand the following:
- the information given in this application for compensation is true
- Criminal Injuries Compensation Authority (CICA) may share and receive information with the following parties for the purposes of processing this application for compensation or verifying information provided:
- police, prosecutors and ACRO Criminal Records Office, including for the purposes of obtaining a report of the crime and a record of any criminal convictions you may have
- medical organisations, practitioners, and police medical staff to obtain medical evidence - including medical records and expert reports. CICA will let you know if this is required
- any other individuals or organisations where necessary to process this application
- any representative appointed to act for you in the course of this application
- CICA must be notified immediately of any change in circumstances relevant to this application, including any change of address and information about any other claim or proceedings which may give rise to a separate award or payment in respect of your injuries
Providing wrong or misleading information
If untrue or misleading information is deliberately provided, compensation may be refused and the person(s) responsible may be prosecuted.
Read our privacy notice to see how we use your data (opens in new tab).
Information about appointing a legal or another representative
It is not necessary to appoint a legal or other representative to act on a victim’s behalf. If a representative is appointed at any stage, please be aware that:
- CICA cannot meet their costs
- we will only communicate directly with any appointed representative
If we make an award, we will pay it only to the victim or their legal representative. This is unless the application has been made on behalf of:
- an adult who cannot manage their own financial affairs
- a child who is under 18 years of age
It is our general policy to put an award for a child in an interest-earning deposit account until they reach the age of 18.
If a monetary award is to be made and there is a dispute about outstanding legal fees, it is our policy to retain the disputed amount until the dispute has been resolved.
If it is decided that a representative’s services are no longer required, CICA must be notified in writing as soon as possible.
"
},
- {
- "properties": {
- "q-applicant-declaration": {
- "type": "string",
+ "q-applicant-declaration": {
+ "title": "Declaration",
+ "type": "string",
+ "meta": {
+ "classifications": {
+ "theme": "declaration"
+ }
+ },
+ "anyOf": [
+ {
+ "title": "I have read and understood the declaration",
"const": "i-agree",
- "title": "I have read and understood the declaration"
+ "meta": {
+ "describedBy": {
+ "$ref": "/properties/applicant-declaration/description"
+ }
+ }
}
- }
- }
- ],
- "title": "Declaration",
- "$schema": "http://json-schema.org/draft-07/schema#",
- "required": ["q-applicant-declaration"],
- "errorMessage": {
- "required": {
- "q-applicant-declaration": "Select that you have read and understood"
+ ]
}
- },
- "propertyNames": {
- "enum": ["q-applicant-declaration"]
}
}
},
@@ -17098,6 +17100,9 @@
"other-compensation": {
"title": "Other compensation"
},
+ "declaration": {
+ "title": "Declaration"
+ },
"main-applicant-details": {
"title": null
}
diff --git a/questionnaire/questionnaire/utils/taskRunner/tasks/transformAndUpload/index.js b/questionnaire/questionnaire/utils/taskRunner/tasks/transformAndUpload/index.js
index 0a4eac6c..6c08d8ee 100644
--- a/questionnaire/questionnaire/utils/taskRunner/tasks/transformAndUpload/index.js
+++ b/questionnaire/questionnaire/utils/taskRunner/tasks/transformAndUpload/index.js
@@ -74,50 +74,13 @@ function flattenAnswers(answers) {
}
/**
- * Parses the relevant declaration information from a questionnaire using its progress
- * and application type to determine which declaration has been answered.
- * @param {questionnaire} questionnaire - The raw questionnaire object
+ * Parses the relevant declaration theme data from the given themes array.
+ * @param themeContent - The themed output produced by transformQuestionnaire
* @returns a declaration object following the format of a standard question.
*/
-function getDeclaration(questionnaire) {
- const progress = questionnaire.getProgress();
- const declarationSectionAndQuestionIds = {
- 'p-applicant-declaration': 'q-applicant-declaration',
- 'p-applicant-declaration-deceased': 'q-applicant-declaration',
- 'p-mainapplicant-declaration-under-12': 'q-mainapplicant-declaration',
- 'p-mainapplicant-declaration-under-12-deceased': 'q-mainapplicant-declaration',
- 'p-mainapplicant-declaration-12-and-over': 'q-mainapplicant-declaration',
- 'p-mainapplicant-declaration-12-and-over-deceased': 'q-mainapplicant-declaration',
- 'p-rep-declaration-under-12': 'q-rep-declaration',
- 'p-rep-declaration-under-12-deceased': 'q-rep-declaration',
- 'p-rep-declaration-12-and-over': 'q-rep-declaration',
- 'p-rep-declaration-12-and-over-deceased': 'q-rep-declaration'
- };
- const declarationSectionIds = Object.keys(declarationSectionAndQuestionIds);
- const declarationSectionId = progress.find(sectionId =>
- declarationSectionIds.includes(sectionId)
- );
-
- if (declarationSectionId !== undefined) {
- const section = questionnaire.getSection(declarationSectionId);
- const sectionSchema = section.getSchema();
- const sectionAnswers = questionnaire.getAnswers()[declarationSectionId];
- const questionId = declarationSectionAndQuestionIds[declarationSectionId];
- const descriptionId = questionId.replace('q-', '');
- const {description} = sectionSchema.allOf[0].properties[descriptionId];
- const value = sectionAnswers[questionId];
- const valueLabel = sectionSchema.allOf[1].properties[questionId].title;
-
- return {
- type: 'simple',
- id: declarationSectionId,
- label: description,
- value,
- valueLabel
- };
- }
-
- return undefined;
+function getDeclaration(themeContent) {
+ return themeContent.filter(themeResource => themeResource.id === 'declaration')?.[0]
+ ?.values?.[0];
}
/**
@@ -125,20 +88,38 @@ function getDeclaration(questionnaire) {
* @param {questionnaire} questionnaire - The raw questionnaire object
* @returns A themed object with attached metadata and declaration content.
*/
-function transformQuestionnaire(questionnaire) {
+function transformQuestionnaire(questionnaire, answers) {
+ console.log({
+ a: questionnaire // ,
+ // a: questionnaire.sections['p-applicant-declaration'],
+ // b: answers['p-applicant-declaration']
+ });
const section = questionnaire.getSection('p--check-your-answers');
const sectionSchema = section.getSchema();
const themeContent =
sectionSchema.properties['p-check-your-answers'].properties.summaryInfo.summaryStructure;
flattenAnswers(themeContent);
-
+ console.log(
+ JSON.stringify(
+ {
+ meta: {
+ caseReference: answers.system['case-reference'],
+ funeralReference: answers.system['secondary-reference']
+ },
+ themes: themeContent,
+ declaration: getDeclaration(themeContent)
+ },
+ null,
+ 4
+ )
+ );
return {
meta: {
- caseReference: questionnaire.getAnswers().system['case-reference'],
- funeralReference: questionnaire.getAnswers().system['secondary-reference']
+ caseReference: answers.system['case-reference'],
+ funeralReference: answers.system['secondary-reference']
},
themes: themeContent,
- declaration: getDeclaration(questionnaire)
+ declaration: getDeclaration(themeContent)
};
}
@@ -156,7 +137,7 @@ async function transformAndUpload({questionnaireDef, logger}) {
const s3Directory = process.env.S3_DIRECTORY ? process.env.S3_DIRECTORY : 'application_json';
logger.info(`Transforming questionnaire with id: ${questionnaire.getId()}`);
- const output = transformQuestionnaire(questionnaire);
+ const output = transformQuestionnaire(questionnaire, questionnaireDef.answers);
// Populate the dateSubmitted from the database
const db = createQuestionnaireDAL({logger});
diff --git a/questionnaire/questionnaire/utils/taskRunner/tasks/transformAndUpload/index.test.js b/questionnaire/questionnaire/utils/taskRunner/tasks/transformAndUpload/index.test.js
index 68bb799e..72055509 100644
--- a/questionnaire/questionnaire/utils/taskRunner/tasks/transformAndUpload/index.test.js
+++ b/questionnaire/questionnaire/utils/taskRunner/tasks/transformAndUpload/index.test.js
@@ -17,16 +17,9 @@ const loggerMock = {
};
describe('Transform and Upload task', () => {
- // Arrange
- const questionnaireObj = questionnaire({questionnaireDefinition: questionnaireFixture});
-
- // Act
- let result;
-
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
- result = transformQuestionnaire(questionnaireObj);
});
it('Should error if input parameters are not arrays', () => {
@@ -36,18 +29,40 @@ describe('Transform and Upload task', () => {
});
it('Should return undefined if declaration does not exist', () => {
- const questionnaireObjNoDeclaration = questionnaire({
+ const questionnaireSingleton = questionnaire({
questionnaireDefinition: questionnaireFixtureNoDeclaration
});
- expect(getDeclaration(questionnaireObjNoDeclaration)).toBeUndefined();
+
+ const transformation = transformQuestionnaire(
+ questionnaireSingleton,
+ questionnaireFixtureNoDeclaration.answers
+ );
+ expect(getDeclaration(transformation.themes)).toBeUndefined();
});
it('Should transform correctly and include the correct CRN in the metadata.', () => {
- expect(result.meta.caseReference).toBe('19\\751194');
+ const questionnaireSingleton = questionnaire({
+ questionnaireDefinition: questionnaireFixture
+ });
+
+ const transformation = transformQuestionnaire(
+ questionnaireSingleton,
+ questionnaireFixture.answers
+ );
+ expect(transformation.meta.caseReference).toBe('19\\751194');
});
it('Should transform correctly with amalgamated injury codes and labels.', () => {
- const injuries = result.themes
+ const questionnaireSingleton = questionnaire({
+ questionnaireDefinition: questionnaireFixture
+ });
+
+ const transformation = transformQuestionnaire(
+ questionnaireSingleton,
+ questionnaireFixture.answers
+ );
+
+ const injuries = transformation.themes
.find(theme => {
return theme.id === 'injuries';
})
@@ -76,15 +91,37 @@ describe('Transform and Upload task', () => {
]);
});
- it('Should transform correctly with the correct declaration.', () => {
- expect(result.declaration.id).toBe('p-applicant-declaration');
- expect(result.declaration.label).toContain('');
- expect(result.declaration.value).toBe('i-agree');
- expect(result.declaration.valueLabel).toBe('I have read and understood the declaration');
+ it.only('Should transform correctly with the correct declaration.', () => {
+ const questionnaireSingleton = questionnaire({
+ questionnaireDefinition: questionnaireFixture
+ });
+
+ const transformation = transformQuestionnaire(
+ questionnaireSingleton,
+ questionnaireFixture.answers
+ );
+ console.log(JSON.stringify(transformation.themes, null, 4));
+ console.log({transformation});
+
+ expect(transformation.declaration.id).toBe('p-applicant-declaration');
+ expect(transformation.declaration.label).toContain('
');
+ expect(transformation.declaration.value).toBe('i-agree');
+ expect(transformation.declaration.valueLabel).toBe(
+ 'I have read and understood the declaration'
+ );
});
it('Should keep hideOnSummary flags.', () => {
- const newOrExistingQuestion = result.themes
+ const questionnaireSingleton = questionnaire({
+ questionnaireDefinition: questionnaireFixture
+ });
+
+ const transformation = transformQuestionnaire(
+ questionnaireSingleton,
+ questionnaireFixture.answers
+ );
+
+ const newOrExistingQuestion = transformation.themes
.find(theme => {
return theme.id === 'about-application';
})
@@ -103,7 +140,7 @@ describe('Transform and Upload task', () => {
uploadFile: () => 'Success'
}));
- result = await transformAndUpload({
+ const result = await transformAndUpload({
questionnaireDef: questionnaireFixture,
logger: loggerMock
});