Exemple #1
0
def post_household_composition(routing_path, schema, metadata, answer_store,
                               **kwargs):
    group_id = kwargs['group_id']

    if _household_answers_changed(answer_store, schema):
        _remove_repeating_on_household_answers(answer_store, schema)

    disable_mandatory = any(x in request.form for x in [
        'action[add_answer]', 'action[remove_answer]', 'action[save_sign_out]'
    ])

    current_location = Location(group_id, 0, 'household-composition')

    block = _get_block_json(current_location, schema, answer_store, metadata)

    form = post_form_for_location(schema,
                                  block,
                                  current_location,
                                  answer_store,
                                  metadata,
                                  request.form,
                                  disable_mandatory=disable_mandatory)

    form.validate(
    )  # call validate here to keep errors in the form object on the context
    context = _get_context(routing_path, block, current_location, schema, form)

    if 'action[add_answer]' in request.form:
        form.household.append_entry()

        return _render_page(block['type'], context, current_location, schema,
                            answer_store, metadata, routing_path)

    if 'action[remove_answer]' in request.form:
        index_to_remove = int(request.form.get('action[remove_answer]'))
        form.remove_person(index_to_remove)

        return _render_page(block['type'], context, current_location, schema,
                            answer_store, metadata, routing_path)

    if 'action[save_sign_out]' in request.form:
        response = _save_sign_out(routing_path, current_location, form, schema,
                                  answer_store, metadata)
        remove_empty_household_members_from_answer_store(answer_store, schema)

        return response

    if form.validate():
        questionnaire_store = get_questionnaire_store(current_user.user_id,
                                                      current_user.user_ik)
        update_questionnaire_store_with_answer_data(questionnaire_store,
                                                    current_location,
                                                    form.serialise(), schema)

        metadata = get_metadata(current_user)
        next_location = path_finder.get_next_location(
            current_location=current_location)

        return redirect(next_location.url(metadata))

    return _render_page(block['type'], context, current_location, schema,
                        answer_store, metadata, routing_path)
    def test_get_first_incomplete_location_in_survey_started_with_repeat(self):
        schema = load_schema_from_params('test', 'navigation')

        completed_blocks = [
            Location('property-details', 0, 'insurance-type'),
            Location('property-details', 0, 'insurance-address'),
            Location('multiple-questions-group', 0, 'household-composition'),
            Location('extra-cover', 1, 'extra-cover-block'),
            Location('repeating-group', 0, 'repeating-block-1'),
            Location('repeating-group', 1, 'repeating-block-1'),
            Location('repeating-group', 0, 'repeating-block-2'),
            Location('repeating-group', 1, 'repeating-block-2'),
            Location('extra-cover', 0, 'extra-cover-block'),
            Location('extra-cover-items-group', 0, 'extra-cover-items'),
            Location('extra-cover-items-group', 0, 'extra-cover-items-radio'),
        ]

        expected_location = Location('extra-cover-items-group', 1, 'extra-cover-items')
        routing_path = [
            Location('multiple-questions-group', 0, 'household-composition'),
            Location('repeating-group', 0, 'repeating-block-1'),
            Location('repeating-group', 1, 'repeating-block-1'),
            Location('repeating-group', 0, 'repeating-block-2'),
            Location('repeating-group', 1, 'repeating-block-2'),
            Location('extra-cover', 0, 'extra-cover-block'),
            Location('extra-cover-items-group', 0, 'extra-cover-items'),
            Location('extra-cover-items-group', 0, 'extra-cover-items-radio'),
            expected_location,
        ]

        answer_store = AnswerStore()
        answer_store.add_or_update(Answer(
            answer_instance=0,
            answer_id='first-name',
            value='Person1'
        ))
        answer_store.add_or_update(Answer(
            answer_instance=1,
            answer_id='first-name',
            value='Person2'
        ))
        answer_store.add_or_update(Answer(
            answer_instance=0,
            answer_id='extra-cover-answer',
            value=2
        ))

        progress = Completeness(
            schema, answer_store, completed_blocks, routing_path, metadata={})

        with patch('app.questionnaire.path_finder.evaluate_goto', return_value=True):
            invalid_location = progress.get_first_incomplete_location_in_survey()
        self.assertEqual(expected_location, invalid_location)
    def test_build_view_context_for_calculation_summary(self):
        # Given
        schema = load_schema_from_params('test', 'calculated_summary')
        block = schema.get_block('currency-total-playback')
        metadata = {
            'tx_id': '12345678-1234-5678-1234-567812345678',
            'collection_exercise_sid': '789',
            'form_type': 'calculated_summary',
            'eq_id': 'test',
        }
        answers = [
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'first-number-answer',
                'value': 1
            },
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'second-number-answer',
                'value': 2
            },
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'third-number-answer',
                'value': 4
            },
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'fourth-number-answer',
                'value': 6
            },
        ]
        schema_context = {
            'answers': answers,
            'group_instance': 0,
            'metadata': metadata
        }
        current_location = Location('group', 0, 'currency-total-playback')

        # When
        with self._application.test_request_context():
            view_context = build_view_context(block['type'],
                                              metadata,
                                              schema,
                                              AnswerStore(answers),
                                              schema_context,
                                              block,
                                              current_location,
                                              form=None)

        # Then
        self.assertTrue('summary' in view_context)
        self.assertTrue('calculated_question' in view_context['summary'])
        self.assertEqual(
            view_context['summary']['title'],
            'We calculate the total of currency values entered to be £13.00. Is this correct?'
        )
    def build_path(self):
        """
        Visits all the blocks from a location forwards and returns path
        taken given a list of answers.

        :param blocks: A list containing all block content in the survey
        :param this_location: The location to visit, represented as a dict
        :return: A list of locations followed through the survey
        """
        this_location = None

        blocks = []
        path = []
        block_index = 0
        first_groups = self._get_first_group_in_section()

        for group in self.schema.groups:
            first_block_in_group = self.schema.get_first_block_id_for_group(
                group['id'])
            if not this_location:
                this_location = Location(group['id'], 0, first_block_in_group)

            no_of_repeats = get_number_of_repeats(group, self.schema, path,
                                                  self.answer_store)

            first_group_instance_index = None
            for group_instance in range(0, no_of_repeats):

                if 'skip_conditions' in group:
                    group_instance_id = get_group_instance_id(
                        self.schema, self.answer_store,
                        Location(group['id'], group_instance,
                                 first_block_in_group))

                    if evaluate_skip_conditions(group['skip_conditions'],
                                                self.schema,
                                                self.metadata,
                                                self.answer_store,
                                                group_instance,
                                                group_instance_id,
                                                routing_path=path):
                        continue

                group_blocks = list(
                    self._build_blocks_for_group(group, group_instance))
                blocks += group_blocks

                if group_blocks and first_group_instance_index is None:
                    # get the group instance of the first instance of a block in this group that has not been skipped
                    first_group_instance_index = group_blocks[0][
                        'group_instance']

            all_blocks_skipped = first_group_instance_index is None

            if not all_blocks_skipped:
                if group['id'] in first_groups:
                    this_location = Location(group['id'],
                                             first_group_instance_index,
                                             first_block_in_group)

                if blocks:
                    path, block_index = self._build_path_within_group(
                        blocks, block_index, this_location, path)

        return RoutingPath(path)
    def test_repeating_skipped_section(self):
        schema = load_schema_from_params('test', 'navigation_confirmation')

        completed_blocks = [
            Location('property-details', 0, 'insurance-type'),
            Location('property-details', 0, 'insurance-address'),
            Location('property-details', 0, 'property-interstitial'),
            Location('house-details', 0, 'house-type'),
            Location('multiple-questions-group', 0, 'household-composition'),
            Location('repeating-group', 0, 'repeating-block-1'),
            Location('repeating-group', 0, 'repeating-block-2'),
            Location('extra-cover', 0, 'extra-cover-block'),
            Location('extra-cover', 0, 'extra-cover-interstitial'),
            Location('payment-details', 0, 'credit-card'),
            Location('payment-details', 0, 'expiry-date'),
            Location('payment-details', 0, 'security-code'),
            Location('payment-details', 0, 'security-code-interstitial'),
            Location('extra-cover-items-group', 0, 'extra-cover-items'),
        ]

        routing_path = [
            Location('property-details', 0, 'insurance-type'),
            Location('property-details', 0, 'insurance-address'),
            Location('property-details', 0, 'property-interstitial'),
            Location('house-details', 0, 'house-type'),
            Location('multiple-questions-group', 0, 'household-composition'),
            Location('repeating-group', 0, 'repeating-block-1'),
            Location('repeating-group', 0, 'repeating-block-2'),
            Location('extra-cover', 0, 'extra-cover-block'),
            Location('extra-cover', 0, 'extra-cover-interstitial'),
            Location('payment-details', 0, 'credit-card'),
            Location('payment-details', 0, 'expiry-date'),
            Location('payment-details', 0, 'security-code'),
            Location('payment-details', 0, 'security-code-interstitial'),
            Location('extra-cover-items-group', 0, 'extra-cover-items'),
            Location('confirmation-group', 0, 'confirmation'),
        ]


        progress = Completeness(
            schema, AnswerStore(), completed_blocks, routing_path, metadata={})
        progress_value = progress.get_state_for_section(
            'household-full-names-section')
        self.assertEqual(Completeness.SKIPPED, progress_value)
    def test_serialise_answers(self):

        form = generate_household_composition_form(self.block_json, {
            'household-0-first-name': 'Joe',
            'household-0-last-name': 'Bloggs',
            'household-1-first-name': 'Bob',
            'household-1-last-name': 'Seymour',
        }, error_messages=self.error_messages)

        location = Location('who-lives-here', 0, 'household-composition')

        answers = form.serialise(location)

        expected_answers = [
            {
                'group_id': 'who-lives-here',
                'group_instance': 0,
                'block_id': 'household-composition',
                'answer_id': 'first-name',
                'answer_instance': 0,
                'value': 'Joe'
            }, {
                'group_id': 'who-lives-here',
                'group_instance': 0,
                'block_id': 'household-composition',
                'answer_id': 'middle-names',
                'answer_instance': 0,
                'value': ''
            }, {
                'group_id': 'who-lives-here',
                'group_instance': 0,
                'block_id': 'household-composition',
                'answer_id': 'last-name',
                'answer_instance': 0,
                'value': 'Bloggs'
            }, {
                'group_id': 'who-lives-here',
                'group_instance': 0,
                'block_id': 'household-composition',
                'answer_id': 'first-name',
                'answer_instance': 1,
                'value': 'Bob'
            }, {
                'group_id': 'who-lives-here',
                'group_instance': 0,
                'block_id': 'household-composition',
                'answer_id': 'middle-names',
                'answer_instance': 1,
                'value': ''
            }, {
                'group_id': 'who-lives-here',
                'group_instance': 0,
                'block_id': 'household-composition',
                'answer_id': 'last-name',
                'answer_instance': 1,
                'value': 'Seymour'
            }
        ]

        for i, answer in enumerate(answers):
            self.assertIn(answer.__dict__, expected_answers)
