Example #1
0
 def get_results(self, obj):
     if self.ruleset:
         return Value.get_value_summary(ruleset=self.ruleset,
                                        segment=self.segment)
     else:
         return Value.get_value_summary(contact_field=self.contact_field,
                                        segment=self.segment)
Example #2
0
    def test_field_results(self):
        (c1, c2, c3, c4) = (self.create_contact("Contact1", '0788111111'),
                            self.create_contact("Contact2", '0788222222'),
                            self.create_contact("Contact3", '0788333333'),
                            self.create_contact("Contact4", '0788444444'))

        # create a gender field that uses strings
        gender = ContactField.get_or_create(self.org, 'gender', label="Gender", value_type=TEXT)

        c1.set_field('gender', "Male")
        c2.set_field('gender', "Female")
        c3.set_field('gender', "Female")

        result = Value.get_value_summary(contact_field=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset']) # this is two as we have the default contact created by our unit tests
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Female", 2)
        self.assertResult(result, 1, "Male", 1)

        # create an born field that uses decimals
        born = ContactField.get_or_create(self.org, 'born', label="Born", value_type=DECIMAL)
        c1.set_field('born', 1977)
        c2.set_field('born', 1990)
        c3.set_field('born', 1977)

        result = Value.get_value_summary(contact_field=born)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset'])
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "1977", 2)
        self.assertResult(result, 1, "1990", 1)

        # ok, state field!
        state = ContactField.get_or_create(self.org, 'state', label="State", value_type=STATE)
        c1.set_field('state', "Kigali City")
        c2.set_field('state', "Kigali City")

        result = Value.get_value_summary(contact_field=state)[0]
        self.assertEquals(1, len(result['categories']))
        self.assertEquals(2, result['set'])
        self.assertEquals(3, result['unset'])
        self.assertResult(result, 0, "1708283", 2)

        reg_date = ContactField.get_or_create(self.org, 'reg_date', label="Registration Date", value_type=DATETIME)
        now = timezone.now()

        c1.set_field('reg_date', now.replace(hour=9))
        c2.set_field('reg_date', now.replace(hour=4))
        c3.set_field('reg_date', now - timedelta(days=1))
        result = Value.get_value_summary(contact_field=reg_date)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertEquals(3, result['set'])
        self.assertEquals(2, result['unset'])
        self.assertResult(result, 0, (now - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0), 1)
        self.assertResult(result, 1, now.replace(hour=0, minute=0, second=0, microsecond=0), 2)
Example #3
0
    def test_open_ended_word_frequencies(self):
        flow = self.get_flow('random_word')

        def run_flow(contact, word):
            self.assertEquals("Thank you", self.send_message(flow, word, contact=contact, restart_participants=True))

        (c1, c2, c3, c4, c5, c6) = (self.create_contact("Contact1", '0788111111'),
                                    self.create_contact("Contact2", '0788222222'),
                                    self.create_contact("Contact3", '0788333333'),
                                    self.create_contact("Contact4", '0788444444'),
                                    self.create_contact("Contact5", '0788555555'),
                                    self.create_contact("Contact6", '0788666666', is_test=True))

        run_flow(c1, "1 better place")
        run_flow(c2, "the great coffee")
        run_flow(c3, "1 cup of black tea")
        run_flow(c4, "awesome than this encore")
        run_flow(c5, "from an awesome place in kigali")
        run_flow(c6, "awesome coffee")

        random = RuleSet.objects.get(flow=flow, label="Random")

        result = Value.get_value_summary(ruleset=random)[0]
        self.assertEquals(10, len(result['categories']))
        self.assertTrue(result['open_ended'])
        self.assertResult(result, 0, "awesome", 2)
        self.assertResult(result, 1, "place", 2)
        self.assertResult(result, 2, "better", 1)
        self.assertResult(result, 3, "black", 1)
        self.assertResult(result, 4, "coffee", 1)
        self.assertResult(result, 5, "cup", 1)
        self.assertResult(result, 6, "encore", 1)
        self.assertResult(result, 7, "great", 1)
        self.assertResult(result, 8, "kigali", 1)
        self.assertResult(result, 9, "tea", 1)

        # add French to org languages
        Language.create(self.org, self.admin, 'French', 'fre')

        # make sure we cleared the cache
        Value.invalidate_cache(ruleset=random)

        # encore is a french stop word and should not be included this time
        result = Value.get_value_summary(ruleset=random)[0]
        self.assertEquals(9, len(result['categories']))
        self.assertTrue(result['open_ended'])
        self.assertResult(result, 0, "awesome", 2)
        self.assertResult(result, 1, "place", 2)
        self.assertResult(result, 2, "better", 1)
        self.assertResult(result, 3, "black", 1)
        self.assertResult(result, 4, "coffee", 1)
        self.assertResult(result, 5, "cup", 1)
        self.assertResult(result, 6, "great", 1)
        self.assertResult(result, 7, "kigali", 1)
        self.assertResult(result, 8, "tea", 1)
