def get_default_sort_elements(detail): from corehq.apps.app_manager.models import SortElement if not detail.columns: return [] def get_sort_params(column): if column.field_type == FIELD_TYPE_LEDGER: return dict(type='int', direction='descending') else: return dict(type='string', direction='ascending') col_0 = detail.get_column(0) sort_elements = [SortElement( field=col_0.field, **get_sort_params(col_0) )] for column in detail.columns[1:]: if column.field_type == FIELD_TYPE_LEDGER: sort_elements.append(SortElement( field=column.field, **get_sort_params(column) )) return sort_elements
def test_sort_calculation(self): app = Application.wrap(self.get_json('suite-advanced')) detail = app.modules[0].case_details.short detail.sort_elements.append( SortElement( field=detail.columns[0].field, type='string', direction='descending', blanks='first', sort_calculation='random()' ) ) sort_node = """ <partial> <sort direction="descending" blanks="first" order="1" type="string"> <text> <xpath function="random()"/> </text> </sort> </partial> """ self.assertXmlPartialEqual( sort_node, app.create_suite(), "./detail[@id='m0_case_short']/field/sort" )
def test_sort_cache_suite(self): app = Application.wrap(self.get_json('suite-advanced')) detail = app.modules[0].case_details.short detail.sort_elements.append( SortElement( field=detail.columns[0].field, type='index', direction='descending', )) self.assertXmlPartialEqual(self.get_xml('sort-cache'), app.create_suite(), "./detail[@id='m0_case_short']")
def get_nodeset_sort_elements(detail): from corehq.apps.app_manager.models import SortElement sort_elements = [] tab_spans = detail.get_tab_spans() for tab in detail.get_tabs(): if tab.nodeset: tab_span = tab_spans[tab.id] for column in detail.columns[tab_span[0]:tab_span[1]]: if column.invisible: sort_elements.append( SortElement(field=column.field, type='string', direction='ascending')) return sort_elements
def test_short_detail_xml_sort_only(self): short = self.case_details.short short.display = 'short' short.sort_elements.append( SortElement( field='gps', type='distance', direction='descending', ) ) suite = self.factory.app.create_suite() template_xpath = './detail[@id="m0_case_short"]/field' self.assertXmlHasXpath(suite, template_xpath) self.assertXmlPartialEqual( """ <partial> <field> <header> <text> <locale id="m0.case_short.case_name_1.header"/> </text> </header> <template> <text> <xpath function="case_name"/> </text> </template> </field> <field> <header width="0"> <text/> </header> <template width="0"> <text> <xpath function="gps"/> </text> </template> <sort direction="descending" order="1" type="double"> <text> <xpath function="if(gps = '', 2147483647, round(distance(gps, here())))"/> </text> </sort> </field> </partial> """, suite, template_xpath )
def get_detail_column_infos(detail, include_sort): """ This is not intented to be a widely used format just a packaging of column info into a form most convenient for rendering """ from corehq.apps.app_manager.models import SortElement DetailColumnInfo = namedtuple('DetailColumnInfo', 'column sort_element order') if not include_sort: return [ DetailColumnInfo(column, None, None) for column in detail.get_columns() ] if detail.sort_elements: sort_elements = detail.sort_elements elif detail.columns: sort_elements = [ SortElement( field=detail.get_column(0).field, type='string', direction='ascending', ) ] else: sort_elements = [] # order is 1-indexed sort_elements = dict( (s.field, (s, i + 1)) for i, s in enumerate(sort_elements)) columns = [] for column in detail.get_columns(): sort_element, order = sort_elements.pop(column.field, (None, None)) columns.append(DetailColumnInfo(column, sort_element, order)) # sort elements is now populated with only what's not in any column # add invisible columns for these sort_only = sorted(sort_elements.items(), key=lambda (field, (sort_element, order)): order) for field, (sort_element, order) in sort_only: column = create_temp_sort_column(field, len(columns)) columns.append(DetailColumnInfo(column, sort_element, order)) return columns
def test_sort_cache_search(self): app = Application.wrap(self.get_json('suite-advanced')) app.modules[0].search_config = CaseSearch( properties=[CaseSearchProperty(name='name', label={'en': 'Name'})], ) detail = app.modules[0].case_details.short detail.sort_elements.append( SortElement( field=detail.columns[0].field, type='index', direction='descending', blanks='first', ) ) self.assertXmlPartialEqual( self.get_xml('sort-cache-search'), app.create_suite(), "./detail[@id='m0_search_short']" )
def test_short_detail_xml_with_sort(self): short = self.case_details.short short.display = 'short' short_column = short.get_column(0) short.sort_elements.append( SortElement( field=short_column.field, type='distance', direction='descending', )) suite = self.factory.app.create_suite() template_xpath = './detail[@id="m0_case_short"]/field' self.assertXmlHasXpath(suite, template_xpath) self.assertXmlPartialEqual( """ <partial> <field> <header> <text> <locale id="m0.case_short.case_name_1.header"/> </text> </header> <template> <text> <xpath function="case_name"/> </text> </template> <sort direction="descending" order="1" type="double"> <text> <xpath function="round(distance(case_name, here()))"/> </text> </sort> </field> </partial> """, suite, template_xpath)
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_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)