Exemple #7
0
 def parent_location(self):
     parent_id = self._schema.parent_id_map[self.rendered_block["id"]]
     return Location(section_id=self._current_location.section_id,
                     block_id=parent_id)
Exemple #8
0
def post_block(
        routing_path,
        schema,
        metadata,
        collection_metadata,
        answer_store,
        eq_id,
        form_type,
        collection_id,
        group_id,
        # pylint: disable=too-many-locals
        group_instance,
        block_id):
    current_location = Location(group_id, group_instance, block_id)
    completeness = get_completeness(current_user)
    router = Router(schema, routing_path, completeness, current_location)

    if not router.can_access_location():
        next_location = router.get_next_location()
        return _redirect_to_location(collection_id, eq_id, form_type,
                                     next_location)

    block = _get_block_json(current_location, schema, answer_store, metadata)

    schema_context = _get_schema_context(routing_path, current_location,
                                         metadata, collection_metadata,
                                         answer_store, schema)

    rendered_block = renderer.render(block, **schema_context)

    form = _generate_wtf_form(request.form, rendered_block, current_location,
                              schema)

    if 'action[save_sign_out]' in request.form:
        return _save_sign_out(routing_path, current_location, form, schema,
                              answer_store, metadata)

    if 'action[sign_out]' in request.form:
        return redirect(url_for('session.get_sign_out'))

    if form.validate():
        _set_started_at_metadata_if_required(form, collection_metadata)
        questionnaire_store = get_questionnaire_store(current_user.user_id,
                                                      current_user.user_ik)
        answer_store_updater = AnswerStoreUpdater(current_location, schema,
                                                  questionnaire_store)
        answer_store_updater.save_answers(form)

        next_location = path_finder.get_next_location(
            current_location=current_location)

        if _is_end_of_questionnaire(block, next_location):
            return submit_answers(routing_path, eq_id, form_type, schema)

        return redirect(_next_location_url(next_location))

    context = build_view_context(block['type'], metadata, schema, answer_store,
                                 schema_context, rendered_block,
                                 current_location, form)

    return _render_page(block['type'], context, current_location, schema,
                        answer_store, metadata, routing_path)