Example #4
0
    def test_open_ended_word_frequencies(self):
        flow = self.get_flow('random_word')

        def run_flow(contact, word):
            self.assertEquals("Thank you", self.send_message(flow, word, contact=contact, restart_participants=True))

        (c1, c2, c3, c4, c5) = (self.create_contact("Contact1", '0788111111'),
                                self.create_contact("Contact2", '0788222222'),
                                self.create_contact("Contact3", '0788333333'),
                                self.create_contact("Contact4", '0788444444'),
                                self.create_contact("Contact4", '0788555555'))

        run_flow(c1, "1 better place")
        run_flow(c2, "the great coffee")
        run_flow(c3, "1 cup of black tea")
        run_flow(c4, "awesome than this")
        run_flow(c5, "from an awesome place in kigali")

        random = RuleSet.objects.get(flow=flow, label="Random")

        result = Value.get_value_summary(ruleset=random)[0]
        self.assertEquals(9, len(result['categories']))
        self.assertTrue(result['open_ended'])
        self.assertResult(result, 0, "awesome", 2)
        self.assertResult(result, 1, "place", 2)
        self.assertResult(result, 2, "better", 1)
        self.assertResult(result, 3, "black", 1)
        self.assertResult(result, 4, "coffee", 1)
        self.assertResult(result, 5, "cup", 1)
        self.assertResult(result, 6, "great", 1)
        self.assertResult(result, 7, "kigali", 1)
        self.assertResult(result, 8, "tea", 1)
Example #5
0
 def _create_values(self, contacts, field, callback):
     """
     Creates a field value for each given contact (a lot faster than calling set_field)
     """
     values = []
     for contact in contacts:
         string_value = callback(contact)
         values.append(Value(contact=contact, org=self.org, contact_field=field, string_value=string_value))
     Value.objects.bulk_create(values)
     return values
Example #6
0
    def _create_contact_batch(self, batch):
        """
        Bulk creates a batch of contacts from flat representations
        """
        for c in batch:
            c['object'] = Contact(org=c['org'], name=c['name'], language=c['language'],
                                  is_stopped=c['is_stopped'], is_blocked=c['is_blocked'],
                                  is_active=c['is_active'],
                                  created_by=c['user'], created_on=c['created_on'],
                                  modified_by=c['user'], modified_on=c['modified_on'])
        Contact.objects.bulk_create([c['object'] for c in batch])

        # now that contacts have pks, bulk create the actual URN, value and group membership objects
        batch_urns = []
        batch_values = []
        batch_memberships = []

        for c in batch:
            org = c['org']
            c['urns'] = []

            if c['tel']:
                c['urns'].append(ContactURN(org=org, contact=c['object'], priority=50, scheme=TEL_SCHEME,
                                            path=c['tel'], urn=URN.from_tel(c['tel'])))
            if c['twitter']:
                c['urns'].append(ContactURN(org=org, contact=c['object'], priority=50, scheme=TWITTER_SCHEME,
                                            path=c['twitter'], urn=URN.from_twitter(c['twitter'])))
            if c['gender']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['gender'],
                                          string_value=c['gender']))
            if c['age']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['age'],
                                          string_value=str(c['age']), decimal_value=c['age']))
            if c['joined']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['joined'],
                                          string_value=datetime_to_str(c['joined']), datetime_value=c['joined']))
            if c['ward']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['ward'],
                                          string_value=c['ward'].name, location_value=c['ward']))
            if c['district']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['district'],
                                          string_value=c['district'].name, location_value=c['district']))
            if c['state']:
                batch_values.append(Value(org=org, contact=c['object'], contact_field=org.cache['fields']['state'],
                                          string_value=c['state'].name, location_value=c['state']))
            for g in c['groups']:
                batch_memberships.append(ContactGroup.contacts.through(contact=c['object'], contactgroup=g))

            batch_urns += c['urns']

        ContactURN.objects.bulk_create(batch_urns)
        Value.objects.bulk_create(batch_values)
        ContactGroup.contacts.through.objects.bulk_create(batch_memberships)
