def test_missing_column_id(self): config = ReportConfiguration( domain='somedomain', config_id='someconfig', aggregation_columns=['doc_id'], columns=[{ 'type': 'percent', # 'column_id': 'pct', 'numerator': { "aggregation": "sum", "field": "pct_numerator", "type": "field", "column_id": "pct_numerator", }, 'denominator': { "aggregation": "sum", "field": "pct_denominator", "type": "field", }, }], filters=[], configured_charts=[] ) with self.assertRaises(BadSpecError): config.validate()
def create_report(self): """ Creates data source and report config. """ matching_data_source = self.ds_builder.get_existing_match() if matching_data_source: data_source_config_id = matching_data_source['id'] else: data_source_config_id = self._build_data_source() report = ReportConfiguration( domain=self.domain, config_id=data_source_config_id, title=self.report_name, aggregation_columns=self._report_aggregation_cols, columns=self._report_columns, filters=self._report_filters, configured_charts=self._report_charts, report_meta=ReportMeta( created_by_builder=True, builder_report_type=self.report_type ) ) report.validate() report.save() return report
def test_expand_column_infos(self): aggregated_report = ReportConfiguration( domain=self.domain.name, config_id=self.data_source._id, aggregation_columns=["opened_by"], columns=[ { "column_id": self.field_name, "type": "field", "field": self.field_name, "aggregation": "expand", } ], filters=[], ) aggregated_report.save() response = self.client.get( self.single_endpoint(aggregated_report._id)) response_dict = json.loads(response.content) columns = response_dict["columns"] for c in columns: self.assertIn("expand_column_value", c) self.assertSetEqual(set(self.case_property_values), {c['expand_column_value'] for c in columns})
def test_report_data_source(self): # bootstrap report data sources against indicator data sources report_config_template = get_sample_report_config() report_config_1 = ReportConfiguration.wrap(report_config_template.to_json()) report_config_1.config_id = self.ds_1._id report_config_2 = ReportConfiguration.wrap(report_config_template.to_json()) report_config_2.config_id = self.ds_2._id # save a few docs to ds 1 sample_doc, _ = get_sample_doc_and_indicators() num_docs = 3 for i in range(num_docs): sample_doc['_id'] = uuid.uuid4().hex self.ds1_adapter.save(sample_doc) # ds 1 should have data, ds2 should not ds1_rows = ReportFactory.from_spec(report_config_1).get_data() self.assertEqual(1, len(ds1_rows)) self.assertEqual(num_docs, ds1_rows[0]['count']) ds2_rows = ReportFactory.from_spec(report_config_2).get_data() self.assertEqual(0, len(ds2_rows)) # save one doc to ds 2 sample_doc['_id'] = uuid.uuid4().hex self.ds2_adapter.save(sample_doc) # ds 1 should still have same data, ds2 should now have one row ds1_rows = ReportFactory.from_spec(report_config_1).get_data() self.assertEqual(1, len(ds1_rows)) self.assertEqual(num_docs, ds1_rows[0]['count']) ds2_rows = ReportFactory.from_spec(report_config_2).get_data() self.assertEqual(1, len(ds2_rows)) self.assertEqual(1, ds2_rows[0]['count'])
def test_get_by_domain(self): results = ReportConfiguration.by_domain("foo") self.assertEqual(2, len(results)) for item in results: self.assertTrue(item.config_id in ("foo1", "foo2")) results = ReportConfiguration.by_domain("not-foo") self.assertEqual(0, len(results))
def testGetByDomain(self): results = ReportConfiguration.by_domain('foo') self.assertEqual(2, len(results)) for item in results: self.assertTrue(item.config_id in ('foo1', 'foo2')) results = ReportConfiguration.by_domain('not-foo') self.assertEqual(0, len(results))
def get_all_report_configs(): from corehq.apps.userreports.models import ReportConfiguration ids = [res['id'] for res in ReportConfiguration.view( 'userreports/report_configs_by_domain', reduce=False, include_docs=False, )] for result in iter_docs(ReportConfiguration.get_db(), ids): yield ReportConfiguration.wrap(result)
def _create_report(self, aggregation_columns, columns): report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source_config._id, title="foo", aggregation_columns=aggregation_columns, columns=columns, ) report_config.save() return report_config
def _build_report(self, vals, field="my_field", build_data_source=True): """ Build a new report, and populate it with cases. Return a ConfigurableReportDataSource and a FieldColumn :param vals: List of values to populate the given report field with. :param field: The name of a field in the data source/report :return: Tuple containing a ConfigurableReportDataSource and FieldColumn. The column is a column mapped to the given field. """ # Create Cases for v in vals: self._new_case({field: v}).save() # Create report data_source_config = DataSourceConfiguration( domain=self.domain, display_name="foo", referenced_doc_type="CommCareCase", table_id=_clean_table_name(self.domain, str(uuid.uuid4().hex)), configured_filter={ "type": "boolean_expression", "operator": "eq", "expression": {"type": "property_name", "property_name": "type"}, "property_value": self.case_type, }, configured_indicators=[ { "type": "expression", "expression": {"type": "property_name", "property_name": field}, "column_id": field, "display_name": field, "datatype": "string", } ], ) data_source_config.validate() data_source_config.save() if build_data_source: tasks.rebuild_indicators(data_source_config._id) report_config = ReportConfiguration( domain=self.domain, config_id=data_source_config._id, title="foo", aggregation_columns=["doc_id"], columns=[{"type": "expanded", "field": field, "display": field, "format": "default"}], filters=[], configured_charts=[], ) report_config.save() data_source = ReportFactory.from_spec(report_config) return data_source, data_source.column_configs[0]
def _create_report(self, aggregation_columns, columns): backend_id = settings.OVERRIDE_UCR_BACKEND or UCR_SQL_BACKEND report_config = ReportConfiguration( domain=self.domain, config_id=self.data_sources[backend_id]._id, title='foo', aggregation_columns=aggregation_columns, columns=columns, ) report_config.save() return report_config
def _create_report(self, aggregation_columns, columns, filters=None): report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, title='foo', aggregation_columns=aggregation_columns, columns=columns, filters=filters or [], ) report_config.save() return report_config
def _create_report(self, aggregation_columns, columns, sort_expression=None): report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, title='foo', aggregation_columns=aggregation_columns, columns=columns, ) if sort_expression: report_config.sort_expression = sort_expression report_config.save() return report_config
def setUpClass(cls): cls.data_source_id = 'd36c7c934cb84725899cca9a0ef96e3a' cls.domain = 'userreport-dbaccessors' cls.report_configs = [ ReportConfiguration(domain=cls.domain, config_id=cls.data_source_id, title='A'), ReportConfiguration(domain=cls.domain, config_id=cls.data_source_id, title='B'), ReportConfiguration(domain=cls.domain, config_id='asabsdjf', title='C'), ReportConfiguration(domain='mallory', config_id=cls.data_source_id, title='X'), ] ReportConfiguration.get_db().bulk_save(cls.report_configs)
def _shared_context(domain): custom_data_sources = list(CustomDataSourceConfiguration.by_domain(domain)) return { 'domain': domain, 'reports': ReportConfiguration.by_domain(domain), 'data_sources': DataSourceConfiguration.by_domain(domain) + custom_data_sources, }
def _get_report_module_context(app, module): def _report_to_config(report): return { 'report_id': report._id, 'title': report.title, 'description': report.description, 'charts': [chart for chart in report.charts if chart.type == 'multibar'], 'filter_structure': report.filters, } all_reports = ReportConfiguration.by_domain(app.domain) warnings = [] validity = module.check_report_validity() if not validity.is_valid: module.report_configs = validity.valid_report_configs warnings.append( gettext_lazy( 'Your app contains references to reports that are deleted. These will be removed on save.') ) return { 'all_reports': [_report_to_config(r) for r in all_reports], 'current_reports': [r.to_json() for r in module.report_configs], 'warnings': warnings, }
def _get_configurable_reports(project): """ User configurable reports """ configs = ReportConfiguration.by_domain(project.name) if configs: def _make_report_class(config): from corehq.apps.reports.generic import GenericReportView # this is really annoying. # the report metadata should really be pulled outside of the report classes @classmethod def get_url(cls, domain, **kwargs): return reverse(ConfigurableReport.slug, args=[domain, config._id]) @classmethod def show_in_navigation(cls, domain=None, project=None, user=None): return config.visible or (user and toggles.USER_CONFIGURABLE_REPORTS.enabled(user.username)) return type('DynamicReport{}'.format(config._id), (GenericReportView, ), { 'name': config.title, 'description': config.description or None, 'get_url': get_url, 'show_in_navigation': show_in_navigation, }) yield (_('Project Reports'), [_make_report_class(config) for config in configs])
def _get_report_module_context(app, module): def _report_to_config(report): return { 'report_id': report._id, 'title': report.title, 'description': report.description, 'charts': [chart for chart in report.charts if chart.type == 'multibar'], 'filter_structure': report.filters_without_prefilters, } all_reports = ReportConfiguration.by_domain(app.domain) + \ StaticReportConfiguration.by_domain(app.domain) warnings = [] validity = module.check_report_validity() # We're now proactively deleting these references, so after that's been # out for a while, this can be removed (say June 2016 or later) if not validity.is_valid: module.report_configs = validity.valid_report_configs warnings.append( gettext_lazy('Your app contains references to reports that are ' 'deleted. These will be removed on save.') ) return { 'all_reports': [_report_to_config(r) for r in all_reports], 'current_reports': [r.to_json() for r in module.report_configs], 'warnings': warnings, }
def _get_report_module_context(app, module): def _report_to_config(report): return { 'report_id': report._id, 'title': report.title, 'description': report.description, 'charts': [chart for chart in report.charts if chart.type == 'multibar'], 'filter_structure': report.filters, } all_reports = ReportConfiguration.by_domain(app.domain) all_report_ids = set([r._id for r in all_reports]) invalid_report_references = filter( lambda r: r.report_id not in all_report_ids, module.report_configs) warnings = [] if invalid_report_references: module.report_configs = filter(lambda r: r.report_id in all_report_ids, module.report_configs) warnings.append( gettext_lazy( 'Your app contains references to reports that are deleted. These will be removed on save.') ) return { 'all_reports': [_report_to_config(r) for r in all_reports], 'current_reports': [r.to_json() for r in module.report_configs], 'invalid_report_references': invalid_report_references, 'warnings': warnings, }
def _get_report_builder_reports(project): from corehq.apps.userreports.models import ReportConfiguration reports = ReportConfiguration.by_domain(project.name) return filter( lambda report: report.report_meta.created_by_builder, reports )
def test_updating_report_that_shares_data_source(self): """ If a report builder builder report shares a data source with another report, then editing the report builder report should result in a new data source being created for the report. """ # Make report builder_form = ConfigureListReportForm( "Test Report", self.app._id, "form", self.form.unique_id, existing_report=None, data={ 'user_filters': '[]', 'default_filters': '[]', 'columns': '[{"property": "/data/first_name", "display_text": "first name"}]', } ) self.assertTrue(builder_form.is_valid()) report = builder_form.create_report() # Make another report that references the same data source report_two = ReportConfiguration( domain="domain", config_id=report.config_id ) report_two.save() # Make an edit to the first report builder report builder_form = ConfigureListReportForm( "Test Report", self.app._id, "form", self.form.unique_id, existing_report=report, data={ 'user_filters': '[]', 'default_filters': '[]', 'columns': '[{"property": "/data/first_name", "display_text": "first name"}]', } ) self.assertTrue(builder_form.is_valid()) report = builder_form.update_report() self.assertNotEqual(report.config_id, report_two.config_id)
def _shared_context(domain): static_reports = list(StaticReportConfiguration.by_domain(domain)) static_data_sources = list(StaticDataSourceConfiguration.by_domain(domain)) return { 'domain': domain, 'reports': ReportConfiguration.by_domain(domain) + static_reports, 'data_sources': DataSourceConfiguration.by_domain(domain) + static_data_sources, }
def _get_existing_reports(domain): from corehq.apps.userreports.models import ReportConfiguration from corehq.apps.userreports.views import TEMP_REPORT_PREFIX existing_reports = ReportConfiguration.by_domain(domain) return [ report for report in existing_reports if not report.title.startswith(TEMP_REPORT_PREFIX) ]
def main_context(self): static_reports = list(StaticReportConfiguration.by_domain(self.domain)) static_data_sources = list(StaticDataSourceConfiguration.by_domain(self.domain)) context = super(BaseUserConfigReportsView, self).main_context context.update({ 'reports': ReportConfiguration.by_domain(self.domain) + static_reports, 'data_sources': DataSourceConfiguration.by_domain(self.domain) + static_data_sources, }) return context
def test_purge_report_from_mobile_ucr(self, get_db): report_config = ReportConfiguration(domain='domain', config_id='foo1') report_config._id = "my_report_config" app = Application.new_app('domain', "App") report_module = app.add_module(ReportModule.new_module('Reports', None)) report_module.report_configs = [ ReportAppConfig(report_id=report_config._id, header={'en': 'CommBugz'}), ReportAppConfig(report_id='other_config_id', header={'en': 'CommBugz'}) ] self.assertEqual(len(app.modules[0].report_configs), 2) with patch('corehq.apps.app_manager.util.get_apps_in_domain') as get_apps: get_apps.return_value = [app] # this will get called when report_config is deleted purge_report_from_mobile_ucr(report_config) self.assertEqual(len(app.modules[0].report_configs), 1)
def migrate_report(self, report_config): rc = ReportConfiguration.wrap(report_config) for column in rc.report_columns: if column.transform and column.transform['type'] == 'translation': column.transform['mobile_or_web'] = 'mobile' column.transform['translations'] = reformat_translations(column.transform['translations']) self.reports_using_transform.add(rc._id) if not self.dry_run: return DocUpdate(rc.to_json())
def create_report(self): """ Creates data source and report config. """ matching_data_source = self.ds_builder.get_existing_match() if matching_data_source: data_source_config_id = matching_data_source['id'] else: data_source_config = DataSourceConfiguration( domain=self.domain, display_name=self.ds_builder.data_source_name, referenced_doc_type=self.ds_builder.source_doc_type, # The uuid gets truncated, so it's not really universally unique. table_id=_clean_table_name(self.domain, str(uuid.uuid4().hex)), configured_filter=self.ds_builder.filter, configured_indicators=self.ds_builder.indicators, meta=DataSourceMeta(build=DataSourceBuildInformation( source_id=self.report_source_id, app_id=self.app._id, app_version=self.app.version, )) ) data_source_config.validate() data_source_config.save() tasks.rebuild_indicators.delay(data_source_config._id) data_source_config_id = data_source_config._id report = ReportConfiguration( domain=self.domain, config_id=data_source_config_id, title=self.report_name, aggregation_columns=self._report_aggregation_cols, columns=self._report_columns, filters=self._report_filters, configured_charts=self._report_charts, report_meta=ReportMeta( created_by_builder=True, builder_report_type=self.report_type ) ) report.validate() report.save() return report
def get_number_of_report_configs_by_data_source(domain, data_source_id): """ Return the number of report configurations that use the given data source. """ from corehq.apps.userreports.models import ReportConfiguration return ReportConfiguration.view( 'userreports/report_configs_by_data_source', reduce=True, key=[domain, data_source_id] ).one()['value']
def clean_columns(json_spec): static_config = StaticReportConfiguration.wrap(deepcopy(json_spec)) report_config = ReportConfiguration.wrap(static_config.config) cleaned_columns = [] for col_spec, wrapped_col in zip(json_spec['config']['columns'], report_config.report_columns): print("Checking column '{}'".format(col_spec['column_id'])) new_col_spec = clean_spec(col_spec, wrapped_col) cleaned_columns.append(order_dict(new_col_spec, COLUMN_PARAMS_ORDER)) return cleaned_columns
def _get_report_module_context(app, module): def _report_to_config(report): return { 'report_id': report._id, 'title': report.title, 'description': report.description, 'charts': [chart for chart in report.charts if chart.type == 'multibar'], 'filter_structure': report.filters_without_prefilters, } all_reports = ReportConfiguration.by_domain(app.domain) + \ StaticReportConfiguration.by_domain(app.domain) validity = module.check_report_validity() # We're now proactively deleting these references, so after that's been # out for a while, this can be removed (say June 2016 or later) if not validity.is_valid: module.report_configs = validity.valid_report_configs filter_choices = [ {'slug': f.doc_type, 'description': f.short_description} for f in get_all_mobile_filter_configs() ] auto_filter_choices = [ {'slug': f.slug, 'description': f.short_description} for f in get_auto_filter_configurations() ] from corehq.apps.app_manager.suite_xml.features.mobile_ucr import get_column_xpath_client_template, get_data_path data_path_placeholders = {} for r in module.report_configs: data_path_placeholders[r.report_id] = {} for chart_id in r.complete_graph_configs.keys(): data_path_placeholders[r.report_id][chart_id] = get_data_path(r, app.domain) context = { 'report_module_options': { 'moduleName': module.name, 'moduleFilter': module.module_filter, 'availableReports': [_report_to_config(r) for r in all_reports], # structure for all reports 'currentReports': [r.to_json() for r in module.report_configs], # config data for app reports 'columnXpathTemplate': get_column_xpath_client_template(app.mobile_ucr_restore_version), 'dataPathPlaceholders': data_path_placeholders, 'languages': app.langs, 'mobileUcrV1': app.mobile_ucr_restore_version == MOBILE_UCR_VERSION_1, 'globalSyncDelay': Domain.get_by_name(app.domain).default_mobile_ucr_sync_interval, }, 'static_data_options': { 'filterChoices': filter_choices, 'autoFilterChoices': auto_filter_choices, 'dateRangeOptions': [choice._asdict() for choice in get_simple_dateranges()], }, 'uuids_by_instance_id': get_uuids_by_instance_id(app.domain), 'legacy_select2': True, } return context
def _safely_get_report_configs(project_name): try: configs = ReportConfiguration.by_domain(project_name) except BadSpecError as e: logging.exception(e) # Pick out the UCRs that don't have spec errors configs = [] for config_id in get_doc_ids_in_domain_by_class(project_name, ReportConfiguration): try: configs.append(ReportConfiguration.get(config_id)) except BadSpecError as e: logging.error("%s with report config %s" % (e.message, config_id)) try: configs.extend(StaticReportConfiguration.by_domain(project_name)) except BadSpecError as e: logging.exception(e) return configs
def setUpClass(cls): super(LocationChoiceProviderTest, cls).setUpClass() report = ReportConfiguration(domain=cls.domain) choice_tuples = [(location.name, SearchableChoice(location.location_id, location.display_name, searchable_text=[ location.site_code, location.name ])) for location in cls.locations.values()] choice_tuples.sort() choices = [choice for name, choice in choice_tuples] cls.web_user = WebUser.create(cls.domain, 'blah', 'password', None, None) cls.choice_provider = LocationChoiceProvider(report, None) cls.choice_provider.configure({ "include_descendants": False, "show_full_path": False, }) cls.static_choice_provider = StaticChoiceProvider(choices) cls.choice_query_context = partial(ChoiceQueryContext, user=cls.web_user)
def setUpClass(cls): cls.domain_obj = create_domain(cls.domain) report = ReportConfiguration(domain=cls.domain) bootstrap_location_types(cls.domain) location_code_name_pairs = ( ('cambridge_ma', 'Cambridge'), ('somerville_ma', 'Somerville'), ('boston_ma', 'Boston'), ) cls.locations = [] choices = [] for location_code, location_name in location_code_name_pairs: location = cls.make_location(location_code, location_name) cls.locations.append(location) choices.append( SearchableChoice( location.location_id, location.sql_location.display_name, searchable_text=[location_code, location_name])) choices.sort(key=lambda choice: choice.display) cls.choice_provider = LocationChoiceProvider(report, None) cls.static_choice_provider = StaticChoiceProvider(choices)
def _release_report(self, domain_link, model): report_id = model['detail']['report_id'] found = False for linked_report in get_report_configs_for_domain( domain_link.linked_domain): if linked_report.report_meta.master_id == report_id: found = True update_linked_ucr(domain_link, linked_report.get_id) if not found: report = ReportConfiguration.get(report_id) if report.report_meta.created_by_builder: view = 'edit_report_in_builder' else: view = 'edit_configurable_report' url = get_url_base() + reverse( view, args=[domain_link.master_domain, report_id]) return self._error_tuple( _('Could not find report. <a href="{}">Click here</a> and click "Link Report" to link this ' + 'report.').format(url), text= _('Could not find report. Please check that the report has been linked.' ), )
def setUpClass(cls): report = ReportConfiguration(domain=cls.domain) cls.web_user = cls.make_web_user('*****@*****.**') cls.users = [ cls.make_mobile_worker('bernice'), cls.web_user, cls.make_mobile_worker('dennis'), cls.make_mobile_worker('elizabeth'), cls.make_mobile_worker('albert'), # test that docs in other domains are filtered out cls.make_mobile_worker('aaa', domain='some-other-domain'), ] choices = [ SearchableChoice(user.get_id, user.raw_username, searchable_text=[ user.username, user.last_name, user.first_name ]) for user in cls.users if user.is_member_of(cls.domain) ] choices.sort(key=lambda choice: choice.display) cls.choice_provider = UserChoiceProvider(report, None) cls.static_choice_provider = StaticChoiceProvider(choices)
def setUpClass(cls): super(DBAccessorsTest, cls).setUpClass() cls.data_source_id = 'd36c7c934cb84725899cca9a0ef96e3a' cls.domain_1 = Domain(name='userreport-dbaccessors') cls.domain_1.save() cls.domain_2 = Domain(name='mallory') cls.domain_2.save() cls.report_configs = [ ReportConfiguration(domain=cls.domain_1.name, config_id=cls.data_source_id, title='A'), ReportConfiguration(domain=cls.domain_1.name, config_id=cls.data_source_id, title='B'), ReportConfiguration(domain=cls.domain_1.name, config_id='asabsdjf', title='C'), ReportConfiguration(domain=cls.domain_2.name, config_id=cls.data_source_id, title='X'), ] ReportConfiguration.get_db().bulk_save(cls.report_configs)
def create_report(self): """ Creates data source and report config. """ matching_data_source = self.ds_builder.get_existing_match() if matching_data_source: data_source_config_id = matching_data_source['id'] else: data_source_config_id = self._build_data_source() report = ReportConfiguration( domain=self.domain, config_id=data_source_config_id, title=self.report_name, aggregation_columns=self._report_aggregation_cols, columns=self._report_columns, filters=self._report_filters, configured_charts=self._report_charts, report_meta=ReportMeta(created_by_builder=True, builder_report_type=self.report_type)) report.validate() report.save() return report
def setUp(self): super(ReportDataTest, self).setUp() # Create report self.domain = 'test-ucr-report-data' self.data_source = DataSourceConfiguration( domain=self.domain, referenced_doc_type='CommCareCase', table_id=uuid.uuid4().hex, configured_filter={}, configured_indicators=[{ "type": "expression", "expression": { "type": "property_name", "property_name": 'name' }, "column_id": 'name', "display_name": 'name', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'number', "display_name": 'number', "datatype": "integer" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'string-number', "display_name": 'string-number', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'just_for_sorting' }, "column_id": 'just_for_sorting', "display_name": 'just_for_sorting', "datatype": "string" }], ) self.data_source.validate() self.data_source.save() self.adapter = get_indicator_adapter(self.data_source) self.adapter.rebuild_table() self.addCleanup(self.data_source.delete) # initialize a report on the data self.report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, aggregation_columns=['doc_id'], columns=[{ "type": "field", "field": "name", "column_id": "name", "display": "Name", "aggregation": "simple", }, { "type": "field", "field": "number", "column_id": "number", "display": "Number", "aggregation": "simple", "calculate_total": True, }, { "type": "expression", "column_id": "ten", "display": "The Number Ten", "expression": { 'type': 'constant', 'constant': 10, } }, { "type": "expression", "column_id": "by_tens", "display": "Counting by tens", "expression": { "type": "evaluator", "statement": "a * b", "context_variables": { "a": { "type": "property_name", "property_name": "number", }, "b": { "type": "property_name", "property_name": "ten", } } } }, { "type": "field", "field": 'string-number', "display": 'Display Number', "aggregation": "simple", "transform": { "type": "translation", "translations": { "0": "zero", "1": { "en": "one", "es": "uno" }, "2": { "en": "two", "es": "dos" } }, }, }], filters=[], configured_charts=[], sort_expression=[{ 'field': 'just_for_sorting', 'order': 'DESC' }]) self.report_config.save() self.addCleanup(self.report_config.delete)
class ReportDataTest(TestCase): def setUp(self): super(ReportDataTest, self).setUp() # Create report self.domain = 'test-ucr-report-data' self.data_source = DataSourceConfiguration( domain=self.domain, referenced_doc_type='CommCareCase', table_id=uuid.uuid4().hex, configured_filter={}, configured_indicators=[{ "type": "expression", "expression": { "type": "property_name", "property_name": 'name' }, "column_id": 'name', "display_name": 'name', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'number', "display_name": 'number', "datatype": "integer" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'string-number', "display_name": 'string-number', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'just_for_sorting' }, "column_id": 'just_for_sorting', "display_name": 'just_for_sorting', "datatype": "string" }], ) self.data_source.validate() self.data_source.save() self.adapter = get_indicator_adapter(self.data_source) self.adapter.rebuild_table() self.addCleanup(self.data_source.delete) # initialize a report on the data self.report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, aggregation_columns=['doc_id'], columns=[{ "type": "field", "field": "name", "column_id": "name", "display": "Name", "aggregation": "simple", }, { "type": "field", "field": "number", "column_id": "number", "display": "Number", "aggregation": "simple", "calculate_total": True, }, { "type": "expression", "column_id": "ten", "display": "The Number Ten", "expression": { 'type': 'constant', 'constant': 10, } }, { "type": "expression", "column_id": "by_tens", "display": "Counting by tens", "expression": { "type": "evaluator", "statement": "a * b", "context_variables": { "a": { "type": "property_name", "property_name": "number", }, "b": { "type": "property_name", "property_name": "ten", } } } }, { "type": "field", "field": 'string-number', "display": 'Display Number', "aggregation": "simple", "transform": { "type": "translation", "translations": { "0": "zero", "1": { "en": "one", "es": "uno" }, "2": { "en": "two", "es": "dos" } }, }, }], filters=[], configured_charts=[], sort_expression=[{ 'field': 'just_for_sorting', 'order': 'DESC' }]) self.report_config.save() self.addCleanup(self.report_config.delete) def _add_some_rows(self, count): rows = [ ReportDataTestRow(uuid.uuid4().hex, i, i) for i in range(count) ] self._add_rows(rows) return rows def _add_rows(self, rows): pillow = get_kafka_ucr_pillow() pillow.bootstrap(configs=[self.data_source]) def _get_case(row): return { '_id': uuid.uuid4().hex, 'domain': self.domain, 'doc_type': 'CommCareCase', 'type': 'city', 'name': row.name, 'number': row.number, 'just_for_sorting': row.sort_key, } for row in rows: pillow.process_change(doc_to_change(_get_case(row))) def test_basic_query(self): # add a few rows to the data source rows = self._add_some_rows(3) # check the returned data from the report looks right report_data_source = ConfigurableReportDataSource.from_spec( self.report_config) report_data = report_data_source.get_data() self.assertEqual(len(rows), len(report_data)) rows_by_name = {r.name: r for r in rows} for row in report_data: self.assertTrue(row['name'] in rows_by_name) self.assertEqual(rows_by_name[row['name']].number, row['number']) self.assertEqual(10, row['ten']) self.assertEqual(10 * row['number'], row['by_tens']) def test_limit(self): count = 5 self._add_some_rows(count) report_data_source = ConfigurableReportDataSource.from_spec( self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) limited_data = report_data_source.get_data(limit=3) self.assertEqual(3, len(limited_data)) self.assertEqual(original_data[:3], limited_data) def test_skip(self): count = 5 self._add_some_rows(count) report_data_source = ConfigurableReportDataSource.from_spec( self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) skipped = report_data_source.get_data(start=3) self.assertEqual(count - 3, len(skipped)) self.assertEqual(original_data[3:], skipped) def test_total_row(self): rows = self._add_some_rows(3) report_data_source = ConfigurableReportDataSource.from_spec( self.report_config) total_number = sum(row.number for row in rows) self.assertEqual(report_data_source.get_total_row(), ['Total', total_number, '', '', '']) def test_transform(self): count = 5 self._add_some_rows(count) report_data_source = ConfigurableReportDataSource.from_spec( self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) rows_by_number = {int(row['number']): row for row in original_data} # Make sure the translations happened self.assertEqual(rows_by_number[0]['string-number'], "zero") self.assertEqual(rows_by_number[1]['string-number'], "one") self.assertEqual(rows_by_number[2]['string-number'], "two") # These last two are untranslated self.assertEqual(rows_by_number[3]['string-number'], "3") self.assertEqual(rows_by_number[4]['string-number'], "4")
def test_duplicate_column_ids(self): spec = self.config._doc spec['columns'].append(spec['columns'][-1]) wrapped = ReportConfiguration.wrap(spec) with self.assertRaises(BadSpecError): wrapped.validate()
def setUpClass(cls): super(TestConfigurableReportDataResource, cls).setUpClass() case_type = "my_case_type" cls.field_name = "my_field" cls.case_property_values = ["foo", "foo", "bar", "baz"] cls.cases = [] for val in cls.case_property_values: id = uuid.uuid4().hex case_block = CaseBlock( create=True, case_id=id, case_type=case_type, update={ cls.field_name: val }, ).as_xml() post_case_blocks([case_block], {'domain': cls.domain.name}) cls.cases.append(CommCareCase.get(id)) cls.report_columns = [{ "column_id": cls.field_name, "type": "field", "field": cls.field_name, "aggregation": "simple", }] cls.report_filters = [{ 'datatype': 'string', 'field': cls.field_name, 'type': 'dynamic_choice_list', 'slug': 'my_field_filter', }] cls.data_source = DataSourceConfiguration( domain=cls.domain.name, referenced_doc_type="CommCareCase", table_id=uuid.uuid4().hex, configured_filter={ "type": "boolean_expression", "operator": "eq", "expression": { "type": "property_name", "property_name": "type" }, "property_value": case_type, }, configured_indicators=[ { "type": "expression", "expression": { "type": "property_name", "property_name": cls.field_name }, "column_id": cls.field_name, "display_name": cls.field_name, "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": "opened_by" }, "column_id": "opened_by", "display_name": "opened_by", "datatype": "string" }, ], ) cls.data_source.validate() cls.data_source.save() rebuild_indicators(cls.data_source._id) cls.report_configuration = ReportConfiguration( domain=cls.domain.name, config_id=cls.data_source._id, aggregation_columns=["doc_id"], columns=cls.report_columns, filters=cls.report_filters, ) cls.report_configuration.save()
def get_sample_report_config(): folder = os.path.join(os.path.dirname(__file__), 'data', 'configs') sample_file = os.path.join(folder, 'sample_report_config.json') with open(sample_file, encoding='utf-8') as f: structure = json.loads(f.read()) return ReportConfiguration.wrap(structure)
def _get_report_module_context(app, module): def _report_to_config(report): return { 'report_id': report._id, 'title': report.title, 'description': report.description, 'charts': [chart for chart in report.charts if chart.type == 'multibar'], 'filter_structure': report.filters_without_prefilters, } all_reports = ReportConfiguration.by_domain(app.domain) + \ StaticReportConfiguration.by_domain(app.domain) validity = module.check_report_validity() # We're now proactively deleting these references, so after that's been # out for a while, this can be removed (say June 2016 or later) if not validity.is_valid: module.report_configs = validity.valid_report_configs filter_choices = [{ 'slug': f.doc_type, 'description': f.short_description } for f in get_all_mobile_filter_configs()] auto_filter_choices = [{ 'slug': f.slug, 'description': f.short_description } for f in get_auto_filter_configurations()] from corehq.apps.app_manager.suite_xml.features.mobile_ucr import get_column_xpath_client_template, get_data_path data_path_placeholders = {} for r in module.report_configs: data_path_placeholders[r.report_id] = {} for chart_id in r.complete_graph_configs.keys(): data_path_placeholders[r.report_id][chart_id] = get_data_path( r, app.domain) context = { 'report_module_options': { 'moduleName': module.name, 'moduleFilter': module.module_filter, 'availableReports': [_report_to_config(r) for r in all_reports], # structure for all reports 'currentReports': [r.to_json() for r in module.report_configs ], # config data for app reports 'columnXpathTemplate': get_column_xpath_client_template(app.mobile_ucr_restore_version), 'dataPathPlaceholders': data_path_placeholders, 'languages': app.langs, 'mobileUcrV1': app.mobile_ucr_restore_version == MOBILE_UCR_VERSION_1, 'globalSyncDelay': Domain.get_by_name(app.domain).default_mobile_ucr_sync_interval, }, 'static_data_options': { 'filterChoices': filter_choices, 'autoFilterChoices': auto_filter_choices, 'dateRangeOptions': [choice._asdict() for choice in get_simple_dateranges()], }, 'uuids_by_instance_id': get_uuids_by_instance_id(app.domain), 'legacy_select2': True, } return context
def _get_report_builder_reports(project): from corehq.apps.userreports.models import ReportConfiguration reports = ReportConfiguration.by_domain(project.name) return [ report for report in reports if report.report_meta.created_by_builder ]
def obj_get_list(self, bundle, **kwargs): domain = kwargs['domain'] return ReportConfiguration.by_domain(domain)
def config(self): if self.report_id is None: return ReportConfiguration(domain=self.domain) return get_report_config_or_404(self.report_id, self.domain)[0]
def number_of_report_builder_reports(domain): from corehq.apps.userreports.models import ReportConfiguration existing_reports = ReportConfiguration.by_domain(domain) builder_reports = filter( lambda report: report.report_meta.created_by_builder, existing_reports) return len(builder_reports)
def test_report_module(self): from corehq.apps.userreports.tests.utils import get_sample_report_config app = Application.new_app('domain', "Untitled Application") report_module = app.add_module(ReportModule.new_module( 'Reports', None)) report_module.unique_id = 'report_module' report = get_sample_report_config() report._id = 'd3ff18cd83adf4550b35db8d391f6008' report_app_config = ReportAppConfig( report_id=report._id, header={'en': 'CommBugz'}, uuid='ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i', xpath_description='"report description"', use_xpath_description=True) report_app_config._report = report report_module.report_configs = [report_app_config] report_module._loaded = True self.assertXmlPartialEqual( self.get_xml('reports_module_menu'), app.create_suite(), "./menu", ) app.multimedia_map = { "jr://file/commcare/image/module0_en.png": HQMediaMapItem( multimedia_id='bb4472b4b3c702f81c0b208357eb22f8', media_type='CommCareImage', unique_id='fe06454697634053cdb75fd9705ac7e6', ), } report_module.media_image = { 'en': 'jr://file/commcare/image/module0_en.png', } self.assertXmlPartialEqual( self.get_xml('reports_module_menu_multimedia'), app.create_suite(), "./menu", ) self.assertXmlPartialEqual( self.get_xml('reports_module_select_detail'), app.create_suite(), "./detail[@id='reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i.select']", ) self.assertXmlPartialEqual( self.get_xml( 'reports_module_summary_detail_use_xpath_description'), app.create_suite(), "./detail[@id='reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i.summary']", ) self.assertXmlPartialEqual( self.get_xml('reports_module_data_detail'), app.create_suite(), "./detail/detail[@id='reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i.data']", ) self.assertXmlPartialEqual( self.get_xml('reports_module_data_entry'), app.create_suite(), "./entry", ) self.assertIn( 'reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i=CommBugz', app.create_app_strings('default'), ) report_app_config.use_xpath_description = False self.assertXmlPartialEqual( self.get_xml( 'reports_module_summary_detail_use_localized_description'), app.create_suite(), "./detail[@id='reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i.summary']", ) # Tuple mapping translation formats to the expected output of each translation_formats = [ ({ u'एक': { 'en': 'one', 'es': 'uno', }, '2': { 'en': 'two', 'es': 'dos\'', 'hin': u'दो', }, }, 'reports_module_data_detail-translated'), ({ u'एक': 'one', '2': 'two', }, 'reports_module_data_detail-translated-simple'), ({ u'एक': { 'en': 'one', 'es': 'uno', }, '2': 'two', }, 'reports_module_data_detail-translated-mixed'), ] for translation_format, expected_output in translation_formats: report_app_config._report.columns[0]['transform'] = { 'type': 'translation', 'translations': translation_format, } report_app_config._report = ReportConfiguration.wrap( report_app_config._report._doc) self.assertXmlPartialEqual( self.get_xml(expected_output), app.create_suite(), "./detail/detail[@id='reports.ip1bjs8xtaejnhfrbzj2r6v1fi6hia4i.data']", )
def _build_report_and_view(self): # Create report data_source_config = DataSourceConfiguration( domain=self.domain, display_name='foo', referenced_doc_type='CommCareCase', table_id="woop_woop", configured_filter={ "type": "boolean_expression", "operator": "eq", "expression": { "type": "property_name", "property_name": "type" }, "property_value": self.case_type, }, configured_indicators=[ { "type": "expression", "expression": { "type": "property_name", "property_name": 'fruit' }, "column_id": 'indicator_col_id_fruit', "display_name": 'indicator_display_name_fruit', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'num1' }, "column_id": 'indicator_col_id_num1', "datatype": "integer" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'num2' }, "column_id": 'indicator_col_id_num2', "datatype": "integer" }, ], ) data_source_config.validate() data_source_config.save() self.addCleanup(data_source_config.delete) tasks.rebuild_indicators(data_source_config._id) adapter = get_indicator_adapter(data_source_config) adapter.refresh_table() report_config = ReportConfiguration( domain=self.domain, config_id=data_source_config._id, title='foo', aggregation_columns=['doc_id'], columns=[ { "type": "field", "display": "report_column_display_fruit", "field": 'indicator_col_id_fruit', 'column_id': 'report_column_col_id_fruit', 'aggregation': 'simple' }, { "type": "percent", "display": "report_column_display_percent", 'column_id': 'report_column_col_id_percent', 'format': 'percent', "denominator": { "type": "field", "aggregation": "sum", "field": "indicator_col_id_num1", "column_id": "report_column_col_id_percent_num1" }, "numerator": { "type": "field", "aggregation": "sum", "field": "indicator_col_id_num2", "column_id": "report_column_col_id_percent_num2" } }, ], ) report_config.save() self.addCleanup(report_config.delete) view = ConfigurableReport(request=HttpRequest()) view._domain = self.domain view._lang = "en" view._report_config_id = report_config._id return report_config, view
def delete_all_report_configs(): from corehq.apps.userreports.models import ReportConfiguration delete_all_docs_by_doc_type(ReportConfiguration.get_db(), ('ReportConfiguration', ))
def _get_master_model_status(self, apps, fixtures, reports, keywords, ignore_models=None): model_status = [] ignore_models = ignore_models or [] for model, name in LINKED_MODELS: if (model not in ignore_models and model not in (MODEL_APP, MODEL_FIXTURE, MODEL_REPORT, MODEL_KEYWORD) and (model != MODEL_CASE_SEARCH or toggles.SYNC_SEARCH_CASE_CLAIM.enabled(self.domain)) and (model != MODEL_DATA_DICTIONARY or toggles.DATA_DICTIONARY.enabled(self.domain)) and (model != MODEL_DIALER_SETTINGS or toggles.WIDGET_DIALER.enabled(self.domain)) and (model != MODEL_OTP_SETTINGS or toggles.GAEN_OTP_SERVER.enabled(self.domain)) and (model != MODEL_HMAC_CALLOUT_SETTINGS or toggles.HMAC_CALLOUT.enabled(self.domain))): model_status.append({ 'type': model, 'name': name, 'last_update': ugettext('Never'), 'detail': None, 'can_update': True }) linked_models = dict(LINKED_MODELS) for app in apps.values(): update = { 'type': MODEL_APP, 'name': '{} ({})'.format(linked_models['app'], app.name), 'last_update': None, 'detail': AppLinkDetail(app_id=app._id).to_json(), 'can_update': True } model_status.append(update) for fixture in fixtures.values(): update = { 'type': MODEL_FIXTURE, 'name': '{} ({})'.format(linked_models['fixture'], fixture.tag), 'last_update': None, 'detail': FixtureLinkDetail(tag=fixture.tag).to_json(), 'can_update': fixture.is_global, } model_status.append(update) for report in reports.values(): report = ReportConfiguration.get(report.get_id) update = { 'type': MODEL_REPORT, 'name': f"{linked_models['report']} ({report.title})", 'last_update': None, 'detail': ReportLinkDetail(report_id=report.get_id).to_json(), 'can_update': True, } model_status.append(update) for keyword in keywords.values(): update = { 'type': MODEL_KEYWORD, 'name': f"{linked_models['keyword']} ({keyword.keyword})", 'last_update': None, 'detail': KeywordLinkDetail(keyword_id=str(keyword.id)).to_json(), 'can_update': True, } model_status.append(update) return model_status
def _get_model_status(self, master_link, apps, fixtures, reports, keywords): model_status = [] if not master_link: return model_status models_seen = set() history = DomainLinkHistory.objects.filter( link=master_link ).annotate(row_number=RawSQL( 'row_number() OVER (PARTITION BY model, model_detail ORDER BY date DESC)', [])) linked_models = dict(LINKED_MODELS) timezone = get_timezone_for_request() for action in history: models_seen.add(action.model) if action.row_number != 1: # first row is the most recent continue name = linked_models[action.model] update = { 'type': action.model, 'name': name, 'last_update': server_to_user_time(action.date, timezone), 'detail': action.model_detail, 'can_update': True } if action.model == 'app': app_name = ugettext('Unknown App') if action.model_detail: detail = action.wrapped_detail app = apps.pop(detail.app_id, None) app_name = app.name if app else detail.app_id if app: update['detail'] = action.model_detail else: update['can_update'] = False else: update['can_update'] = False update['name'] = '{} ({})'.format(name, app_name) if action.model == 'fixture': tag_name = ugettext('Unknown Table') can_update = False if action.model_detail: detail = action.wrapped_detail tag = action.wrapped_detail.tag try: fixture = fixtures.get(tag) del fixtures[tag] except KeyError: fixture = get_fixture_data_type_by_tag( self.domain, tag) tag_name = fixture.tag can_update = fixture.is_global update['name'] = f'{name} ({tag_name})' update['can_update'] = can_update if action.model == 'report': report_id = action.wrapped_detail.report_id try: report = reports.get(report_id) del reports[report_id] except KeyError: report = ReportConfiguration.get(report_id) update['name'] = f'{name} ({report.title})' if action.model == 'keyword': keyword_id = action.wrapped_detail.linked_keyword_id try: keyword = keywords[keyword_id].keyword del keywords[keyword_id] except KeyError: try: keyword = Keyword.objects.get(id=keyword_id).keyword except Keyword.DoesNotExist: keyword = ugettext_lazy("Deleted Keyword") update['can_update'] = False update['name'] = f'{name} ({keyword})' model_status.append(update) # Add in models and apps that have never been synced model_status.extend( self._get_master_model_status(apps, fixtures, reports, keywords, ignore_models=models_seen)) return model_status
def test_report_builder_datasource_deactivation(self): def _get_data_source(id_): return get_datasource_config(id_, self.project.name)[0] # Upgrade the domain # (for the upgrade to work, there has to be an existing subscription, # which is why we subscribe to advanced first) self._subscribe_to_advanced() pro_with_rb_sub = self._subscribe_to_pro_with_rb() # Create reports and data sources builder_report_data_source = DataSourceConfiguration( domain=self.project.name, is_deactivated=False, referenced_doc_type="XFormInstance", table_id="foo", ) other_data_source = DataSourceConfiguration( domain=self.project.name, is_deactivated=False, referenced_doc_type="XFormInstance", table_id="bar", ) builder_report_data_source.save() other_data_source.save() report_builder_report = ReportConfiguration( domain=self.project.name, config_id=builder_report_data_source._id, report_meta=ReportMeta(created_by_builder=True), ) report_builder_report.save() # downgrade the domain community_sub = pro_with_rb_sub.change_plan( DefaultProductPlan.get_default_plan_version()) # Check that the builder data source is deactivated builder_report_data_source = _get_data_source( builder_report_data_source._id) self.assertTrue(builder_report_data_source.is_deactivated) # Check that the other data source has not been deactivated other_data_source = _get_data_source(other_data_source._id) self.assertFalse(other_data_source.is_deactivated) # upgrade the domain # (for the upgrade to work, there has to be an existing subscription, # which is why we subscribe to advanced first) community_sub.change_plan( DefaultProductPlan.get_default_plan_version( edition=SoftwarePlanEdition.ADVANCED)) pro_with_rb_sub = self._subscribe_to_pro_with_rb() # check that the data source is activated builder_report_data_source = _get_data_source( builder_report_data_source._id) self.assertFalse(builder_report_data_source.is_deactivated) # delete the data sources builder_report_data_source.delete() other_data_source.delete() # Delete the report report_builder_report.delete() # reset the subscription pro_with_rb_sub.change_plan( DefaultProductPlan.get_default_plan_version())
def _build_report(self, vals, field='my_field', build_data_source=True): """ Build a new report, and populate it with cases. Return a ConfigurableReportDataSource and a FieldColumn :param vals: List of values to populate the given report field with. :param field: The name of a field in the data source/report :return: Tuple containing a ConfigurableReportDataSource and FieldColumn. The column is a column mapped to the given field. """ # Create Cases for v in vals: update_props = {field: v} if v is not None else {} self._new_case(update_props).save() # Create report data_source_config = DataSourceConfiguration( domain=self.domain, display_name='foo', referenced_doc_type='CommCareCase', table_id=_clean_table_name(self.domain, str(uuid.uuid4().hex)), configured_filter={ "type": "boolean_expression", "operator": "eq", "expression": { "type": "property_name", "property_name": "type" }, "property_value": self.case_type, }, configured_indicators=[{ "type": "expression", "expression": { "type": "property_name", "property_name": field }, "column_id": field, "display_name": field, "datatype": "string" }], ) data_source_config.validate() data_source_config.save() self.addCleanup(data_source_config.delete) if build_data_source: tasks.rebuild_indicators(data_source_config._id) adapter = get_indicator_adapter(data_source_config) adapter.refresh_table() report_config = ReportConfiguration(domain=self.domain, config_id=data_source_config._id, title='foo', aggregation_columns=['doc_id'], columns=[{ "type": "expanded", "field": field, "display": field, "format": "default", }], filters=[], configured_charts=[]) report_config.save() self.addCleanup(report_config.delete) data_source = ReportFactory.from_spec(report_config) adapter = get_indicator_adapter(data_source_config) if build_data_source: adapter.refresh_table() return data_source, data_source.top_level_columns[0]
def test_config_id_is_required(self): with self.assertRaises(BadValueError): ReportConfiguration(domain='foo').save()
class ReportDataTest(TestCase): def setUp(self): super(ReportDataTest, self).setUp() # Create report self.domain = 'test-ucr-report-data' self.data_source = DataSourceConfiguration( domain=self.domain, referenced_doc_type='CommCareCase', table_id=uuid.uuid4().hex, configured_filter={}, configured_indicators=[{ "type": "expression", "expression": { "type": "property_name", "property_name": 'name' }, "column_id": 'name', "display_name": 'name', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'number', "display_name": 'number', "datatype": "integer" }], ) self.data_source.validate() self.data_source.save() self.adapter = get_indicator_adapter(self.data_source) self.adapter.rebuild_table() self.addCleanup(self.data_source.delete) # initialize a report on the data self.report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, aggregation_columns=['doc_id'], columns=[{ "type": "field", "field": "name", "column_id": "name", "display": "Name", "aggregation": "simple", }, { "type": "field", "field": "number", "column_id": "number", "display": "Number", "aggregation": "simple", }, { "type": "expression", "column_id": "ten", "display": "The Number Ten", "expression": { 'type': 'constant', 'constant': 10, } }, { "type": "expression", "column_id": "by_tens", "display": "Counting by tens", "expression": { "type": "evaluator", "statement": "a * b", "context_variables": { "a": { "type": "property_name", "property_name": "number", }, "b": { "type": "property_name", "property_name": "ten", } } } }], filters=[], configured_charts=[]) self.report_config.save() self.addCleanup(self.report_config.delete) def _add_some_rows(self, count): rows = [ReportDataTestRow(uuid.uuid4().hex, i) for i in range(count)] self._add_rows(rows) self.adapter.refresh_table() return rows def _add_rows(self, rows): pillow = get_kafka_ucr_pillow() pillow.bootstrap(configs=[self.data_source]) def _get_case(row): return { '_id': uuid.uuid4().hex, 'domain': self.domain, 'doc_type': 'CommCareCase', 'type': 'city', 'name': row.name, 'number': row.number, } for row in rows: pillow.process_change(doc_to_change(_get_case(row))) @run_with_all_ucr_backends def test_basic_query(self): # add a few rows to the data source rows = self._add_some_rows(3) # check the returned data from the report looks right report_data_source = ReportFactory.from_spec(self.report_config) report_data = report_data_source.get_data() self.assertEqual(len(rows), len(report_data)) rows_by_name = {r.name: r for r in rows} for row in report_data: self.assertTrue(row['name'] in rows_by_name) self.assertEqual(rows_by_name[row['name']].number, row['number']) self.assertEqual(10, row['ten']) self.assertEqual(10 * row['number'], row['by_tens']) @run_with_all_ucr_backends def test_limit(self): count = 5 self._add_some_rows(count) report_data_source = ReportFactory.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) limited_data = report_data_source.get_data(limit=3) self.assertEqual(3, len(limited_data)) self.assertEqual(original_data[:3], limited_data) @run_with_all_ucr_backends def test_skip(self): count = 5 self._add_some_rows(count) report_data_source = ReportFactory.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) skipped = report_data_source.get_data(start=3) self.assertEqual(count - 3, len(skipped)) self.assertEqual(original_data[3:], skipped)
def setUp(self): super(ReportTranslationTest, self).setUp() report = ReportConfiguration.by_domain(self.DOMAIN)[0] self.report_source = ReportFactory.from_spec(report)
def tearDownClass(cls): ReportConfiguration.get_db().bulk_delete(cls.report_configs) cls.domain_1.delete() cls.domain_2.delete()
def _get_report_module_context(app, module): def _report_to_config(report): return { 'report_id': report._id, 'title': report.title, 'description': report.description, 'charts': [chart for chart in report.charts if chart.type == 'multibar'], 'filter_structure': report.filters_without_prefilters, } all_reports = ReportConfiguration.by_domain(app.domain) + \ StaticReportConfiguration.by_domain(app.domain) validity = module.check_report_validity() # We're now proactively deleting these references, so after that's been # out for a while, this can be removed (say June 2016 or later) if not validity.is_valid: module.report_configs = validity.valid_report_configs filter_choices = [{ 'slug': f.doc_type, 'description': f.short_description } for f in get_all_mobile_filter_configs()] auto_filter_choices = [{ 'slug': f.slug, 'description': f.short_description } for f in get_auto_filter_configurations()] from corehq.apps.app_manager.suite_xml.features.mobile_ucr import COLUMN_XPATH_CLIENT_TEMPLATE, get_data_path current_reports = [] data_path_placeholders = {} for r in module.report_configs: r.migrate_graph_configs(app.domain) current_reports.append(r.to_json()) data_path_placeholders[r.report_id] = {} for chart_id in r.complete_graph_configs.keys(): data_path_placeholders[r.report_id][chart_id] = get_data_path( r, app.domain) context = { 'report_module_options': { 'moduleName': module.name, 'moduleFilter': module.module_filter, 'availableReports': [_report_to_config(r) for r in all_reports], # structure for all reports 'currentReports': current_reports, # config data for app reports 'columnXpathTemplate': COLUMN_XPATH_CLIENT_TEMPLATE, 'dataPathPlaceholders': data_path_placeholders, 'languages': app.langs, }, 'static_data_options': { 'filterChoices': filter_choices, 'autoFilterChoices': auto_filter_choices, 'dateRangeOptions': [choice._asdict() for choice in get_simple_dateranges()], }, } return context
MAKE_REPORT_CONFIG = lambda domain, report_id: ReportConfiguration( _id=report_id, title="Entry Report", aggregation_columns=["color_94ec39e6"], config_id="516c494736e95b023cc7845b557de0f5", domain=domain, report_meta=ReportMeta(builder_report_type="chart", created_by_builder=True), columns=[ FieldColumn(type='field', aggregation="simple", column_id="color_94ec39e6", display="color", field="color_94ec39e6").to_json(), ], configured_charts=[ MultibarChartSpec(type='multibar', chart_id="7451243209119342931", x_axis_column="color_94ec39e6", y_axis_columns=[ GraphDisplayColumn(column_id="count", display="count") ]).to_json() ], filters=[ DynamicChoiceListFilterSpec(type='dynamic_choice_list', display="owner name", field="computed_owner_name_40cc88a0", slug="computed_owner_name_40cc88a0_1"). to_json(), ChoiceListFilterSpec(type='choice_list', display="fav color", field="fav_fruit_abc123", slug="fav_fruit_abc123_1", choices=[ FilterChoice(value='a', display='apple'), FilterChoice(value='b', display='banana'), FilterChoice(value='c', display='clementine'), ]).to_json() ], )
def _get_report_builder_reports(project): from corehq.apps.userreports.models import ReportConfiguration reports = ReportConfiguration.by_domain(project.name) return filter(lambda report: report.report_meta.created_by_builder, reports)