Exemple #9
0
def post_household_composition(routing_path, schema, metadata, answer_store,
                               **kwargs):  # pylint: disable=too-many-locals
    group_id = kwargs['group_id']
    current_location = Location(group_id, 0, 'household-composition')
    questionnaire_store = get_questionnaire_store(current_user.user_id,
                                                  current_user.user_ik)

    answer_store_updater = AnswerStoreUpdater(current_location, schema,
                                              questionnaire_store)
    answer_store_updater.remove_repeats_for_changed_household_answers(
        request.form.copy())

    disable_mandatory = any(x in request.form for x in [
        'action[add_answer]', 'action[remove_answer]', 'action[save_sign_out]'
    ])

    block = _get_block_json(current_location, schema, answer_store, metadata)

    form = post_form_for_location(schema,
                                  block,
                                  current_location,
                                  answer_store,
                                  metadata,
                                  request.form,
                                  disable_mandatory=disable_mandatory)

    form.validate(
    )  # call validate here to keep errors in the form object on the context
    context = _get_context(routing_path, block, current_location, schema, form)

    if 'action[add_answer]' in request.form:
        form.household.append_entry()

        return _render_page(block['type'], context, current_location, schema,
                            answer_store, metadata, routing_path)

    if 'action[remove_answer]' in request.form:
        index_to_remove = int(request.form.get('action[remove_answer]'))
        form.remove_person(index_to_remove)

        return _render_page(block['type'], context, current_location, schema,
                            answer_store, metadata, routing_path)

    if 'action[save_sign_out]' in request.form:
        response = _save_sign_out(routing_path, current_location, form, schema,
                                  answer_store, metadata)
        answer_store_updater.remove_empty_household_members()

        return response

    if form.validate():
        answer_store_updater.save_answers(form)

        metadata = get_metadata(current_user)
        next_location = path_finder.get_next_location(
            current_location=current_location)

        return redirect(next_location.url(metadata))

    return _render_page(block['type'], context, current_location, schema,
                        answer_store, metadata, routing_path)
def test_context_for_driving_question_summary():
    schema = load_schema_from_name("test_list_collector_driving_question")

    summary_context = SectionSummaryContext(
        DEFAULT_LANGUAGE_CODE,
        schema,
        AnswerStore(
            [
                {"answer_id": "anyone-usually-live-at-answer", "value": "Yes"},
                {"answer_id": "first-name", "value": "Toni", "list_item_id": "PlwgoG"},
                {
                    "answer_id": "last-name",
                    "value": "Morrison",
                    "list_item_id": "PlwgoG",
                },
            ]
        ),
        ListStore([{"items": ["PlwgoG"], "name": "people"}]),
        ProgressStore(),
        {},
        {},
        current_location=Location(section_id="section"),
        routing_path=RoutingPath(
            ["anyone-usually-live-at", "anyone-else-live-at"], section_id="section"
        ),
    )

    context = summary_context()

    expected = {
        "summary": {
            "answers_are_editable": True,
            "collapsible": False,
            "custom_summary": [
                {
                    "add_link": "/questionnaire/people/add-person/?return_to=section-summary",
                    "add_link_text": "Add someone to this household",
                    "empty_list_text": "There are no householders",
                    "list": {
                        "editable": True,
                        "list_items": [
                            {
                                "item_title": "Toni Morrison",
                                "primary_person": False,
                                "edit_link": "/questionnaire/people/PlwgoG/edit-person/?return_to=section-summary",
                                "remove_link": "/questionnaire/people/PlwgoG/remove-person/?return_to=section-summary",
                                "list_item_id": "PlwgoG",
                            }
                        ],
                    },
                    "list_name": "people",
                    "title": "Household members",
                    "type": "List",
                }
            ],
            "page_title": "List Collector Driving Question Summary",
            "summary_type": "SectionSummary",
            "title": "List Collector Driving Question Summary",
        }
    }

    assert context == expected