Example #7
0
 def get_results(self, obj):
     if self.ruleset:
         return Value.get_value_summary(ruleset=self.ruleset, segment=self.segment)
     else:
         return Value.get_value_summary(contact_field=self.contact_field, segment=self.segment)
Example #8
0
    def test_category_results(self):
        self.setup_color_gender_flow()

        # create a state field:
        # assign c1 and c2 to Kigali
        state = ContactField.get_or_create(self.org, 'state', label="State", value_type=STATE)
        district = ContactField.get_or_create(self.org, 'district', label="District", value_type=DISTRICT)
        self.c1.set_field('state', "Kigali City")
        self.c1.set_field('district', "Kigali")
        self.c2.set_field('state', "Kigali City")
        self.c2.set_field('district', "Kigali")

        self.run_color_gender_flow(self.c1, "red", "male", "16")
        self.run_color_gender_flow(self.c2, "blue", "female", "19")
        self.run_color_gender_flow(self.c3, "green", "male", "75")
        self.run_color_gender_flow(self.c4, "maroon", "female", "50")

        # create a group of the women
        ladies = self.create_group("Ladies", [self.c2, self.c4])

        # get our rulesets
        color = RuleSet.objects.get(flow=self.flow, label="Color")
        gender = RuleSet.objects.get(flow=self.flow, label="Gender")
        age = RuleSet.objects.get(flow=self.flow, label="Age")

        # categories should be in the same order as our rules, should have correct counts
        result = Value.get_value_summary(ruleset=color)[0]
        self.assertEquals(3, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Red", 2)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 1)

        # check our age category as well
        result = Value.get_value_summary(ruleset=age)[0]
        self.assertEquals(3, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Child", 1)
        self.assertResult(result, 1, "Adult", 2)
        self.assertResult(result, 2, "Senior", 1)

        # and our gender categories
        result = Value.get_value_summary(ruleset=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Male", 2)
        self.assertResult(result, 1, "Female", 2)

        # now filter the results and only get responses by men
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male"])])[0]
        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 1)

        # what about men that are adults?
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male"]),
                                         dict(ruleset=age.pk, categories=["Adult"])])[0]
        self.assertResult(result, 0, "Red", 0)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 0)

        # union of all genders
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male", "Female"]),
                                         dict(ruleset=age.pk, categories=["Adult"])])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 0)

        # just women adults by group
        result = Value.get_value_summary(ruleset=color, filters=[dict(groups=[ladies.pk]), dict(ruleset=age.pk, categories="Adult")])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 0)

        # remove one of the women from the group
        ladies.update_contacts([self.c2], False)

        # get a new summary
        result = Value.get_value_summary(ruleset=color, filters=[dict(groups=[ladies.pk]), dict(ruleset=age.pk, categories="Adult")])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 0)

        # ok, back in she goes
        ladies.update_contacts([self.c2], True)

        # do another run for contact 1
        run5 = self.run_color_gender_flow(self.c1, "blue", "male", "16")

        # totals should reflect the new value, not the old
        result = Value.get_value_summary(ruleset=color)[0]
        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 2)
        self.assertResult(result, 2, "Green", 1)

        # what if we do a partial run?
        self.send_message(self.flow, "red", contact=self.c1, restart_participants=True)

        # should change our male/female breakdown since c1 now no longer has a gender
        result = Value.get_value_summary(ruleset=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertResult(result, 0, "Male", 1)
        self.assertResult(result, 1, "Female", 2)

        # back to a full flow
        run5 = self.run_color_gender_flow(self.c1, "blue", "male", "16")

        # ok, now segment by gender
        result = Value.get_value_summary(ruleset=color, filters=[], segment=dict(ruleset=gender.pk, categories=["Male", "Female"]))
        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 1)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 1)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # segment by gender again, but use the contact field to do so
        result = Value.get_value_summary(ruleset=color, filters=[], segment=dict(contact_field="Gender", values=["MALE", "Female"]))
        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 1)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 1)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # add in a filter at the same time
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=color.pk, categories=["Blue"])],
                                         segment=dict(ruleset=gender.pk, categories=["Male", "Female"]))

        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 0)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 0)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # ok, try segmenting by location instead
        result = Value.get_value_summary(ruleset=color, segment=dict(location="State"))

        eastern_result = result[0]
        self.assertEquals('171591', eastern_result['boundary'])
        self.assertEquals('Eastern Province', eastern_result['label'])
        self.assertResult(eastern_result, 0, "Red", 0)
        self.assertResult(eastern_result, 1, "Blue", 0)
        self.assertResult(eastern_result, 2, "Green", 0)

        kigali_result = result[1]
        self.assertEquals('1708283', kigali_result['boundary'])
        self.assertEquals('Kigali City', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 2)
        self.assertResult(kigali_result, 2, "Green", 0)

        # updating state location leads to updated data
        self.c2.set_field('state', "Eastern Province")
        result = Value.get_value_summary(ruleset=color, segment=dict(location="State"))

        eastern_result = result[0]
        self.assertEquals('171591', eastern_result['boundary'])
        self.assertEquals('Eastern Province', eastern_result['label'])
        self.assertResult(eastern_result, 0, "Red", 0)
        self.assertResult(eastern_result, 1, "Blue", 1)
        self.assertResult(eastern_result, 2, "Green", 0)

        kigali_result = result[1]
        self.assertEquals('1708283', kigali_result['boundary'])
        self.assertEquals('Kigali City', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 1)
        self.assertResult(kigali_result, 2, "Green", 0)

        # segment by district instead
        result = Value.get_value_summary(ruleset=color, segment=dict(parent="1708283", location="District"))

        # only on district in kigali
        self.assertEquals(1, len(result))
        kigali_result = result[0]
        self.assertEquals('60485579', kigali_result['boundary'])
        self.assertEquals('Kigali', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 2)
        self.assertResult(kigali_result, 2, "Green", 0)

        # do a sanity check on our choropleth view
        self.login(self.admin)
        response = self.client.get(reverse('flows.ruleset_choropleth', args=[color.pk]) +
                                   "?_format=json&boundary=" + self.org.country.osm_id)

        # response should be valid json
        response = json.loads(response.content)

        # should have breaks
        self.assertTrue('breaks' in response)

        # should have two categories, Blue and Others
        self.assertEquals(2, len(response['categories']))
        self.assertEquals("Blue", response['categories'][0])
        self.assertEquals("Others", response['categories'][1])

        # assert our kigali result
        kigali_result = response['scores']['1708283']
        self.assertEquals(1, kigali_result['score'])
        self.assertEquals("Kigali City", kigali_result['name'])
        self.assertEquals("Blue", kigali_result['results'][0]['label'])
        self.assertEquals("Others", kigali_result['results'][1]['label'])

        self.assertEquals(1, kigali_result['results'][0]['count'])
        self.assertEquals(0, kigali_result['results'][1]['count'])

        self.assertEquals(100, kigali_result['results'][0]['percentage'])
        self.assertEquals(0, kigali_result['results'][1]['percentage'])

        with patch('temba.values.models.Value.get_value_summary') as mock:
            mock.return_value = []

            response = self.client.get(reverse('flows.ruleset_choropleth', args=[color.pk]) +
                                   "?_format=json&boundary=" + self.org.country.osm_id)

            # response should be valid json
            response = json.loads(response.content)

            # should have two categories, Blue and Others
            self.assertEquals(2, len(response['categories']))
            self.assertEquals("", response['categories'][0])
            self.assertEquals("", response['categories'][1])

            # all counts and percentage are 0
            self.assertEquals(0, response['totals']['count'])
            self.assertEquals(0, response['totals']['results'][0]['count'])
            self.assertEquals(0, response['totals']['results'][0]['percentage'])
            self.assertEquals(0, response['totals']['results'][1]['count'])
            self.assertEquals(0, response['totals']['results'][1]['percentage'])

            # and empty string labels
            self.assertEquals("", response['totals']['results'][0]['label'])
            self.assertEquals("", response['totals']['results'][1]['label'])

        # also check our analytics view
        response = self.client.get(reverse('flows.ruleset_analytics'))

        # make sure we have only one flow in it
        flows = json.loads(response.context['flows'])
        self.assertEquals(1, len(flows))
        self.assertEquals(3, len(flows[0]['rules']))
