class ChildProtectionData(AgeGenderFilteredReport): title = 'Number and Type of Incidents of Abuse Reported at CVSU' chart_x_label = 'CVSU Location' chart_y_label = 'Number of incidents' table_name = make_ctable_table_name('cvsulive_UnicefMalawiFluff') @property def columns(self): cat_group = DataTablesColumnGroup("Category of abuse") return [ self.location_column, DatabaseColumn("Physical", SumColumn('abuse_category_physical_total'), header_group=cat_group), DatabaseColumn("Sexual", SumColumn('abuse_category_sexual_total'), header_group=cat_group), DatabaseColumn("Emotional", SumColumn('abuse_category_psychological_total'), header_group=cat_group), DatabaseColumn("Neglect", SumColumn('abuse_category_neglect_total'), header_group=cat_group), DatabaseColumn("Exploitation", SumColumn('abuse_category_exploitation_total'), header_group=cat_group), DatabaseColumn("Other", SumColumn('abuse_category_other_total'), header_group=cat_group), DatabaseColumn("Total incidents reported", SumColumn('abuse_category_total_total'), header_group=cat_group) ]
class CVSUIncidentResolutionData(BaseSqlData): title = 'Incident Resolution' chart_x_label = 'CVSU Location' chart_y_label = 'Number of incidents' table_name = make_ctable_table_name('cvsulive_UnicefMalawiFluff') @property def columns(self): return [ self.location_column, DatabaseColumn("Resolved at CVSU", SumColumn('resolution_resolved_at_cvsu_total')), DatabaseColumn("Referred to TA", SumColumn('resolution_referred_ta_total')), DatabaseColumn("Referred to TA Court", SumColumn('resolution_referral_ta_court_total')), DatabaseColumn("Referred to Police", SumColumn('resolution_referral_police_total')), DatabaseColumn( "Referred to Social Welfare", SumColumn('resolution_referral_social_welfare_total')), DatabaseColumn("Referred to NGO", SumColumn('resolution_referral_ngo_total')), DatabaseColumn("Referred to Other", SumColumn('resolution_referral_other_total')), DatabaseColumn("Unresolved", SumColumn('resolution_unresolved_total')), DatabaseColumn("Case Withdrawn", SumColumn('resolution_case_withdrawn_total')), DatabaseColumn("Other", SumColumn('resolution_other_total')), DatabaseColumn("Total", SumColumn('resolution_total_total')), ]
class PSISQLEventsReport(PSISQLReport): fields = [ 'corehq.apps.reports.filters.dates.DatespanFilter', 'psi.reports.StateDistrictField', 'psi.reports.AASD', ] name = "Event Demonstration Report (SQL)" exportable = True emailable = True slug = "event_demonstations_sql" section_name = "event demonstrations" default_aggregation = 'district' table_name = make_ctable_table_name('psi-unicef_psi_events') @property def columns(self): return self.initial_columns + [ DatabaseColumn("Number of events", SumColumn('events')), DatabaseColumn("Number of male attendees", SumColumn('males')), DatabaseColumn("Number of female attendees", SumColumn('females')), DatabaseColumn("Total number of attendees", SumColumn('attendees')), DatabaseColumn("Total number of leaflets distributed", SumColumn('leaflets')), DatabaseColumn("Total number of gifts distributed", SumColumn('gifts')) ]
class PSISQLSensitizationReport(PSISQLReport): name = "Sensitization Sessions Report (SQL)" exportable = True emailable = True slug = "sensitization_sessions_sql" section_name = "sensitization sessions" fields = [ 'corehq.apps.reports.filters.dates.DatespanFilter', 'psi.reports.StateDistrictBlockField', 'psi.reports.AASDB', ] default_aggregation = 'block' table_name = make_ctable_table_name('psi-unicef_psi_sensitization') @property def columns(self): return self.initial_columns + [ DatabaseColumn("Number of Sessions", SumColumn("sessions")), DatabaseColumn("Ayush Sensitized", SumColumn("ayush_doctors")), DatabaseColumn("MBBS Sensitized", SumColumn("mbbs_doctors")), DatabaseColumn("Asha Supervisors Sensitized", SumColumn("asha_supervisors")), DatabaseColumn("Ashas Sensitized", SumColumn("ashas")), DatabaseColumn("AWW Sensitized", SumColumn("awws")), DatabaseColumn("Others (ANM, MPW, etc.)", SumColumn("other")), DatabaseColumn("VHND Attendees", SumColumn('attendees')) ]
class ChildrenInHouseholdData(AgeGenderFilteredReport): title = 'Number of Children in Survivor Household' chart_x_label = 'CVSU Location' chart_y_label = 'Number of children' table_name = make_ctable_table_name('cvsulive_UnicefMalawiFluff') has_total_column = False @property def columns(self): return [ self.location_column, DatabaseColumn("Children per household experiencing abuse", SumColumn('abuse_children_abused_total')), DatabaseColumn("Total number of children in household", SumColumn('abuse_children_in_household_total')), ]
class PSISQLTrainingReport(PSISQLReport): name = "Training Sessions Report (SQL)" exportable = True emailable = True slug = "training_sessions_sql" section_name = "training sessions" fields = [ 'corehq.apps.reports.filters.dates.DatespanFilter', 'psi.reports.StateDistrictField', 'psi.reports.AASD', ] default_aggregation = 'district' table_name = make_ctable_table_name("psi-unicef_psi_training") @property def columns(self): return self.initial_columns + [ DatabaseColumn("Private: Number of Trainings", SumColumn("priv_trained")), DatabaseColumn("Private: Ayush trained", SumColumn("priv_ayush_trained")), DatabaseColumn("Private: Allopathics trained", SumColumn("priv_allo_trained")), DatabaseColumn("Private: Learning changed", SumColumn("priv_avg_diff")), DatabaseColumn("Private: Num > 80%", SumColumn("priv_gt80")), DatabaseColumn("Public: Number of Trainings", SumColumn("pub_trained")), DatabaseColumn("Public: Ayush trained", SumColumn("pub_ayush_trained")), DatabaseColumn("Public: Allopathics trained", SumColumn("pub_allo_trained")), DatabaseColumn("Public: Learning changed", SumColumn("pub_avg_diff")), DatabaseColumn("Public: Num > 80%", SumColumn("pub_gt80")), DatabaseColumn("Depot: Number of Trainings", SumColumn("dep_trained")), DatabaseColumn("Depot: Number of Personnel Trained", SumColumn("dep_pers_trained")), DatabaseColumn("Depot: Learning changed", SumColumn("dep_avg_diff")), DatabaseColumn("Depot: Num > 80%", SumColumn("dep_gt80")), DatabaseColumn("FLW: Number of Trainings", SumColumn("flw_trained")), DatabaseColumn("FLW: Number of Personnel Trained", SumColumn("flw_pers_trained")), DatabaseColumn("FLW: Learning changed", SumColumn("flw_avg_diff")), DatabaseColumn("FLW: Num > 80%", SumColumn("flw_gt80")), ]
class PSISQLHouseholdReport(PSISQLReport): name = "Household Demonstrations Report (SQL)" exportable = True emailable = True slug = "household_demonstrations_sql" section_name = "household demonstrations" fields = [ 'corehq.apps.reports.filters.dates.DatespanFilter', 'psi.reports.AsyncPlaceField', 'psi.reports.DemoTypeField', 'psi.reports.AASDBV', ] default_aggregation = 'village' table_name = make_ctable_table_name( "psi-unicef_psi_household_demonstrations") @property @memoized def selected_dt(self): return self.request.GET.get('demo_type', "") @property def keys(self): combos = get_unique_combinations(self.domain, place_types=self.place_types, place=self.selected_fixture()) selected_demo_type = self.request.GET.get('demo_type', "") for c in combos: if self.selected_dt: if self.selected_dt == '_all': for dt in DEMO_TYPES: yield [c[pt] for pt in self.place_types] + [dt] else: yield [c[pt] for pt in self.place_types] + [selected_demo_type] else: yield [c[pt] for pt in self.place_types] @property def columns(self): return self.initial_columns + [ DatabaseColumn("Number of demonstrations done", SumColumn("demonstrations")), DatabaseColumn("Number of 0-6 year old children", SumColumn("children")), DatabaseColumn("Total number of leaflets distributed", SumColumn("leaflets")), DatabaseColumn("Number of kits sold", SumColumn("kits")) ]
class CVSUServicesData(BaseSqlData): title = 'Services Provided' chart_x_label = 'CVSU Location' chart_y_label = 'Number of incidents' table_name = make_ctable_table_name('cvsulive_UnicefMalawiFluff') @property def columns(self): return [ self.location_column, DatabaseColumn("Counselling", SumColumn('service_counselling_total')), DatabaseColumn("Psychosocial Support", SumColumn('service_psychosocial_support_total')), DatabaseColumn("First Aid", SumColumn('service_first_aid_total')), DatabaseColumn("Shelter", SumColumn('service_shelter_total')), DatabaseColumn("Referral", SumColumn('service_referral_total')), DatabaseColumn("Mediation", SumColumn('service_mediation_total')), DatabaseColumn("Other", SumColumn('service_other_total')), DatabaseColumn("Total", SumColumn('service_total_total')), ]
class CVSUActivityData(BaseSqlData): title = 'Activities Performed' chart_x_label = 'CVSU Location' chart_y_label = 'Number of reports' table_name = make_ctable_table_name('cvsulive_UnicefMalawiFluff') @property def columns(self): return [ self.location_column, DatabaseColumn("Incidents of Abuse", SumColumn('incidents_total')), DatabaseColumn("Outreach activities", SumColumn('outreach_total')), DatabaseColumn("IGA Reports", SumColumn('iga_total')), AggregateColumn( "Total", self.sum, [AliasColumn('incidents_total'), AliasColumn('outreach_total')]), ] def sum(self, no_incidents, outreach): return (no_incidents or 0) + (outreach or 0)
class CareReport(SqlTabularReport, CustomProjectReport, DatespanMixin): exportable = True emailable = True table_name = make_ctable_table_name("care-ihapc-live_CareSAFluff") report_template_path = "care_sa/reports/grouped.html" fields = [ 'corehq.apps.reports.filters.dates.DatespanFilter', 'custom.reports.care_sa.reports.sql.ProvinceField', 'custom.reports.care_sa.reports.sql.CBOField', 'custom.reports.care_sa.reports.sql.ShowAgeField', 'custom.reports.care_sa.reports.sql.ShowGenderField', ] def selected_province(self): fixture = self.request.GET.get('fixture_id', "") return fixture.split(':')[1] if fixture else None def selected_cbo(self): group = self.request.GET.get('group', '') return group def show_age(self): show_age_field = self.request.GET.get('show_age_field', '') return show_age_field == 'on' def show_gender(self): show_gender_field = self.request.GET.get('show_gender_field', '') return show_gender_field == 'on' @property def filters(self): filters = [ "domain = :domain", "date between :startdate and :enddate", ] if self.selected_province(): filters.append("province = :province") if self.selected_cbo(): filters.append("cbo = :cbo") return filters @property def group_by(self): groups = [] if not self.selected_province(): groups.append('province') elif not self.selected_cbo(): groups.append('cbo') else: groups.append('user_id') if self.show_age(): groups.append('age_group') if self.show_gender(): groups.append('gender') return groups @property def filter_values(self): return dict( domain=self.domain, startdate=self.datespan.startdate_param_utc, enddate=self.datespan.enddate_param_utc, province=self.selected_province(), cbo=self.selected_cbo(), ) def first_indicator_column_index(self): return len(self.columns) - len(self.report_columns) @property def headers(self): """ Override the headers method to be able to add male/female sub header columns. """ header_columns = [] for idx, column in enumerate(self.columns): if idx >= self.first_indicator_column_index() and self.show_gender( ): group = DataTablesColumnGroup(column.header) group.add_column(DataTablesColumn("male", sortable=False)) group.add_column(DataTablesColumn("female", sortable=False)) header_columns.append(group) else: # gender is included in the columns to populate data # but we don't show it on the page if column.header != 'Gender': header_columns.append( DataTablesColumn(column.header, sortable=False)) # insert a blank header to display the "all genders/ages" message if not self.show_gender() and not self.show_age(): header_columns.insert(1, DataTablesColumn('', sortable=False)) return DataTablesHeader(*header_columns) @property def columns(self): if not self.selected_province(): columns = [ DatabaseColumn("Province", SimpleColumn('province'), sortable=False) ] elif not self.selected_cbo(): columns = [ DatabaseColumn("CBO", SimpleColumn('cbo'), sortable=False) ] else: columns = [ DatabaseColumn("User", SimpleColumn('user_id'), sortable=False) ] if self.show_gender(): columns.append( DatabaseColumn("Gender", SimpleColumn('gender'), sortable=False)) if self.show_age(): columns.append( DatabaseColumn("Age", SimpleColumn('age_group'), sortable=False)) for column_attrs in self.report_columns: text, name = column_attrs[:2] name = '%s_total' % name if len(column_attrs) == 2: column = DatabaseColumn(text, CountColumn(name), sortable=False) elif column_attrs[2] == 'SumColumn': column = DatabaseColumn(text, SumColumn(name), sortable=False) columns.append(column) return columns @property def keys(self): [self.domain] @property def export_table(self): headers = self.headers rows = self.rows formatted_rows = [] for row in rows: if not self.show_age() and not self.show_gender(): if 'total_width' not in row: formatted_rows.append([row['username']] + ['All genders and ages'] + row['row_data']) elif not self.show_age() and self.show_gender(): if 'total_width' not in row: formatted_rows.append([row['username']] + row['row_data']) else: # both groups with age get built the same if 'total_width' not in row: formatted_rows.append([row['username']] + [row['age_display']] + row['row_data']) else: formatted_rows.append(['Total:', ''] + row['row_data']) def _unformat_row(row): return [ col.get("sort_key", col) if isinstance(col, dict) else col for col in row ] table = headers.as_export_table rows = [_unformat_row(row) for row in formatted_rows] table.extend(rows) if self.total_row: table.append(_unformat_row(self.total_row)) if self.statistics_rows: table.extend([_unformat_row(row) for row in self.statistics_rows]) return [[self.export_sheet_name, table]] def empty_row(self): return ['--'] * len(self.report_columns) def gender_seperated_dict(self): return {'male': self.empty_row(), 'female': self.empty_row()} def age_seperated_dict(self, default): """ Build a dictionary with a copy of default for each age group """ return dict((str(i), copy(default)) for i in range(4)) def initialize_user_stuff(self): """ Return a dictionary appropriately formatted based on the set filter options Used to seperate a given users/province/cbo's data into a dictionary seperated by age group and gender as needed """ if self.show_age() and self.show_gender(): return self.age_seperated_dict(self.gender_seperated_dict()) if self.show_age() and not self.show_gender(): return self.age_seperated_dict(self.empty_row()) if not self.show_age() and self.show_gender(): return self.gender_seperated_dict() if not self.show_age() and not self.show_gender(): return self.empty_row() def add_row_to_total(self, total, row): # initialize it if it hasn't been used yet if len(total) == 0: total = [0] * len(row) return [ a if isinstance(b, str) else a + b for (a, b) in zip(total, row) ] def add_row_to_row(self, base_row, row_to_add): for i in range(len(base_row)): if isinstance(row_to_add[i], int) or isinstance( row_to_add[i], long): if isinstance(base_row[i], int): base_row[i] = base_row[i] + int(row_to_add[i]) else: base_row[i] = row_to_add[i] return base_row def get_data_grouping_id(self, row): if not self.selected_province() or not self.selected_cbo(): grouping_id = row.pop(0) else: # if it's a user we need to get the username user = CommCareUser.get_by_user_id(row.pop(0)) grouping_id = user.username return grouping_id def add_row_to_grouping_data(self, built_data, row, grouping_id, age_group, gender): """ Take whatever was left in row and add it to the appropriate spot in the data we are building for this grouping_id """ if self.show_age() and self.show_gender(): built_data[grouping_id][age_group][gender] = row elif self.show_age() and not self.show_gender(): built_data[grouping_id][age_group] = \ self.add_row_to_row(built_data[grouping_id][age_group], row) elif not self.show_age() and self.show_gender(): built_data[grouping_id][gender] = \ self.add_row_to_row(built_data[grouping_id][gender], row) elif not self.show_age() and not self.show_gender(): built_data[grouping_id] = \ self.add_row_to_row(built_data[grouping_id], row) def build_data(self, rows): """ Take all of the individual data from the rows and collect it into a dict (built_data) that is used to group the values by gender/age """ built_data = {} for row in rows: gender = age_group = None try: grouping_id = self.get_data_grouping_id(row) except AttributeError: continue if grouping_id not in built_data: # If we haven't seen this id yet we need to create # an empty row/dict (depending on selected filters) built_data[grouping_id] = self.initialize_user_stuff() if self.show_gender(): gender = row.pop(0) if gender == 'refuses_answer': continue if self.show_age(): age_group = row.pop(0) self.add_row_to_grouping_data(built_data, row, grouping_id, age_group, gender) return built_data def age_group_text(self, age_group_val): if age_group_val == '0': return '0-14 years' elif age_group_val == '1': return '15-24 years' elif age_group_val == '2': return '25+ years' else: return 'Unknown' def get_grouping_name(self, user): """ Get the name of province/cbo/user (depending on what is selected) """ if not self.selected_province(): return FixtureDataItem.get(user).fields_without_attributes['name'] elif not self.selected_cbo(): return Group.get(user).name else: return CommCareUser.get_by_username(user).name def merge_gender_data(self, data): return [ val for pair in zip(data['male'], data['female']) for val in pair ] @property def rows(self): """ Override rows method to be able to properly group data """ # use super to get the raw rows from the report stock_rows = list(super(CareReport, self).rows) # pack these rows into a dict representing the currently # configured report structure rows = self.build_data(stock_rows) # set up with for total rows if (not self.show_age() and self.show_gender()): total_width = 1 else: total_width = 2 rows_for_table = [] overall_total_row = [] age_group_totals = {'0': [], '1': [], '2': [], '3': []} # for every group of data, unpack back to individual rows # and set up the information the template needs to render this # stuff for user in rows: u = self.get_grouping_name(user) total_row = [] if self.show_age() and self.show_gender(): for age_group in sorted(rows[user]): age_display = self.age_group_text(age_group) row_data = self.merge_gender_data(rows[user][age_group]) rows_for_table.append({ 'username': u if age_group == '0' else '', 'gender': True, 'age_display': age_display, 'row_data': row_data }) age_group_totals[age_group] = self.add_row_to_total( age_group_totals[age_group], row_data) total_row = self.add_row_to_total(total_row, row_data) elif not self.show_age() and self.show_gender(): row_data = self.merge_gender_data(rows[user]) rows_for_table.append({ 'username': u, 'gender': True, 'row_data': row_data }) elif self.show_age() and not self.show_gender(): for age_group in sorted(rows[user]): row_data = rows[user][age_group] rows_for_table.append({ 'username': u if age_group == '0' else '', 'age_display': self.age_group_text(age_group), 'row_data': row_data }) age_group_totals[age_group] = self.add_row_to_total( age_group_totals[age_group], row_data) total_row = self.add_row_to_total(total_row, row_data) else: row_data = rows[user] rows_for_table.append({ 'username': u, 'gender': 'no_grouping', # magic 'row_data': row_data }) if total_row: overall_total_row = self.add_row_to_total( overall_total_row, total_row) else: # there is no total_row if we aren't grouping by age overall_total_row = self.add_row_to_total( overall_total_row, row_data) rows_for_table.append({ 'username': '******', 'total_width': total_width, 'gender': self.show_gender(), 'row_data': total_row, }) if self.show_age(): for group in ['0', '1', '2', '3']: rows_for_table.append({ 'username': '******', 'total_width': total_width, 'age_display': self.age_group_text(group), 'gender': self.show_gender(), 'row_data': age_group_totals[group] }) rows_for_table.append({ 'username': '******', 'total_width': total_width, 'gender': self.show_gender(), 'row_data': overall_total_row, }) return rows_for_table
class GSIDSQLReport(SummingSqlTabularReport, CustomProjectReport, DatespanMixin): fields = [ 'custom.apps.gsid.reports.TestField', 'corehq.apps.reports.filters.dates.DatespanFilter', 'custom.apps.gsid.reports.AsyncClinicField', 'custom.apps.gsid.reports.AggregateAtField' ] exportable = True emailable = True table_name = make_ctable_table_name("gsid_patient_summary") default_aggregation = "clinic" def __init__(self, request, base_context=None, domain=None, **kwargs): self.is_map = kwargs.pop('map', False) super(GSIDSQLReport, self).__init__(request, base_context=base_context, domain=domain, **kwargs) @property def daterange_display(self): format = "%d %b %Y" st = self.datespan.startdate.strftime(format) en = self.datespan.enddate.strftime(format) return "%s to %s" % (st, en) @property def report_subtitles(self): if self.needs_filters: return [] subtitles = ["Date range: %s" % self.daterange_display] if self.selected_fixture(): tag, id = self.selected_fixture() location = FixtureDataItem.get(id).fields_without_attributes[ '%s_name' % tag] subtitles.append('Location: %s' % location) if self.disease: location = FixtureDataItem.get( self.disease[1]).fields_without_attributes['disease_name'] subtitles.append('Disease: %s' % location) if self.test_version: test_version = FixtureDataItem.get( self.test_version[1] ).fields_without_attributes['visible_test_name'] subtitles.append('Test Version: %s' % test_version) return subtitles @property @memoized def diseases(self): disease_fixtures = FixtureDataItem.by_data_type( self.domain, FixtureDataType.by_domain_tag(self.domain, "diseases").one()) return { "ids": [ d.fields_without_attributes["disease_id"] for d in disease_fixtures ], "names": [ d.fields_without_attributes["disease_name"] for d in disease_fixtures ] } @property def test_types(self): test_fixtures = FixtureDataItem.by_data_type( self.domain, FixtureDataType.by_domain_tag(self.domain, "test").one()) return [ t.fields_without_attributes["test_name"] for t in test_fixtures ] @property def filter_values(self): ret = dict(domain=self.domain, startdate=self.datespan.startdate_param, enddate=self.datespan.enddate_param, male="male", female="female", positive="POSITIVE") DISEASES = self.diseases["ids"] TESTS = self.test_types ret.update(zip(DISEASES, DISEASES)) ret.update(zip(TESTS, TESTS)) return ret @property def filters(self): return [ EQ("domain", "domain"), BETWEEN("date", "startdate", "enddate") ] + self.disease_filters @property def disease(self): disease = self.request.GET.get('test_type_disease', '') return disease.split(':') if disease else None @property def test_version(self): test = self.request.GET.get('test_type_test', '') return test.split(':') if test else None @property def disease_filters(self): disease = self.disease test = self.test_version filters = [] if test: filters.append(EQ("test_version", test[0])) elif disease: filters.append(EQ("disease_name", disease[0])) return filters @property @memoized def gps_key(self): gps_key = "gps" agg_at = self.request.GET.get('aggregate_at', None) if agg_at and not agg_at == "clinic": gps_key = "gps_" + agg_at return gps_key @property def group_by(self): return self.place_types @property def keys(self): combos = get_unique_combinations(self.domain, place_types=self.place_types, place=self.selected_fixture()) for c in combos: yield [c[pt] for pt in self.place_types] def selected_fixture(self): fixture = self.request.GET.get('fixture_id', "") return fixture.split(':') if fixture else None @property @memoized def place_types(self): opts = ['country', 'province', 'district', 'clinic'] agg_at = self.request.GET.get('aggregate_at', None) agg_at = agg_at if agg_at and opts.index(agg_at) <= opts.index( self.default_aggregation) else self.default_aggregation place = self.selected_fixture() agg_at = place[0] if place and opts.index(agg_at) < opts.index( place[0]) else agg_at return opts[:opts.index(agg_at) + 1] @property def common_columns(self): columns = [] for place in self.place_types: columns.append( DatabaseColumn(place.capitalize(), SimpleColumn(place), format_fn=capitalize_fn)) return columns
class McSqlData(SqlData): table_name = make_ctable_table_name("mc-inscale_MalariaConsortiumFluff") def __init__(self, sections, format_class, domain, datespan, fixture_type, fixture_item): self.format_class = format_class self.domain = domain self.datespan = datespan self.fixture_type = fixture_type self.fixture_item = fixture_item self._sections = sections @property @memoized def format(self): return self.format_class([], self.get_users()) def get_headers(self): return self.format.get_headers() @memoized def get_data(self, slugs=None): # only overridden to memoize return super(McSqlData, self).get_data(slugs) @memoized def get_users(self): def _is_ape(user): return user.user_data.get('level') == 'APE' def _matches_location(user): def _tag_to_user_data(tag): return { 'hf': 'health_facility', }.get(tag) or tag if self.fixture_type and self.fixture_item: return user.user_data.get( _tag_to_user_data(self.fixture_type.tag), None) == self.fixture_item.fields_without_attributes.get( 'name') else: return True unfiltered_users = CommCareUser.by_domain(self.domain) filtered_users = filter( lambda u: _is_ape(u) and _matches_location(u), unfiltered_users, ) return sorted(filtered_users, key=lambda u: u.username) @property def group_by(self): return ['user_id'] @property def filters(self): base_filters = [ "domain = :domain", "date between :startdate and :enddate" ] if self.fixture_item is not None: base_filters.append('"user_id" in :userids') return base_filters @property @memoized def sections(self): def _section_class(section_def): return { 'form_lookup': FormPropertySection, }.get(section_def.get('type'), SqlSection) return [ _section_class(section)(self, section, self.format_class) for section in self._sections ] @memoized def all_rows(self): return [value for s in self.sections for value in s.rows] @property def filter_values(self): base_filter_values = { 'domain': self.domain, 'startdate': self.datespan.startdate_param_utc, 'enddate': self.datespan.enddate_param_utc, } if self.fixture_item is not None: user_ids = tuple(u._id for u in self.get_users()) if user_ids: base_filter_values['userids'] = user_ids else: base_filter_values['userids'] = ('__EMPTY__', ) return base_filter_values @property def user_column(self): return DatabaseColumn("User", SimpleColumn("user_id"), sortable=False) @property def columns(self): columns = [self.user_column] for section in self.sections: columns.extend(section.columns) return columns @memoized def get_user_ids(self): return [u._id for u in self.get_users()]