Exemple #11
0
 def parent_location(self):
     return Location(
         section_id=self._current_location.section_id,
         block_id=self.relationships_block["id"],
     )
def test_context_for_section_list_summary(people_answer_store):
    schema = load_schema_from_name("test_list_collector_section_summary")

    summary_context = SectionSummaryContext(
        language=DEFAULT_LANGUAGE_CODE,
        schema=schema,
        answer_store=people_answer_store,
        list_store=ListStore(
            [
                {"items": ["PlwgoG", "UHPLbX"], "name": "people"},
                {"items": ["gTrlio"], "name": "visitors"},
            ]
        ),
        progress_store=ProgressStore(),
        metadata={"display_address": "70 Abingdon Road, Goathill"},
        response_metadata={},
        current_location=Location(section_id="section"),
        routing_path=RoutingPath(
            [
                "primary-person-list-collector",
                "list-collector",
                "visitor-list-collector",
            ],
            section_id="section",
        ),
    )
    context = summary_context()
    expected = {
        "summary": {
            "answers_are_editable": True,
            "collapsible": False,
            "custom_summary": [
                {
                    "add_link": "/questionnaire/people/add-person/?return_to=section-summary",
                    "add_link_text": "Add someone to this household",
                    "empty_list_text": "There are no householders",
                    "list": {
                        "editable": True,
                        "list_items": [
                            {
                                "edit_link": "/questionnaire/people/PlwgoG/edit-person/?return_to=section-summary",
                                "item_title": "Toni Morrison",
                                "primary_person": False,
                                "remove_link": "/questionnaire/people/PlwgoG/remove-person/?return_to=section-summary",
                                "list_item_id": "PlwgoG",
                            },
                            {
                                "edit_link": "/questionnaire/people/UHPLbX/edit-person/?return_to=section-summary",
                                "item_title": "Barry Pheloung",
                                "primary_person": False,
                                "remove_link": "/questionnaire/people/UHPLbX/remove-person/?return_to=section-summary",
                                "list_item_id": "UHPLbX",
                            },
                        ],
                    },
                    "list_name": "people",
                    "title": "Household members staying overnight on 13 October 2019 at 70 Abingdon Road, Goathill",
                    "type": "List",
                },
                {
                    "add_link": "/questionnaire/visitors/add-visitor/?return_to=section-summary",
                    "add_link_text": "Add another visitor to this household",
                    "empty_list_text": "There are no visitors",
                    "list": {
                        "editable": True,
                        "list_items": [
                            {
                                "edit_link": "/questionnaire/visitors/gTrlio/edit-visitor-person/?return_to=section-summary",
                                "item_title": "",
                                "primary_person": False,
                                "remove_link": "/questionnaire/visitors/gTrlio/remove-visitor/?return_to=section-summary",
                                "list_item_id": "gTrlio",
                            }
                        ],
                    },
                    "list_name": "visitors",
                    "title": "Visitors staying overnight on 13 October 2019 at 70 Abingdon Road, Goathill",
                    "type": "List",
                },
            ],
            "page_title": "People who live here and overnight visitors",
            "summary_type": "SectionSummary",
            "title": "People who live here and overnight visitors",
        }
    }

    assert context == expected
def get_introduction(eq_id, form_type, collection_id):  # pylint: disable=unused-argument
    group_id = SchemaHelper.get_first_group_id(g.schema_json)
    current_location = Location(group_id, group_instance=0, block_id='introduction')
    return _build_template(current_location, get_introduction_context(g.schema_json))
Exemple #14
0
    def build_path(self, blocks, this_location):
        """
        Visits all the blocks from a location forwards and returns path
        taken given a list of answers.

        :param blocks: A list containing all block content in the survey
        :param this_location: The location to visit, represented as a dict
        :return: A list of locations followed through the survey
        """
        path = []
        block_index = 0
        blocks_len = len(blocks)

        # Keep going unless we've hit the last block
        while block_index < blocks_len:
            if this_location.block_id in self.CLOSING_INTERSTITIAL_PATH:
                return path

            block_index = PathFinder._block_index_for_location(
                blocks, this_location)
            if block_index is None:
                logger.error(
                    'build_path: _block_index_for_location %s is None (invalid location)',
                    this_location)
                return path

            path.append(this_location)
            block = blocks[block_index]["block"]

            # If routing rules exist then a rule must match (i.e. default goto)
            if 'routing_rules' in block and len(block['routing_rules']) > 0:
                original_this_location = copy.copy(this_location)
                for rule in filter(is_goto_rule, block['routing_rules']):
                    should_goto = evaluate_goto(rule['goto'], self.metadata,
                                                self.answer_store,
                                                this_location.group_instance)

                    if should_goto:
                        next_location = copy.copy(this_location)
                        next_location.block_id = rule['goto']['id']

                        next_block_index = PathFinder._block_index_for_location(
                            blocks, next_location)
                        next_precedes_current = next_block_index is not None and next_block_index < block_index

                        if next_precedes_current:
                            self._remove_rule_answers(rule['goto'],
                                                      this_location)

                        this_location = next_location
                        break

                # If we haven't changed location based on routing rules then we can't progress any further
                if this_location == original_this_location:
                    break

            # No routing rules, so if this isn't the last block, step forward a block
            elif block_index < len(blocks) - 1:
                this_location = Location(
                    blocks[block_index + 1]['group_id'],
                    blocks[block_index + 1]['group_instance'],
                    blocks[block_index + 1]['block']['id'])

            # If we've reached last block stop evaluating the path
            else:
                break

        return path
