def get_test_app(self): app = Application.new_app('domain', 'New App') app.version = 1 m0 = self._make_module(app, 0, 'parent') m0.get_form(0).actions.subcases.append( OpenSubCaseAction(case_type='child', reference_id='parent')) m1 = self._make_module(app, 1, 'child') m1.get_form(0).actions.subcases.append( OpenSubCaseAction(case_type='grand child', reference_id='parent')) m2 = self._make_module(app, 2, 'grand child') m3 = app.add_module(AdvancedModule.new_module('Module3', lang='en')) m3.case_type = 'other grand child' m3f0 = m3.new_form('other form', 'en') m3f0.actions.load_update_cases.append( LoadUpdateAction(case_type='child', case_tag='child')) m3f0.actions.open_cases.append( AdvancedOpenCaseAction(name_path='/data/question1', case_type='other grand child', case_indices=[CaseIndex(tag='child')])) m3f0.actions.open_cases[0].open_condition.type = 'always' m2.parent_select = ParentSelect(active=True, module_id=m1.unique_id) m1.parent_select = ParentSelect(active=True, module_id=m0.unique_id) expected_hierarchy = { 'parent': { 'child': { 'grand child': {}, 'other grand child': {} } } } return app, expected_hierarchy
def get_test_app(self): app = Application.new_app('domain', 'New App') app._id = uuid.uuid4().hex app.version = 1 m0 = self._make_module(app, 0, 'parent') m0.get_form(0).actions.subcases.extend([ OpenSubCaseAction(case_type='child', reference_id='parent'), OpenSubCaseAction(case_type='other_child', reference_id='parent') ]) m1 = self._make_module(app, 1, 'child') m1.get_form(0).actions.subcases.append( OpenSubCaseAction(case_type='grand child', reference_id='parent')) m2 = self._make_module(app, 2, 'grand child') m3 = app.add_module(AdvancedModule.new_module('Module3', lang='en')) m3.case_type = 'other grand child' m3f0 = m3.new_form('other form', 'en') m3f0.actions.load_update_cases.append( LoadUpdateAction(case_type='child', case_tag='child')) m3f0.actions.open_cases.append( AdvancedOpenCaseAction( name_path='/data/question1', case_type='other grand child', case_indices=[CaseIndex(tag='child', reference_id='father')])) m3f0.actions.open_cases[0].open_condition.type = 'always' m4 = app.add_module(AdvancedModule.new_module('Module4', lang='en')) m4.case_type = 'extension' self._make_module(app, 5, 'other_child') m4f0 = m4.new_form('other form', 'en') m4f0.actions.load_update_cases.extend([ LoadUpdateAction(case_type='child', case_tag='child'), LoadUpdateAction(case_type='other_child', case_tag='other_child'), ]) m4f0.actions.open_cases.extend([ AdvancedOpenCaseAction(name_path='/data/question1', case_type='extension', case_indices=[ CaseIndex(tag='child', relationship='extension', reference_id='host') ]), AdvancedOpenCaseAction( # 'extension' case has 2 parents name_path='/data/question1', case_type='extension', case_indices=[ CaseIndex(tag='other_child', relationship='extension', reference_id='host') ]) ]) m4f0.actions.open_cases[0].open_condition.type = 'always' m4f0.actions.open_cases[1].open_condition.type = 'always' m2.parent_select = ParentSelect(active=True, module_id=m1.unique_id) m1.parent_select = ParentSelect(active=True, module_id=m0.unique_id) return app
def test_child_module_with_parent_select_entry_datums(self): """ m0 - opens 'gold-fish' case. m1 - has m0 as root-module, has parent-select, updates 'guppy' case, creates 'pregnancy' subcases to guppy """ self.module_1.root_module_id = self.module_0.unique_id # m0f0 registers gold-fish case self.module_0.case_type = 'gold-fish' m0f0 = self.module_0.get_form(0) m0f0.requires = 'case' m0f0.actions.update_case = UpdateCaseAction( update={'question2': '/data/question2'}) m0f0.actions.update_case.condition.type = 'always' # m1f0 has parent-select, updates `guppy` case, and opens sub-subcase 'pregnancy' self.module_1.case_type = 'guppy' self.module_1.parent_select = ParentSelect( active=True, module_id=self.module_0.unique_id) m1f0 = self.module_1.get_form(0) m1f0.requires = 'case' m1f0.actions.update_case = UpdateCaseAction( update={'question2': '/data/question2'}) m1f0.actions.update_case.condition.type = 'always' m1f0.actions.subcases.append( OpenSubCaseAction(case_type='pregnancy', case_name="/data/question1", condition=FormActionCondition(type='always'))) self.assertXmlPartialEqual( self.get_xml('child-module-with-parent-select-entry-datums-added'), self.app.create_suite(), "./entry")
def setUp(self): factory = AppFactory(DOMAIN, "App with DR and child modules", build_version='2.53.0') m0, f0 = factory.new_basic_module("case list", "case") factory.form_requires_case(f0) m1, f1 = factory.new_basic_module("child case list", "case", parent_module=m0) m1.parent_select = ParentSelect(active=True, relationship="other", module_id=m0.get_or_create_unique_id()) f2 = factory.new_form(m1) factory.form_requires_case(f1) factory.form_requires_case(f2) m1.search_config = CaseSearch( properties=[CaseSearchProperty(name='name', label={'en': 'Name'})], data_registry="myregistry", data_registry_workflow=REGISTRY_WORKFLOW_LOAD_CASE, ) # link from f1 to f2 (both in the child module) f1.post_form_workflow = WORKFLOW_FORM f1.form_links = [FormLink(form_id=f2.get_unique_id())] factory.app._id = "123" # wrap to have assign_references called self.app = Application.wrap(factory.app.to_json())
def edit_module_detail_screens(request, domain, app_id, module_id): """ Overwrite module case details. Only overwrites components that have been provided in the request. Components are short, long, filter, parent_select, fixture_select and sort_elements. """ params = json_request(request.POST) detail_type = params.get('type') short = params.get('short', None) long = params.get('long', None) tabs = params.get('tabs', None) filter = params.get('filter', ()) custom_xml = params.get('custom_xml', None) parent_select = params.get('parent_select', None) fixture_select = params.get('fixture_select', None) sort_elements = params.get('sort_elements', None) persist_case_context = params.get('persistCaseContext', None) use_case_tiles = params.get('useCaseTiles', None) persist_tile_on_forms = params.get("persistTileOnForms", None) pull_down_tile = params.get("enableTilePullDown", None) case_list_lookup = params.get("case_list_lookup", None) app = get_app(domain, app_id) module = app.get_module(module_id) if detail_type == 'case': detail = module.case_details elif detail_type == CAREPLAN_GOAL: detail = module.goal_details elif detail_type == CAREPLAN_TASK: detail = module.task_details else: try: detail = getattr(module, '{0}_details'.format(detail_type)) except AttributeError: return HttpResponseBadRequest("Unknown detail type '%s'" % detail_type) if short is not None: detail.short.columns = map(DetailColumn.wrap, short) if persist_case_context is not None: detail.short.persist_case_context = persist_case_context if use_case_tiles is not None: detail.short.use_case_tiles = use_case_tiles if persist_tile_on_forms is not None: detail.short.persist_tile_on_forms = persist_tile_on_forms if pull_down_tile is not None: detail.short.pull_down_tile = pull_down_tile if case_list_lookup is not None: _save_case_list_lookup_params(detail.short, case_list_lookup) if long is not None: detail.long.columns = map(DetailColumn.wrap, long) if tabs is not None: detail.long.tabs = map(DetailTab.wrap, tabs) if filter != (): # Note that we use the empty tuple as the sentinel because a filter # value of None represents clearing the filter. detail.short.filter = filter if custom_xml is not None: detail.short.custom_xml = custom_xml if sort_elements is not None: detail.short.sort_elements = [] for sort_element in sort_elements: item = SortElement() item.field = sort_element['field'] item.type = sort_element['type'] item.direction = sort_element['direction'] detail.short.sort_elements.append(item) if parent_select is not None: module.parent_select = ParentSelect.wrap(parent_select) if fixture_select is not None: module.fixture_select = FixtureSelect.wrap(fixture_select) resp = {} app.save(resp) return json_response(resp)
def edit_module_detail_screens(request, domain, app_id, module_id): """ Overwrite module case details. Only overwrites components that have been provided in the request. Components are short, long, filter, parent_select, fixture_select and sort_elements. """ params = json_request(request.POST) detail_type = params.get('type') short = params.get('short', None) long = params.get('long', None) tabs = params.get('tabs', None) filter = params.get('filter', ()) custom_xml = params.get('custom_xml', None) parent_select = params.get('parent_select', None) fixture_select = params.get('fixture_select', None) sort_elements = params.get('sort_elements', None) persist_case_context = params.get('persistCaseContext', None) persistent_case_context_xml = params.get('persistentCaseContextXML', None) use_case_tiles = params.get('useCaseTiles', None) persist_tile_on_forms = params.get("persistTileOnForms", None) pull_down_tile = params.get("enableTilePullDown", None) case_list_lookup = params.get("case_list_lookup", None) search_properties = params.get("search_properties") custom_variables = { 'short': params.get("short_custom_variables", None), 'long': params.get("long_custom_variables", None) } app = get_app(domain, app_id) module = app.get_module(module_id) if detail_type == 'case': detail = module.case_details elif detail_type == CAREPLAN_GOAL: detail = module.goal_details elif detail_type == CAREPLAN_TASK: detail = module.task_details else: try: detail = getattr(module, '{0}_details'.format(detail_type)) except AttributeError: return HttpResponseBadRequest("Unknown detail type '%s'" % detail_type) lang = request.COOKIES.get('lang', app.langs[0]) if short is not None: detail.short.columns = map(DetailColumn.from_json, short) if persist_case_context is not None: detail.short.persist_case_context = persist_case_context detail.short.persistent_case_context_xml = persistent_case_context_xml if use_case_tiles is not None: detail.short.use_case_tiles = use_case_tiles if persist_tile_on_forms is not None: detail.short.persist_tile_on_forms = persist_tile_on_forms if pull_down_tile is not None: detail.short.pull_down_tile = pull_down_tile if case_list_lookup is not None: _save_case_list_lookup_params(detail.short, case_list_lookup, lang) if long is not None: detail.long.columns = map(DetailColumn.from_json, long) if tabs is not None: detail.long.tabs = map(DetailTab.wrap, tabs) if filter != (): # Note that we use the empty tuple as the sentinel because a filter # value of None represents clearing the filter. detail.short.filter = filter if custom_xml is not None: detail.short.custom_xml = custom_xml if custom_variables['short'] is not None: try: etree.fromstring("<variables>{}</variables>".format( custom_variables['short'])) except etree.XMLSyntaxError as error: return HttpResponseBadRequest( "There was an issue with your custom variables: {}".format( error.message)) detail.short.custom_variables = custom_variables['short'] if custom_variables['long'] is not None: try: etree.fromstring("<variables>{}</variables>".format( custom_variables['long'])) except etree.XMLSyntaxError as error: return HttpResponseBadRequest( "There was an issue with your custom variables: {}".format( error.message)) detail.long.custom_variables = custom_variables['long'] if sort_elements is not None: detail.short.sort_elements = [] for sort_element in sort_elements: item = SortElement() item.field = sort_element['field'] item.type = sort_element['type'] item.direction = sort_element['direction'] item.display[lang] = sort_element['display'] if toggles.SORT_CALCULATION_IN_CASE_LIST.enabled(domain): item.sort_calculation = sort_element['sort_calculation'] else: item.sort_calculation = "" detail.short.sort_elements.append(item) if parent_select is not None: module.parent_select = ParentSelect.wrap(parent_select) if module_case_hierarchy_has_circular_reference(module): return HttpResponseBadRequest( _("The case hierarchy contains a circular reference.")) if fixture_select is not None: module.fixture_select = FixtureSelect.wrap(fixture_select) if search_properties is not None: if search_properties.get('properties') is not None: module.search_config = CaseSearch( properties=[ CaseSearchProperty.wrap(p) for p in _update_search_properties( module, search_properties.get('properties'), lang) ], relevant=(search_properties.get('relevant') if search_properties.get('relevant') is not None else CLAIM_DEFAULT_RELEVANT_CONDITION), include_closed=bool(search_properties.get('include_closed')), default_properties=[ DefaultCaseSearchProperty.wrap(p) for p in search_properties.get('default_properties') ]) resp = {} app.save(resp) return json_response(resp)
def edit_module_detail_screens(request, domain, app_id, module_unique_id): """ Overwrite module case details. Only overwrites components that have been provided in the request. Components are short, long, filter, parent_select, fixture_select and sort_elements. """ params = json_request(request.POST) detail_type = params.get('type') short = params.get('short', None) long_ = params.get('long', None) tabs = params.get('tabs', None) filter = params.get('filter', ()) custom_xml = params.get('custom_xml', None) parent_select = params.get('parent_select', None) fixture_select = params.get('fixture_select', None) sort_elements = params.get('sort_elements', None) persist_case_context = params.get('persistCaseContext', None) persistent_case_context_xml = params.get('persistentCaseContextXML', None) use_case_tiles = params.get('useCaseTiles', None) persist_tile_on_forms = params.get("persistTileOnForms", None) persistent_case_tile_from_module = params.get("persistentCaseTileFromModule", None) pull_down_tile = params.get("enableTilePullDown", None) sort_nodeset_columns = params.get("sortNodesetColumns", None) print_template = params.get('printTemplate', None) case_list_lookup = params.get("case_list_lookup", None) search_properties = params.get("search_properties") custom_variables = { 'short': params.get("short_custom_variables", None), 'long': params.get("long_custom_variables", None) } app = get_app(domain, app_id) try: module = app.get_module_by_unique_id(module_unique_id) except ModuleNotFoundException: # temporary fallback module = app.get_module(module_unique_id) if detail_type == 'case': detail = module.case_details else: try: detail = getattr(module, '{0}_details'.format(detail_type)) except AttributeError: return HttpResponseBadRequest("Unknown detail type '%s'" % detail_type) lang = request.COOKIES.get('lang', app.langs[0]) if short is not None: detail.short.columns = list(map(DetailColumn.from_json, short)) if persist_case_context is not None: detail.short.persist_case_context = persist_case_context detail.short.persistent_case_context_xml = persistent_case_context_xml if use_case_tiles is not None: detail.short.use_case_tiles = use_case_tiles if persist_tile_on_forms is not None: detail.short.persist_tile_on_forms = persist_tile_on_forms if persistent_case_tile_from_module is not None: detail.short.persistent_case_tile_from_module = persistent_case_tile_from_module if pull_down_tile is not None: detail.short.pull_down_tile = pull_down_tile if case_list_lookup is not None: _save_case_list_lookup_params(detail.short, case_list_lookup, lang) if long_ is not None: detail.long.columns = list(map(DetailColumn.from_json, long_)) if tabs is not None: detail.long.tabs = list(map(DetailTab.wrap, tabs)) if print_template is not None: detail.long.print_template = print_template if filter != (): # Note that we use the empty tuple as the sentinel because a filter # value of None represents clearing the filter. detail.short.filter = filter if custom_xml is not None: detail.short.custom_xml = custom_xml if custom_variables['short'] is not None: try: etree.fromstring("<variables>{}</variables>".format(custom_variables['short'])) except etree.XMLSyntaxError as error: return HttpResponseBadRequest( "There was an issue with your custom variables: {}".format(error.message) ) detail.short.custom_variables = custom_variables['short'] if custom_variables['long'] is not None: try: etree.fromstring("<variables>{}</variables>".format(custom_variables['long'])) except etree.XMLSyntaxError as error: return HttpResponseBadRequest( "There was an issue with your custom variables: {}".format(error.message) ) detail.long.custom_variables = custom_variables['long'] if sort_nodeset_columns is not None: detail.long.sort_nodeset_columns = sort_nodeset_columns if sort_elements is not None: # Attempt to map new elements to old so we don't lose translations # Imperfect because the same field may be used multiple times, or user may change field old_elements_by_field = {e['field']: e for e in detail.short.sort_elements} detail.short.sort_elements = [] for sort_element in sort_elements: item = SortElement() item.field = sort_element['field'] item.type = sort_element['type'] item.direction = sort_element['direction'] item.blanks = sort_element['blanks'] if item.field in old_elements_by_field: item.display = old_elements_by_field[item.field].display item.display[lang] = sort_element['display'] if toggles.SORT_CALCULATION_IN_CASE_LIST.enabled(domain): item.sort_calculation = sort_element['sort_calculation'] else: item.sort_calculation = "" detail.short.sort_elements.append(item) if parent_select is not None: module.parent_select = ParentSelect.wrap(parent_select) if module_case_hierarchy_has_circular_reference(module): return HttpResponseBadRequest(_("The case hierarchy contains a circular reference.")) if fixture_select is not None: module.fixture_select = FixtureSelect.wrap(fixture_select) if search_properties is not None: if ( search_properties.get('properties') is not None or search_properties.get('default_properties') is not None ): module.search_config = CaseSearch( properties=[ CaseSearchProperty.wrap(p) for p in _update_search_properties( module, search_properties.get('properties'), lang ) ], relevant=( search_properties.get('relevant') if search_properties.get('relevant') is not None else CLAIM_DEFAULT_RELEVANT_CONDITION ), include_closed=bool(search_properties.get('include_closed')), search_button_display_condition=search_properties.get('search_button_display_condition', ""), blacklisted_owner_ids_expression=search_properties.get('blacklisted_owner_ids_expression', ""), default_properties=[ DefaultCaseSearchProperty.wrap(p) for p in search_properties.get('default_properties') ] ) resp = {} app.save(resp) return json_response(resp)
def edit_module_detail_screens(request, domain, app_id, module_id): """ Overwrite module case details. Only overwrites components that have been provided in the request. Components are short, long, filter, parent_select, fixture_select and sort_elements. """ params = json_request(request.POST) detail_type = params.get('type') short = params.get('short', None) long = params.get('long', None) tabs = params.get('tabs', None) filter = params.get('filter', ()) custom_xml = params.get('custom_xml', None) parent_select = params.get('parent_select', None) fixture_select = params.get('fixture_select', None) sort_elements = params.get('sort_elements', None) persist_case_context = params.get('persistCaseContext', None) persistent_case_context_xml = params.get('persistentCaseContextXML', None) use_case_tiles = params.get('useCaseTiles', None) persist_tile_on_forms = params.get("persistTileOnForms", None) pull_down_tile = params.get("enableTilePullDown", None) case_list_lookup = params.get("case_list_lookup", None) search_properties = params.get("search_properties") app = get_app(domain, app_id) module = app.get_module(module_id) if detail_type == 'case': detail = module.case_details elif detail_type == CAREPLAN_GOAL: detail = module.goal_details elif detail_type == CAREPLAN_TASK: detail = module.task_details else: try: detail = getattr(module, '{0}_details'.format(detail_type)) except AttributeError: return HttpResponseBadRequest("Unknown detail type '%s'" % detail_type) lang = request.COOKIES.get('lang', app.langs[0]) if short is not None: detail.short.columns = map(DetailColumn.from_json, short) if persist_case_context is not None: detail.short.persist_case_context = persist_case_context detail.short.persistent_case_context_xml = persistent_case_context_xml if use_case_tiles is not None: detail.short.use_case_tiles = use_case_tiles if persist_tile_on_forms is not None: detail.short.persist_tile_on_forms = persist_tile_on_forms if pull_down_tile is not None: detail.short.pull_down_tile = pull_down_tile if case_list_lookup is not None: _save_case_list_lookup_params(detail.short, case_list_lookup, lang) if long is not None: detail.long.columns = map(DetailColumn.from_json, long) if tabs is not None: detail.long.tabs = map(DetailTab.wrap, tabs) if filter != (): # Note that we use the empty tuple as the sentinel because a filter # value of None represents clearing the filter. detail.short.filter = filter if custom_xml is not None: detail.short.custom_xml = custom_xml if sort_elements is not None: detail.short.sort_elements = [] for sort_element in sort_elements: item = SortElement() item.field = sort_element['field'] item.type = sort_element['type'] item.direction = sort_element['direction'] item.display[lang] = sort_element['display'] detail.short.sort_elements.append(item) if parent_select is not None: module.parent_select = ParentSelect.wrap(parent_select) if fixture_select is not None: module.fixture_select = FixtureSelect.wrap(fixture_select) if search_properties is not None: if search_properties.get('properties') is not None: module.search_config = CaseSearch( properties=[ CaseSearchProperty.wrap(p) for p in _update_search_properties( module, search_properties.get('properties'), lang) ], relevant=(search_properties.get('relevant') if search_properties.get('relevant') is not None else CLAIM_DEFAULT_RELEVANT_CONDITION)) resp = {} app.save(resp) return json_response(resp)
def edit_module_detail_screens(request, domain, app_id, module_id): """ Overwrite module case details. Only overwrites components that have been provided in the request. Components are short, long, filter, parent_select, fixture_select and sort_elements. """ params = json_request(request.POST) detail_type = params.get('type') short = params.get('short', None) long = params.get('long', None) tabs = params.get('tabs', None) filter = params.get('filter', ()) custom_xml = params.get('custom_xml', None) parent_select = params.get('parent_select', None) fixture_select = params.get('fixture_select', None) sort_elements = params.get('sort_elements', None) persist_case_context = params.get('persistCaseContext', None) persistent_case_context_xml = params.get('persistentCaseContextXML', None) use_case_tiles = params.get('useCaseTiles', None) persist_tile_on_forms = params.get("persistTileOnForms", None) pull_down_tile = params.get("enableTilePullDown", None) case_list_lookup = params.get("case_list_lookup", None) search_properties = params.get("search_properties") custom_variables = { 'short': params.get("short_custom_variables", None), 'long': params.get("long_custom_variables", None) } app = get_app(domain, app_id) module = app.get_module(module_id) if detail_type == 'case': detail = module.case_details elif detail_type == CAREPLAN_GOAL: detail = module.goal_details elif detail_type == CAREPLAN_TASK: detail = module.task_details else: try: detail = getattr(module, '{0}_details'.format(detail_type)) except AttributeError: return HttpResponseBadRequest("Unknown detail type '%s'" % detail_type) lang = request.COOKIES.get('lang', app.langs[0]) if short is not None: detail.short.columns = map(DetailColumn.from_json, short) if persist_case_context is not None: detail.short.persist_case_context = persist_case_context detail.short.persistent_case_context_xml = persistent_case_context_xml if use_case_tiles is not None: detail.short.use_case_tiles = use_case_tiles if persist_tile_on_forms is not None: detail.short.persist_tile_on_forms = persist_tile_on_forms if pull_down_tile is not None: detail.short.pull_down_tile = pull_down_tile if case_list_lookup is not None: _save_case_list_lookup_params(detail.short, case_list_lookup, lang) if long is not None: detail.long.columns = map(DetailColumn.from_json, long) if tabs is not None: detail.long.tabs = map(DetailTab.wrap, tabs) if filter != (): # Note that we use the empty tuple as the sentinel because a filter # value of None represents clearing the filter. detail.short.filter = filter if custom_xml is not None: detail.short.custom_xml = custom_xml if custom_variables['short'] is not None: try: etree.fromstring("<variables>{}</variables>".format(custom_variables['short'])) except etree.XMLSyntaxError as error: return HttpResponseBadRequest( "There was an issue with your custom variables: {}".format(error.message) ) detail.short.custom_variables = custom_variables['short'] if custom_variables['long'] is not None: try: etree.fromstring("<variables>{}</variables>".format(custom_variables['long'])) except etree.XMLSyntaxError as error: return HttpResponseBadRequest( "There was an issue with your custom variables: {}".format(error.message) ) detail.long.custom_variables = custom_variables['long'] if sort_elements is not None: detail.short.sort_elements = [] for sort_element in sort_elements: item = SortElement() item.field = sort_element['field'] item.type = sort_element['type'] item.direction = sort_element['direction'] item.display[lang] = sort_element['display'] detail.short.sort_elements.append(item) if parent_select is not None: module.parent_select = ParentSelect.wrap(parent_select) if module_case_hierarchy_has_circular_reference(module): return HttpResponseBadRequest(_("The case hierarchy contains a circular reference.")) if fixture_select is not None: module.fixture_select = FixtureSelect.wrap(fixture_select) if search_properties is not None: if search_properties.get('properties') is not None: module.search_config = CaseSearch( properties=[ CaseSearchProperty.wrap(p) for p in _update_search_properties( module, search_properties.get('properties'), lang ) ], relevant=( search_properties.get('relevant') if search_properties.get('relevant') is not None else CLAIM_DEFAULT_RELEVANT_CONDITION ), include_closed=bool(search_properties.get('include_closed')), default_properties=[ DefaultCaseSearchProperty.wrap(p) for p in search_properties.get('default_properties') ] ) resp = {} app.save(resp) return json_response(resp)