Example #9
0
    def test_category_results(self):
        self.setup_color_gender_flow()

        # create a state field:
        # assign c1 and c2 to Kigali
        state = ContactField.get_or_create(self.org, 'state', label="State", value_type=STATE)
        district = ContactField.get_or_create(self.org, 'district', label="District", value_type=DISTRICT)
        self.c1.set_field('state', "Kigali City")
        self.c1.set_field('district', "Kigali")
        self.c2.set_field('state', "Kigali City")
        self.c2.set_field('district', "Kigali")

        self.run_color_gender_flow(self.c1, "red", "male", "16")
        self.run_color_gender_flow(self.c2, "blue", "female", "19")
        self.run_color_gender_flow(self.c3, "green", "male", "75")
        self.run_color_gender_flow(self.c4, "maroon", "female", "50")

        # create a group of the women
        ladies = self.create_group("Ladies", [self.c2, self.c4])

        # get our rulesets
        color = RuleSet.objects.get(flow=self.flow, label="Color")
        gender = RuleSet.objects.get(flow=self.flow, label="Gender")
        age = RuleSet.objects.get(flow=self.flow, label="Age")

        # categories should be in the same order as our rules, should have correct counts
        result = Value.get_value_summary(ruleset=color)[0]
        self.assertEquals(3, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Red", 2)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 1)

        # check our age category as well
        result = Value.get_value_summary(ruleset=age)[0]
        self.assertEquals(3, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Child", 1)
        self.assertResult(result, 1, "Adult", 2)
        self.assertResult(result, 2, "Senior", 1)

        # and our gender categories
        result = Value.get_value_summary(ruleset=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertFalse(result['open_ended'])
        self.assertResult(result, 0, "Male", 2)
        self.assertResult(result, 1, "Female", 2)

        # now filter the results and only get responses by men
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male"])])[0]
        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 1)

        # what about men that are adults?
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male"]),
                                         dict(ruleset=age.pk, categories=["Adult"])])[0]
        self.assertResult(result, 0, "Red", 0)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 0)

        # union of all genders
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=gender.pk, categories=["Male", "Female"]),
                                         dict(ruleset=age.pk, categories=["Adult"])])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 0)

        # just women adults by group
        result = Value.get_value_summary(ruleset=color, filters=[dict(groups=[ladies.pk]), dict(ruleset=age.pk, categories="Adult")])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 1)
        self.assertResult(result, 2, "Green", 0)

        # remove one of the women from the group
        ladies.update_contacts([self.c2], False)

        # get a new summary
        result = Value.get_value_summary(ruleset=color, filters=[dict(groups=[ladies.pk]), dict(ruleset=age.pk, categories="Adult")])[0]

        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 0)
        self.assertResult(result, 2, "Green", 0)

        # ok, back in she goes
        ladies.update_contacts([self.c2], True)

        # do another run for contact 1
        run5 = self.run_color_gender_flow(self.c1, "blue", "male", "16")

        # totals should reflect the new value, not the old
        result = Value.get_value_summary(ruleset=color)[0]
        self.assertResult(result, 0, "Red", 1)
        self.assertResult(result, 1, "Blue", 2)
        self.assertResult(result, 2, "Green", 1)

        # what if we do a partial run?
        self.send_message(self.flow, "red", contact=self.c1, restart_participants=True)

        # should change our male/female breakdown since c1 now no longer has a gender
        result = Value.get_value_summary(ruleset=gender)[0]
        self.assertEquals(2, len(result['categories']))
        self.assertResult(result, 0, "Male", 1)
        self.assertResult(result, 1, "Female", 2)

        # back to a full flow
        run5 = self.run_color_gender_flow(self.c1, "blue", "male", "16")

        # ok, now segment by gender
        result = Value.get_value_summary(ruleset=color, filters=[], segment=dict(ruleset=gender.pk, categories=["Male", "Female"]))
        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 1)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 1)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # add in a filter at the same time
        result = Value.get_value_summary(ruleset=color, filters=[dict(ruleset=color.pk, categories=["Blue"])],
                                         segment=dict(ruleset=gender.pk, categories=["Male", "Female"]))

        male_result = result[0]
        self.assertResult(male_result, 0, "Red", 0)
        self.assertResult(male_result, 1, "Blue", 1)
        self.assertResult(male_result, 2, "Green", 0)

        female_result = result[1]
        self.assertResult(female_result, 0, "Red", 0)
        self.assertResult(female_result, 1, "Blue", 1)
        self.assertResult(female_result, 2, "Green", 0)

        # ok, try segmenting by location instead
        result = Value.get_value_summary(ruleset=color, segment=dict(location="State"))

        eastern_result = result[0]
        self.assertEquals('171591', eastern_result['boundary'])
        self.assertEquals('Eastern Province', eastern_result['label'])
        self.assertResult(eastern_result, 0, "Red", 0)
        self.assertResult(eastern_result, 1, "Blue", 0)
        self.assertResult(eastern_result, 2, "Green", 0)

        kigali_result = result[1]
        self.assertEquals('1708283', kigali_result['boundary'])
        self.assertEquals('Kigali City', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 2)
        self.assertResult(kigali_result, 2, "Green", 0)

        # updating state location leads to updated data
        self.c2.set_field('state', "Eastern Province")
        result = Value.get_value_summary(ruleset=color, segment=dict(location="State"))

        eastern_result = result[0]
        self.assertEquals('171591', eastern_result['boundary'])
        self.assertEquals('Eastern Province', eastern_result['label'])
        self.assertResult(eastern_result, 0, "Red", 0)
        self.assertResult(eastern_result, 1, "Blue", 1)
        self.assertResult(eastern_result, 2, "Green", 0)

        kigali_result = result[1]
        self.assertEquals('1708283', kigali_result['boundary'])
        self.assertEquals('Kigali City', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 1)
        self.assertResult(kigali_result, 2, "Green", 0)

        # segment by district instead
        result = Value.get_value_summary(ruleset=color, segment=dict(parent="1708283", location="District"))

        # only on district in kigali
        self.assertEquals(1, len(result))
        kigali_result = result[0]
        self.assertEquals('60485579', kigali_result['boundary'])
        self.assertEquals('Kigali', kigali_result['label'])
        self.assertResult(kigali_result, 0, "Red", 0)
        self.assertResult(kigali_result, 1, "Blue", 2)
        self.assertResult(kigali_result, 2, "Green", 0)