Exemple #15
0
    def test_post_form_for_household_relationship_driven_by_multiple_answers(
            self):
        with self.app_request_context():
            schema = load_schema_from_params(
                'test', 'routing_on_answer_from_driving_repeating_group')

            block_json = schema.get_block('relationships')
            location = Location('household-relationships', 0, 'relationships')

            primary_group_instance_id = str(uuid.uuid4())
            repeating_group_1_instance_id = str(uuid.uuid4())
            repeating_group_2_instance_id = str(uuid.uuid4())

            answer_store = AnswerStore({})
            answer_store.add(
                Answer(answer_id='primary-name',
                       value='Jon',
                       group_instance=0,
                       group_instance_id=primary_group_instance_id))
            answer_store.add(
                Answer(answer_id='primary-live-here',
                       value='No',
                       group_instance=0,
                       group_instance_id=primary_group_instance_id))
            answer_store.add(
                Answer(
                    answer_id='repeating-anyone-else',
                    answer_instance=0,
                    value='Yes',
                    group_instance=0,
                ))
            answer_store.add(
                Answer(answer_id='repeating-name',
                       answer_instance=0,
                       value='Adam',
                       group_instance=0,
                       group_instance_id=repeating_group_1_instance_id))
            answer_store.add(
                Answer(
                    answer_id='repeating-anyone-else',
                    answer_instance=0,
                    value='Yes',
                    group_instance=1,
                ))
            answer_store.add(
                Answer(answer_id='repeating-name',
                       answer_instance=0,
                       value='Ben',
                       group_instance=1,
                       group_instance_id=repeating_group_2_instance_id))
            answer_store.add(
                Answer(
                    answer_id='repeating-anyone-else',
                    answer_instance=0,
                    value='No',
                    group_instance=2,
                ))

            answer = schema.get_answers_for_block('relationships')[0]

            form = post_form_for_location(
                schema,
                block_json,
                location,
                answer_store,
                metadata=None,
                request_form=MultiDict(
                    {'{answer_id}-0'.format(answer_id=answer['id']): '3'}))

            self.assertTrue(hasattr(form, answer['id']))

            field_list = getattr(form, answer['id'])

            # With three people, we need to define 2 relationships
            self.assertEqual(len(field_list.entries), 2)

            # Check the data matches what was passed from request
            self.assertEqual(field_list.entries[0].data, '3')
def _is_answer_on_path(schema, answer, routing_path):
    answer_schema = schema.get_answer(answer['answer_id'])
    question_schema = schema.get_question(answer_schema['parent_id'])
    block_schema = schema.get_block(question_schema['parent_id'])
    location = Location(block_schema['parent_id'], answer['group_instance'], block_schema['id'])
    return location in routing_path
 def parent_location(self):
     return Location(
         section_id=self._current_location.section_id,
         block_id=self.rendered_block["parent_id"],
     )
    def test_converter_checkboxes_with_q_codes_and_other_value(self):
        with self.application.test_request_context():
            routing_path = [Location(group_id='favourite food', group_instance=0, block_id='crisps')]
            answers = [create_answer('crisps-answer', ['Ready salted', 'other', 'Bacon'], group_id='favourite food', block_id='crisps')]

            questionnaire = {
                "survey_id": "999",
                "data_version": "0.0.1",
                "groups": [
                    {
                        "id": "favourite food",
                        "blocks": [
                            {
                                "id": "crisps",
                                "sections": [
                                    {
                                        "questions": [{
                                            "id": 'crisps-question',
                                            "answers": [
                                                {
                                                    "id": "crisps-answer",
                                                    "type": "Checkbox",
                                                    "options": [
                                                        {
                                                            "label": "Ready salted",
                                                            "value": "Ready salted",
                                                            "q_code": "1"
                                                        },
                                                        {
                                                            "label": "Sweet chilli",
                                                            "value": "Sweet chilli",
                                                            "q_code": "2"
                                                        },
                                                        {
                                                            "label": "Cheese and onion",
                                                            "value": "Cheese and onion",
                                                            "q_code": "3"
                                                        },
                                                        {
                                                            "label": "Other",
                                                            "value": "other",
                                                            "q_code": "4",
                                                            "description": "Choose any other flavour",
                                                            "other": {
                                                                "label": "Please specify other"
                                                            }
                                                        }
                                                    ]
                                                }
                                            ]
                                        }]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }

            # When
            answer_object = convert_answers(metadata, questionnaire, AnswerStore(answers), routing_path)

            # Then
            self.assertEqual(len(answer_object['data']), 2)
            self.assertEqual(answer_object['data']['1'], 'Ready salted')
            self.assertEqual(answer_object['data']['4'], 'Bacon')
Exemple #19
0
    def test_when_rule_comparing_answer_values(self):
        answers = {
            "low":
            Answer(answer_id="low", value=1),
            "medium":
            Answer(answer_id="medium", value=5),
            "high":
            Answer(answer_id="high", value=10),
            "list_answer":
            Answer(answer_id="list_answer", value=["a", "abc", "cba"]),
            "other_list_answer":
            Answer(answer_id="other_list_answer", value=["x", "y", "z"]),
            "other_list_answer_2":
            Answer(answer_id="other_list_answer_2", value=["a", "abc", "cba"]),
            "text_answer":
            Answer(answer_id="small_string", value="abc"),
            "other_text_answer":
            Answer(answer_id="other_string", value="xyz"),
        }

        # An answer that won't be added to the answer store.
        missing_answer = Answer(answer_id="missing", value=1)

        param_list = [
            (answers["medium"], "equals", answers["medium"], True),
            (answers["medium"], "equals", answers["low"], False),
            (answers["medium"], "greater than", answers["low"], True),
            (answers["medium"], "greater than", answers["high"], False),
            (answers["medium"], "less than", answers["high"], True),
            (answers["medium"], "less than", answers["low"], False),
            (answers["medium"], "equals", missing_answer, False),
            (answers["list_answer"], "contains", answers["text_answer"], True),
            (answers["list_answer"], "contains", answers["other_text_answer"],
             False),
            (
                answers["list_answer"],
                "not contains",
                answers["other_text_answer"],
                True,
            ),
            (answers["list_answer"], "not contains", answers["text_answer"],
             False),
            (
                answers["list_answer"],
                "contains any",
                answers["other_list_answer_2"],
                True,
            ),
            (
                answers["list_answer"],
                "contains any",
                answers["other_list_answer"],
                False,
            ),
            (
                answers["list_answer"],
                "contains all",
                answers["other_list_answer"],
                False,
            ),
            (
                answers["list_answer"],
                "contains all",
                answers["other_list_answer_2"],
                True,
            ),
            (answers["text_answer"], "equals any", answers["list_answer"],
             True),
            (answers["text_answer"], "equals any",
             answers["other_list_answer"], False),
            (
                answers["text_answer"],
                "not equals any",
                answers["other_list_answer"],
                True,
            ),
            (answers["text_answer"], "not equals any", answers["list_answer"],
             False),
        ]

        for lhs, comparison, rhs, expected_result in param_list:
            # Given
            with self.subTest(lhs=lhs,
                              comparison=comparison,
                              rhs=rhs,
                              expected_result=expected_result):
                answer_store = AnswerStore()
                for answer in answers.values():
                    answer_store.add_or_update(answer)

                when = [{
                    "id": lhs.answer_id,
                    "condition": comparison,
                    "comparison": {
                        "id": rhs.answer_id,
                        "source": "answers"
                    },
                }]

                current_location = Location(section_id="some-section",
                                            block_id="some-block")

                self.assertEqual(
                    evaluate_when_rules(
                        when_rules=when,
                        schema=get_schema(),
                        metadata={},
                        answer_store=answer_store,
                        list_store=ListStore(),
                        current_location=current_location,
                        routing_path_block_ids=None,
                    ),
                    expected_result,
                )
Exemple #20
0
 def _deserialise(raw_data):
     data = json.loads(raw_data)
     data['COMPLETED_BLOCKS'] = [Location.from_dict(location_dict=completed_block) for completed_block in data['COMPLETED_BLOCKS']]
     return data
 def get_last_location_in_survey(self):
     last_section_id = self._schema.get_section_ids()[-1]
     last_block_id = self._schema.get_last_block_id_for_section(
         last_section_id)
     return Location(section_id=last_section_id, block_id=last_block_id)
    def test_convert_answers(self):
        with self._app.test_request_context():
            user_answer = [
                create_answer('ABC',
                              '2016-01-01',
                              group_id='group-1',
                              block_id='block-1'),
                create_answer('DEF',
                              '2016-03-30',
                              group_id='group-1',
                              block_id='block-1')
            ]

            questionnaire = {
                'survey_id':
                '021',
                'data_version':
                '0.0.1',
                'sections': [{
                    'id':
                    'section-1',
                    'groups': [{
                        'id':
                        'group-1',
                        'blocks': [{
                            'id':
                            'block-1',
                            'questions': [{
                                'id':
                                'question-1',
                                'answers': [{
                                    'id': 'ABC',
                                    'type': 'TextField',
                                    'q_code': '001'
                                }, {
                                    'id': 'DEF',
                                    'type': 'TextField',
                                    'q_code': '002'
                                }]
                            }]
                        }]
                    }]
                }]
            }

            routing_path = [
                Location(group_id='group-1',
                         group_instance=0,
                         block_id='block-1')
            ]
            answer_object = convert_answers(self.metadata,
                                            QuestionnaireSchema(questionnaire),
                                            AnswerStore(user_answer),
                                            routing_path)

            self.assertEqual(answer_object['type'],
                             'uk.gov.ons.edc.eq:surveyresponse')
            self.assertEqual(answer_object['version'], '0.0.1')
            self.assertEqual(answer_object['origin'], 'uk.gov.ons.edc.eq')
            self.assertEqual(answer_object['survey_id'], '021')
            self.assertEqual(answer_object['collection']['exercise_sid'],
                             self.metadata['collection_exercise_sid'])
            self.assertEqual(answer_object['collection']['instrument_id'],
                             self.metadata['form_type'])
            self.assertEqual(answer_object['collection']['period'],
                             self.metadata['period_id'])
            self.assertEqual(answer_object['metadata']['user_id'],
                             self.metadata['user_id'])
            self.assertEqual(answer_object['metadata']['ru_ref'],
                             self.metadata['ru_ref'])
            self.assertEqual(answer_object['data']['001'], '2016-01-01')
            self.assertEqual(answer_object['data']['002'], '2016-03-30')
Exemple #23
0
def location():
    return Location("test-section", "test-block", "test-list", "list_item_id")
Exemple #24
0
    def test_repeat_on_answer_count_when_not_all_answers_on_path(self):
        schema = load_schema_from_params('test', 'routing_repeat_until')

        primary_group_instance_id = str(uuid.uuid4())
        repeating_group_1_instance_id = str(uuid.uuid4())
        repeating_group_2_instance_id = str(uuid.uuid4())

        answer_store = AnswerStore({})
        answer_store.add_or_update(
            Answer(answer_id='primary-name',
                   value='Jon',
                   group_instance=0,
                   group_instance_id=primary_group_instance_id))
        answer_store.add_or_update(
            Answer(
                answer_id='repeating-anyone-else',
                answer_instance=0,
                value='Yes',
                group_instance=0,
            ))
        answer_store.add_or_update(
            Answer(answer_id='repeating-name',
                   answer_instance=0,
                   value='Adam',
                   group_instance=0,
                   group_instance_id=repeating_group_1_instance_id))
        answer_store.add_or_update(
            Answer(
                answer_id='repeating-anyone-else',
                answer_instance=0,
                value='No',
                group_instance=1,
            ))
        answer_store.add_or_update(
            Answer(answer_id='repeating-name',
                   answer_instance=0,
                   value='Ben',
                   group_instance=1,
                   group_instance_id=repeating_group_2_instance_id))
        answer_store.add_or_update(
            Answer(
                answer_id='repeating-anyone-else',
                answer_instance=0,
                value='No',
                group_instance=2,
            ))

        routing_path = [
            Location('primary-group', 0, 'primary-name-block'),
            Location('repeating-group', 0, 'repeating-anyone-else-block'),
            Location('repeating-group', 0, 'repeating-name-block'),
            Location('repeating-group', 1, 'repeating-anyone-else-block'),
        ]

        repeat = {
            'type': 'answer_count',
            'answer_ids': ['primary-name', 'repeating-name']
        }

        # When
        number_of_repeats = evaluate_repeat(repeat, answer_store, schema,
                                            routing_path)

        self.assertEqual(number_of_repeats, 2)
    def test_skipped_group(self):
        schema = load_schema_from_params('test', 'navigation')

        completed_blocks = [
            Location('property-details', 0, 'insurance-type'),
            Location('property-details', 0, 'insurance-address'),
            Location('property-details', 0, 'property-interstitial'),
            Location('house-details', 0, 'house-type'),
            Location('multiple-questions-group', 0, 'household-composition'),
            Location('repeating-group', 0, 'repeating-block-1'),
            Location('repeating-group', 0, 'repeating-block-2'),
            Location('extra-cover', 0, 'extra-cover-block'),
            Location('extra-cover', 0, 'extra-cover-interstitial'),
            Location('payment-details', 0, 'credit-card'),
            Location('payment-details', 0, 'expiry-date'),
            Location('payment-details', 0, 'security-code'),
            Location('payment-details', 0, 'security-code-interstitial'),
            Location('extra-cover-items-group', 0, 'extra-cover-items'),
        ]

        routing_path = [
            Location('property-details', 0, 'insurance-type'),
            Location('property-details', 0, 'insurance-address'),
            Location('property-details', 0, 'property-interstitial'),
            Location('house-details', 0, 'house-type'),
            Location('multiple-questions-group', 0, 'household-composition'),
            Location('repeating-group', 0, 'repeating-block-1'),
            Location('repeating-group', 0, 'repeating-block-2'),
            Location('payment-details', 0, 'credit-card'),
            Location('payment-details', 0, 'expiry-date'),
            Location('payment-details', 0, 'security-code'),
            Location('payment-details', 0, 'security-code-interstitial'),
            Location('extra-cover', 0, 'extra-cover-block'),
            Location('extra-cover', 0, 'extra-cover-interstitial'),
            Location('extra-cover-items-group', 0, 'extra-cover-items'),
            Location('summary-group', 0, 'summary'),
        ]

        progress = Completeness(
            schema, AnswerStore(), completed_blocks, routing_path, metadata={})
        with patch('app.questionnaire.path_finder.evaluate_skip_conditions', return_value=True):
            progress_value = progress.get_state_for_group('payment-details')
        self.assertEqual(Completeness.SKIPPED, progress_value)
Exemple #26
0
    def test_should_repeat_until(self):
        questionnaire = {
            'survey_id':
            '021',
            'data_version':
            '0.0.1',
            'sections': [{
                'id':
                'section1',
                'groups': [{
                    'id':
                    'group-1',
                    'blocks': [{
                        'id':
                        'block-1',
                        'questions': [{
                            'id':
                            'question-2',
                            'answers': [{
                                'id': 'my_answer',
                                'type': 'TextField'
                            }]
                        }]
                    }]
                }]
            }]
        }

        schema = QuestionnaireSchema(questionnaire)

        # Given
        repeat = {
            'type': 'until',
            'when': [{
                'id': 'my_answer',
                'condition': 'equals',
                'value': 'Done'
            }]
        }

        answer_store = AnswerStore({})
        current_path = [Location('group-1', 0, 'block-1')]

        # The schema doesn't actually contain a repeat clause, so fake it.
        with patch.object(schema,
                          'answer_is_in_repeating_group',
                          return_value=True):
            self.assertEqual(
                evaluate_repeat(repeat, answer_store, schema, current_path), 1)

            answer_store.add_or_update(
                Answer(answer_id='my_answer',
                       value='Not Done',
                       group_instance=0,
                       group_instance_id=None))
            self.assertEqual(
                evaluate_repeat(repeat, answer_store, schema, current_path), 2)

            answer_store.add_or_update(
                Answer(answer_id='my_answer',
                       value='Done',
                       group_instance=1,
                       group_instance_id=None))
            self.assertEqual(
                evaluate_repeat(repeat, answer_store, schema, current_path), 2)
    def test_get_first_incomplete_location_in_survey_completed(self):
        schema = load_schema_from_params('test', 'navigation')

        # interstitial blocks have been removed
        completed_blocks = [
            Location('property-details', 0, 'insurance-type'),
            Location('property-details', 0, 'insurance-address'),
            Location('house-details', 0, 'house-type'),
            Location('multiple-questions-group', 0, 'household-composition'),
            Location('repeating-group', 0, 'repeating-block-1'),
            Location('repeating-group', 0, 'repeating-block-2'),
            Location('extra-cover', 0, 'extra-cover-block'),
            Location('payment-details', 0, 'credit-card'),
            Location('payment-details', 0, 'expiry-date'),
            Location('payment-details', 0, 'security-code'),
            Location('extra-cover-items-group', 0, 'extra-cover-items'),
            Location('extra-cover-items-group', 0, 'extra-cover-items-radio'),
            Location('skip-payment-group', 0, 'skip-payment'),
        ]

        routing_path = [
            Location('property-details', 0, 'insurance-type'),
            Location('property-details', 0, 'insurance-address'),
            Location('property-details', 0, 'property-interstitial'),
            Location('house-details', 0, 'house-type'),
            Location('multiple-questions-group', 0, 'household-composition'),
            Location('repeating-group', 0, 'repeating-block-1'),
            Location('repeating-group', 0, 'repeating-block-2'),
            Location('extra-cover', 0, 'extra-cover-block'),
            Location('extra-cover', 0, 'extra-cover-interstitial'),
            Location('payment-details', 0, 'credit-card'),
            Location('payment-details', 0, 'expiry-date'),
            Location('payment-details', 0, 'security-code'),
            Location('payment-details', 0, 'security-code-interstitial'),
            Location('extra-cover-items-group', 0, 'extra-cover-items'),
            Location('extra-cover-items-group', 0, 'extra-cover-items-radio'),
            Location('skip-payment-group', 0, 'skip-payment'),
            Location('confirmation-group', 0, 'confirmation'),
        ]
        progress = Completeness(
            schema, AnswerStore(), completed_blocks, routing_path, metadata={})
        with patch('app.questionnaire.path_finder.evaluate_goto', return_value=False):
            self.assertFalse(progress.get_first_incomplete_location_in_survey())
Exemple #28
0
    def test_get_form_for_household_relationship_driven_by_multiple_answers(
            self):
        with self.app_request_context():
            schema = load_schema_from_params(
                'test', 'routing_on_answer_from_driving_repeating_group')

            block_json = schema.get_block('relationships')
            location = Location('household-relationships', 0, 'relationships')
            error_messages = schema.error_messages

            primary_group_instance_id = str(uuid.uuid4())
            repeating_group_1_instance_id = str(uuid.uuid4())
            repeating_group_2_instance_id = str(uuid.uuid4())

            answer_store = AnswerStore({})
            answer_store.add(
                Answer(answer_id='primary-name',
                       value='Jon',
                       group_instance=0,
                       group_instance_id=primary_group_instance_id))
            answer_store.add(
                Answer(answer_id='primary-live-here',
                       value='No',
                       group_instance=0,
                       group_instance_id=primary_group_instance_id))
            answer_store.add(
                Answer(
                    answer_id='repeating-anyone-else',
                    answer_instance=0,
                    value='Yes',
                    group_instance=0,
                ))
            answer_store.add(
                Answer(answer_id='repeating-name',
                       answer_instance=0,
                       value='Adam',
                       group_instance=0,
                       group_instance_id=repeating_group_1_instance_id))
            answer_store.add(
                Answer(
                    answer_id='repeating-anyone-else',
                    answer_instance=0,
                    value='Yes',
                    group_instance=1,
                ))
            answer_store.add(
                Answer(answer_id='repeating-name',
                       answer_instance=0,
                       value='Ben',
                       group_instance=1,
                       group_instance_id=repeating_group_2_instance_id))
            answer_store.add(
                Answer(
                    answer_id='repeating-anyone-else',
                    answer_instance=0,
                    value='No',
                    group_instance=2,
                ))

            form = get_form_for_location(schema, block_json, location,
                                         answer_store, error_messages)

            answer = schema.get_answers_for_block('relationships')[0]

            self.assertTrue(hasattr(form, answer['id']))

            field_list = getattr(form, answer['id'])

            # With three people, we need to define 2 relationships
            self.assertEqual(len(field_list.entries), 2)
Exemple #29
0
 def get_first_location(cls, survey_json):
     return Location(
         group_id=cls.get_first_group_id(survey_json),
         group_instance=0,
         block_id=cls.get_first_block_id(survey_json),
     )
 def parent_location(self):
     return Location(section_id=self._current_location.section_id,
                     block_id=self.block["id"])