Example #10
0
    def create_contacts(self, orgs, locations, num_total):
        batch_size = 5000
        num_test_contacts = len(orgs) * len(USERS)
        group_membership_model = ContactGroup.contacts.through
        group_counts = defaultdict(int)

        self._log("Creating %d test contacts...\n" % num_test_contacts)

        for org in orgs:
            for user in org.cache['users']:
                Contact.get_test_contact(user)

        self._log("Creating %d regular contacts...\n" % (num_total - num_test_contacts))

        base_contact_id = self.get_current_id(Contact) + 1

        # Disable table triggers to speed up insertion and in the case of contact group m2m, avoid having an unsquashed
        # count row for every contact
        with DisableTriggersOn(Contact, ContactURN, Value, group_membership_model):
            names = [('%s %s' % (c1, c2)).strip() for c2 in CONTACT_NAMES[1] for c1 in CONTACT_NAMES[0]]
            names = [n if n else None for n in names]

            batch = 1
            for index_batch in chunk_list(range(num_total - num_test_contacts), batch_size):
                contacts = []
                urns = []
                values = []
                memberships = []

                def add_to_group(g):
                    group_counts[g] += 1
                    memberships.append(group_membership_model(contact_id=c['id'], contactgroup=g))

                for c_index in index_batch:  # pragma: no cover

                    org = orgs[c_index] if c_index < len(orgs) else self.random_org(orgs)  # at least 1 contact per org
                    name = self.random_choice(names)
                    location = self.random_choice(locations) if self.probability(CONTACT_HAS_FIELD_PROB) else None
                    created_on = self.timeline_date(float(num_test_contacts + c_index) / num_total)

                    c = {
                        'id': base_contact_id + c_index,  # database id this contact will have when created
                        'org': org,
                        'user': org.cache['users'][0],
                        'name': name,
                        'tel': '+2507%08d' % c_index if self.probability(CONTACT_HAS_TEL_PROB) else None,
                        'twitter': '%s%d' % (name.replace(' ', '_').lower() if name else 'tweep', c_index) if self.probability(CONTACT_HAS_TWITTER_PROB) else None,
                        'gender': self.random_choice(('M', 'F')) if self.probability(CONTACT_HAS_FIELD_PROB) else None,
                        'age': self.random.randint(16, 80) if self.probability(CONTACT_HAS_FIELD_PROB) else None,
                        'joined': self.random_date() if self.probability(CONTACT_HAS_FIELD_PROB) else None,
                        'ward': location[0] if location else None,
                        'district': location[1] if location else None,
                        'state': location[2] if location else None,
                        'language': self.random_choice(CONTACT_LANGS),
                        'is_stopped': self.probability(CONTACT_IS_STOPPED_PROB),
                        'is_blocked': self.probability(CONTACT_IS_BLOCKED_PROB),
                        'is_active': self.probability(1 - CONTACT_IS_DELETED_PROB),
                        'created_on': created_on,
                        'modified_on': self.random_date(created_on, self.db_ends_on),
                    }

                    if c['is_active']:
                        if not c['is_blocked'] and not c['is_stopped']:
                            add_to_group(org.cache['system_groups'][ContactGroup.TYPE_ALL])
                        if c['is_blocked']:
                            add_to_group(org.cache['system_groups'][ContactGroup.TYPE_BLOCKED])
                        if c['is_stopped']:
                            add_to_group(org.cache['system_groups'][ContactGroup.TYPE_STOPPED])

                    contacts.append(Contact(org=org, name=c['name'], language=c['language'],
                                            is_stopped=c['is_stopped'], is_blocked=c['is_blocked'],
                                            is_active=c['is_active'],
                                            created_by=user, created_on=c['created_on'],
                                            modified_by=user, modified_on=c['modified_on']))

                    if c['tel']:
                        urns.append(ContactURN(org=org, contact_id=c['id'], priority=50, scheme=TEL_SCHEME,
                                               path=c['tel'], urn=URN.from_tel(c['tel'])))
                    if c['twitter']:
                        urns.append(ContactURN(org=org, contact_id=c['id'], priority=50, scheme=TWITTER_SCHEME,
                                               path=c['twitter'], urn=URN.from_twitter(c['twitter'])))
                    if c['gender']:
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['gender'],
                                            string_value=c['gender']))
                    if c['age']:
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['age'],
                                            string_value=str(c['age']), decimal_value=c['age']))
                    if c['joined']:
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['joined'],
                                            string_value=datetime_to_str(c['joined']), datetime_value=c['joined']))
                    if location:
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['ward'],
                                            string_value=c['ward'].name, location_value=c['ward']))
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['district'],
                                            string_value=c['district'].name, location_value=c['district']))
                        values.append(Value(org=org, contact_id=c['id'], contact_field=org.cache['fields']['state'],
                                            string_value=c['state'].name, location_value=c['state']))

                    # let each group decide if it is taking this contact
                    for g in org.cache['groups']:
                        if g.member(c) if callable(g.member) else self.probability(g.member):
                            add_to_group(g)

                Contact.objects.bulk_create(contacts)
                ContactURN.objects.bulk_create(urns)
                Value.objects.bulk_create(values)
                group_membership_model.objects.bulk_create(memberships)

                self._log(" > Created batch %d of %d\n" % (batch, max(num_total // batch_size, 1)))
                batch += 1

        # create group count records manually
        counts = []
        for group, count in group_counts.items():
            counts.append(ContactGroupCount(group=group, count=count, is_squashed=True))
        ContactGroupCount.objects.bulk_create(counts)

        # for sanity check that our presumed last contact id matches the last actual contact id
        assert c['id'] == Contact.objects.order_by('-id').first().id