Beispiel #1
0
 def _create_registrations(self, expected_stats):
     """ Create different numbers of registrations on each of the chosen registration dates
     so we can be sure that a count was assigned to the correct date.
     """
     msg_type_str = self._msg_type_to_str(SMS.REGISTRATION)
     expected_stats['message_stats'][msg_type_str] = dict()
     # Accumulators for by-center and total number of registrations
     expected_stats['by_center'][self.rc_1.center_id]['registrations'] = 0
     expected_stats['by_center'][self.rc_2.center_id]['registrations'] = 0
     expected_stats['by_center'][self.rc_3.center_id]['registrations'] = 0
     expected_stats['by_center'][self.rc_4.center_id]['registrations'] = 0
     expected_stats['by_center'][self.copy_of_rc_1.center_id]['registrations'] = ''
     expected_stats['by_center'][self.rc_5.center_id]['registrations'] = 0
     expected_stats['message_stats'][msg_type_str]['total'] = 0
     for i, reg_date in enumerate(self.registration_dates):
         regs_on_date = i + 1
         for j in range(regs_on_date):
             citizen = CitizenFactory()
             s = SMS(from_number='12345', to_number='12345', citizen=citizen,
                     direction=INCOMING, message='my reg message',
                     msg_type=SMS.REGISTRATION, message_code=MESSAGE_1,
                     carrier=self.carrier_1, creation_date=reg_date)
             s.full_clean()
             s.save()
             r = Registration(citizen=citizen, registration_center=self.rc_1,
                              archive_time=None,
                              sms=s, creation_date=reg_date, modification_date=reg_date)
             r.full_clean()
             r.save()
             expected_stats['by_center'][self.rc_1.center_id]['registrations'] += 1
         expected_stats['message_stats'][msg_type_str]['total'] += regs_on_date
         # Capture the count on "yesterday" (reported on SMS page)
         if self.yesterday_date == reg_date.date():
             expected_stats['message_stats'][msg_type_str][self.yesterday_date_dm] = \
                 regs_on_date
 def _create_sms_messages(self, expected_stats):
     """ Create SMS messages of a certain type at different times "yesterday".
     The times should have the same date in local TZ but different dates when
     the TZ is bungled somewhere.  By making them "yesterday", the counts will show
     up in the SMS page in the yesterday column.
     """
     msg_type = SMS.INVALID_CENTRE_CODE_LENGTH
     msg_type_str = self._msg_type_to_str(msg_type)
     expected_stats['message_stats'][msg_type_str] = dict()
     num_staff_messages = 8
     for msg_hour in range(num_staff_messages):
         msg_time = self.yesterday_date_dt.replace(hour=msg_hour, minute=23)
         s = SMS(from_number=self.staff_phone_number,
                 to_number='12345',
                 citizen=self.citizen_1,
                 direction=INCOMING,
                 message='my message',
                 msg_type=msg_type,
                 message_code=MESSAGE_1,
                 carrier=self.carrier_1,
                 creation_date=msg_time)
         s.full_clean()
         s.save()
     expected_stats['message_stats'][msg_type_str][self.yesterday_date_dt.strftime('%d/%m')] = \
         num_staff_messages
     expected_stats['message_stats'][msg_type_str][
         'total'] = num_staff_messages
     expected_stats['phone_history'][self.staff_phone_number] = {
         'message_count': num_staff_messages,
     }
Beispiel #3
0
 def _create_sms_messages(self, expected_stats):
     """ Create SMS messages of a certain type at different times "yesterday".
     The times should have the same date in local TZ but different dates when
     the TZ is bungled somewhere.  By making them "yesterday", the counts will show
     up in the SMS page in the yesterday column.
     """
     msg_type = SMS.INVALID_CENTRE_CODE_LENGTH
     msg_type_str = self._msg_type_to_str(msg_type)
     expected_stats['message_stats'][msg_type_str] = dict()
     num_staff_messages = 8
     for msg_hour in range(num_staff_messages):
         msg_time = self.yesterday_date_dt.replace(hour=msg_hour, minute=23)
         s = SMS(from_number=self.staff_phone_number, to_number='12345', citizen=self.citizen_1,
                 direction=INCOMING, message='my message',
                 msg_type=msg_type, message_code=MESSAGE_1,
                 carrier=self.carrier_1, creation_date=msg_time)
         s.full_clean()
         s.save()
     expected_stats['message_stats'][msg_type_str][self.yesterday_date_dt.strftime('%d/%m')] = \
         num_staff_messages
     expected_stats['message_stats'][msg_type_str]['total'] = num_staff_messages
     expected_stats['phone_history'][self.staff_phone_number] = {
         'message_count': num_staff_messages,
     }
 def _create_registrations(self, expected_stats):
     """ Create different numbers of registrations on each of the chosen registration dates
     so we can be sure that a count was assigned to the correct date.
     """
     msg_type_str = self._msg_type_to_str(SMS.REGISTRATION)
     expected_stats['message_stats'][msg_type_str] = dict()
     # Accumulators for by-center and total number of registrations
     expected_stats['by_center'][self.rc_1.center_id]['registrations'] = 0
     expected_stats['by_center'][self.rc_2.center_id]['registrations'] = 0
     expected_stats['by_center'][self.rc_3.center_id]['registrations'] = 0
     expected_stats['by_center'][self.rc_4.center_id]['registrations'] = 0
     expected_stats['by_center'][
         self.copy_of_rc_1.center_id]['registrations'] = ''
     expected_stats['by_center'][self.rc_5.center_id]['registrations'] = 0
     expected_stats['message_stats'][msg_type_str]['total'] = 0
     for i, reg_date in enumerate(self.registration_dates):
         regs_on_date = i + 1
         for j in range(regs_on_date):
             citizen = CitizenFactory()
             s = SMS(from_number='12345',
                     to_number='12345',
                     citizen=citizen,
                     direction=INCOMING,
                     message='my reg message',
                     msg_type=SMS.REGISTRATION,
                     message_code=MESSAGE_1,
                     carrier=self.carrier_1,
                     creation_date=reg_date)
             s.full_clean()
             s.save()
             r = Registration(citizen=citizen,
                              registration_center=self.rc_1,
                              archive_time=None,
                              sms=s,
                              creation_date=reg_date,
                              modification_date=reg_date)
             r.full_clean()
             r.save()
             expected_stats['by_center'][
                 self.rc_1.center_id]['registrations'] += 1
         expected_stats['message_stats'][msg_type_str][
             'total'] += regs_on_date
         # Capture the count on "yesterday" (reported on SMS page)
         if self.yesterday_date == reg_date.date():
             expected_stats['message_stats'][msg_type_str][self.yesterday_date_dm] = \
                 regs_on_date
def create(center_without_office=False,
           num_copy_centers=DEFAULT_NUM_COPY_CENTERS,
           num_registrations=DEFAULT_NUM_REGISTRATIONS,
           num_registration_dates=DEFAULT_NUM_REGISTRATION_DATES,
           num_daily_reports=DEFAULT_NUM_DAILY_REPORTS,
           num_registration_centers=DEFAULT_NUM_REGISTRATION_CENTERS,
           num_subconstituencies=DEFAULT_NUM_SUBCONSTITUENCIES,
           use_existing_infra=False,
           num_inactive_centers_per_election=DEFAULT_NUM_INACTIVE_PER_ELECTION,
           num_no_reg_centers=DEFAULT_NUM_NO_REG_CENTERS,
           election_dates=()):
    assert settings.ENVIRONMENT not in ('production', 'testing')
    delete(delete_infra=not use_existing_infra)
    empty_report_store()  # Remove any old data from Redis

    # Figure out ~10% of "normal" centers...
    fraction_of_normal_centers = \
        max(1, int(0.1 * num_registration_centers)) if num_registration_centers else 0

    # If numbers of some weird center types weren't specified, use a small
    # fraction of normal centers.
    if num_copy_centers == DEFAULT_NUM_COPY_CENTERS:
        num_copy_centers = fraction_of_normal_centers
    if num_no_reg_centers == DEFAULT_NUM_NO_REG_CENTERS:
        num_no_reg_centers = fraction_of_normal_centers

    carrier = BackendFactory()

    if election_dates:
        elections = [
            ElectionFactory(polling_start_time=election_date.replace(hour=8),
                            polling_end_time=election_date.replace(hour=20))
            for election_date in election_dates
        ]
    else:
        election_date = PAST_DAY.replace(hour=8, microsecond=123456)
        election = ElectionFactory(
            polling_start_time=election_date,
            polling_end_time=election_date.replace(hour=20))
        elections = (election, )

    if not use_existing_infra:
        OfficeFactory()
        ConstituencyFactory(name_english='first')
        SubConstituencyFactory(name_english='Benghazi')

    offices = Office.objects.all()
    copy_centers = []
    no_reg_centers = []
    staff_phones = []

    if use_existing_infra:
        # Pick centers that support registrations at random.
        centers = RegistrationCenter.objects.filter(reg_open=True)\
            .exclude(center_type=RegistrationCenter.Types.COPY)\
            .order_by('?')[:num_registration_centers]
        if num_copy_centers:  # user wants some, but there might not be any
            copy_centers = RegistrationCenter.objects.\
                filter(reg_open=True, center_type=RegistrationCenter.Types.COPY)\
                .order_by('?')[:num_copy_centers]
        if num_no_reg_centers:  # user wants some, but there might not be any
            no_reg_centers = RegistrationCenter.objects.\
                filter(reg_open=False).order_by('?')[:num_no_reg_centers]
        # why like this? sliced queries and/or list
        all_kinds_of_centers = \
            list(centers) + list(copy_centers) + list(no_reg_centers)
    else:
        subconstituencies = SubConstituency.objects.exclude(
            pk=SPLIT_CENTER_SUBCONSTITUENCY_ID)
        subconstituencies = subconstituencies[:num_subconstituencies]

        centers = []
        for i in range(num_registration_centers):
            constituency = Constituency.objects.filter(name_english='first')[0]
            subconstituency = random.choice(subconstituencies)

            rc = RegistrationCenter(name='polling-center-%d' % i,
                                    center_id=CENTER_ID_MIN_INT_VALUE + i,
                                    constituency=constituency,
                                    subconstituency=subconstituency,
                                    office=random.choice(offices))
            rc.full_clean()
            rc.save()
            centers.append(rc)

        for i in range(num_copy_centers):
            original = random.choice(centers)
            # XXX This doesn't handle accidentally making too many copies of the same
            #     center, so make sure --num-centers is "big enough" w.r.t. --num-copy-centers.
            new_center_id = CENTER_ID_MIN_INT_VALUE + num_registration_centers + i
            copy = RegistrationCenter(
                name='Copy of %s' % original.name,
                center_id=new_center_id,
                constituency=original.constituency,
                subconstituency=original.subconstituency,
                office=original.office,
                center_type=RegistrationCenter.Types.COPY,
                copy_of=original)
            copy.full_clean()
            copy.save()
            copy_centers.append(copy)

        for i in range(num_no_reg_centers):
            constituency = Constituency.objects.filter(name_english='first')[0]
            subconstituency = random.choice(subconstituencies)
            center_id = CENTER_ID_MIN_INT_VALUE + num_registration_centers + num_copy_centers + i
            rc = RegistrationCenter(name='no-reg-polling-center-%d' % i,
                                    center_id=center_id,
                                    constituency=constituency,
                                    subconstituency=subconstituency,
                                    office=random.choice(offices),
                                    reg_open=False)
            rc.full_clean()
            rc.save()

        all_kinds_of_centers = centers + copy_centers + no_reg_centers

    if center_without_office:
        try:
            # by not specifying office and other infra, it will be "standalone"
            rc = RegistrationCenter(name='dummy-registration-center',
                                    center_id=UNUSED_CENTER_ID)
            rc.full_clean()
            rc.save()
        except ValidationError:
            pass  # assume that it already exists

    for election in elections:
        num_daily_reports_on_election_day = int(round(0.9 * num_daily_reports))
        centers_reported = set()
        for i in range(num_daily_reports_on_election_day):
            staff_phone_number = STAFF_PHONE_NUMBER_PATTERN % i
            from_center = random.choice(all_kinds_of_centers)
            ensure_staff_phone_exists(
                staff_phone_number, from_center, staff_phones,
                election.work_start_time + datetime.timedelta(minutes=5))

            # split votes between two options
            number_of_votes = (random.randint(1, 100), random.randint(1, 100))
            random_period_number = random.randint(FIRST_PERIOD_NUMBER,
                                                  LAST_PERIOD_NUMBER)
            pr = PollingReport(election=election,
                               phone_number=staff_phone_number,
                               registration_center=from_center,
                               period_number=random_period_number,
                               num_voters=sum(number_of_votes),
                               creation_date=election.polling_start_time)
            pr.full_clean()
            pr.save()
            s = SMS(from_number=staff_phone_number,
                    to_number=POLLING_REPORT_PHONE_NUMBER,
                    direction=INCOMING,
                    message='my message',
                    msg_type=SMS.POLLING_REPORT,
                    message_code=MESSAGE_1,
                    carrier=carrier,
                    creation_date=election.polling_start_time)
            s.full_clean()
            s.save()

            if from_center in centers_reported:
                continue  # can't send but one PreliminaryVoteCount from a center

            # send a corresponding vote count
            for option, votes_for_option in enumerate(number_of_votes,
                                                      start=1):
                pvc = PreliminaryVoteCount(
                    election=election,
                    phone_number=staff_phone_number,
                    registration_center=from_center,
                    option=option,
                    num_votes=votes_for_option,
                    creation_date=election.polling_start_time)
                pvc.full_clean()
                pvc.save()
                s = SMS(
                    from_number=staff_phone_number,
                    to_number=PRELIMINARY_VOTE_COUNT_PHONE_NUMBER,
                    # XXX no specific message type for PreliminaryVoteCount
                    direction=INCOMING,
                    message='my message',
                    msg_type=SMS.POLLING_REPORT,
                    message_code=MESSAGE_1,
                    carrier=carrier,
                    creation_date=election.polling_start_time)
                s.full_clean()
                s.save()

            centers_reported.add(from_center)

        # some daily reports on the day after
        for i in range(num_daily_reports - num_daily_reports_on_election_day):
            staff_phone_number = STAFF_PHONE_NUMBER_PATTERN % i
            rc = random.choice(all_kinds_of_centers)
            ensure_staff_phone_exists(
                staff_phone_number, rc, staff_phones,
                election.work_start_time + datetime.timedelta(minutes=5))
            report_creation_date = election.polling_start_time + datetime.timedelta(
                days=1)
            pr = PollingReport(
                election=election,
                phone_number=staff_phone_number,
                registration_center=rc,
                period_number=
                LAST_PERIOD_NUMBER,  # day after counts as last period
                num_voters=random.randint(1, 50),
                creation_date=report_creation_date)
            pr.full_clean()
            pr.save()
            s = SMS(from_number=staff_phone_number,
                    to_number=POLLING_REPORT_PHONE_NUMBER,
                    direction=INCOMING,
                    message='my message',
                    msg_type=SMS.POLLING_REPORT,
                    message_code=MESSAGE_1,
                    carrier=carrier,
                    creation_date=election.polling_start_time)
            s.full_clean()
            s.save()

        # Tag some centers as inactive for the election.  We may or may not pick some that
        # sent messages as being inactive.
        num_inactive_centers_per_election = \
            min(num_inactive_centers_per_election, len(all_kinds_of_centers))
        if num_inactive_centers_per_election:
            reordered = all_kinds_of_centers
            random.shuffle(reordered)
            for i in range(num_inactive_centers_per_election):
                inactive_on_election = CenterClosedForElection(
                    registration_center=reordered[i], election=election)
                inactive_on_election.full_clean()
                inactive_on_election.save()

    tz = timezone(settings.TIME_ZONE)
    # construct a datetime that will change based on timezone discrepancies
    # 0-2am in Libya has a different date than the same time in UDT or EDT
    today_fragile = now().astimezone(tz).replace(hour=0, minute=59)

    # tz.normalize fixes up the date arithmetic when crossing DST boundaries
    creation_dates = \
        [tz.normalize((today_fragile -
                       datetime.timedelta(days=DAYS_BETWEEN_REGISTRATIONS * i)).astimezone(tz))
         for i in range(num_registration_dates)]

    citizens = []
    for i in range(num_registrations):
        # about 60% of registrations are for males, just as with actual data
        gender = MALE if random.randint(1, 100) <= 60 else FEMALE
        nat_id = '%d%011d' % (gender, i)

        creation_date = random.choice(creation_dates)
        modification_date = creation_date

        # Select voter ages from 18 years on up.
        voter_age = random.randint(18, 99)
        # If they were a certain age at any time yesterday, they are certainly that age at any time
        # today.
        yesterday = datetime.datetime.now().replace(
            tzinfo=tz) - datetime.timedelta(days=1)
        birth_date = datetime.date(yesterday.year - voter_age, yesterday.month,
                                   yesterday.day)
        civil_registry_id = random.randint(1, 99999999)
        citizen = CitizenFactory(civil_registry_id=civil_registry_id,
                                 national_id=nat_id,
                                 gender=gender,
                                 birth_date=birth_date)
        citizens.append(citizen)
        s = SMS(from_number=VOTER_PHONE_NUMBER_PATTERN % i,
                to_number=REGISTRATION_PHONE_NUMBER,
                citizen=citizen,
                direction=INCOMING,
                message='my reg message',
                msg_type=SMS.REGISTRATION,
                message_code=MESSAGE_1,
                carrier=carrier,
                creation_date=creation_date)
        s.full_clean()
        s.save()

        rc = random.choice(centers)

        confirmed = random.randint(1, 100) <= 80  # most are confirmed
        if confirmed:
            archive_time = None
        else:
            archive_time = random.choice(creation_dates)
        r = Registration(citizen=citizen,
                         registration_center=rc,
                         sms=s,
                         archive_time=archive_time,
                         creation_date=creation_date,
                         modification_date=modification_date)
        r.full_clean()
        r.save()

    if num_registrations:  # if any data being generated
        # generate a variety of sms messages
        for i in range(NUM_RANDOM_SMS_MESSAGES):
            sms_type = random.choice(SMS.MESSAGE_TYPES)[0]
            staff_phone = random.choice(staff_phones)
            s = SMS(from_number=staff_phone.phone_number,
                    to_number=RANDOM_MESSAGE_PHONE_NUMBER,
                    citizen=random.choice(citizens),
                    direction=INCOMING,
                    message='my long random message',
                    msg_type=sms_type,
                    message_code=MESSAGE_1,
                    carrier=carrier,
                    creation_date=random.choice(creation_dates))
            s.full_clean()
            s.save()

        for election in elections:
            for rc in centers:
                i = random.randint(8888, 9999)
                staff_phone_number = STAFF_PHONE_NUMBER_PATTERN % i
                ensure_staff_phone_exists(
                    staff_phone_number, rc, staff_phones,
                    election.work_start_time + datetime.timedelta(minutes=5))
                center_open = CenterOpen(
                    election=election,
                    phone_number=staff_phone_number,
                    registration_center=rc,
                    creation_date=election.polling_start_time.replace(
                        hour=random.randint(0, 10), minute=23))
                center_open.full_clean()
                center_open.save()
                s = SMS(from_number=staff_phone_number,
                        to_number=ACTIVATE_PHONE_NUMBER,
                        direction=INCOMING,
                        message='my message',
                        msg_type=SMS.ACTIVATE,
                        message_code=MESSAGE_1,
                        carrier=carrier,
                        creation_date=election.polling_start_time)
                s.full_clean()
                s.save()
Beispiel #6
0
def create(center_without_office=False,
           num_copy_centers=DEFAULT_NUM_COPY_CENTERS,
           num_registrations=DEFAULT_NUM_REGISTRATIONS,
           num_registration_dates=DEFAULT_NUM_REGISTRATION_DATES,
           num_daily_reports=DEFAULT_NUM_DAILY_REPORTS,
           num_registration_centers=DEFAULT_NUM_REGISTRATION_CENTERS,
           num_subconstituencies=DEFAULT_NUM_SUBCONSTITUENCIES,
           use_existing_infra=False,
           num_inactive_centers_per_election=DEFAULT_NUM_INACTIVE_PER_ELECTION,
           num_no_reg_centers=DEFAULT_NUM_NO_REG_CENTERS,
           election_dates=()):
    assert settings.ENVIRONMENT not in ('production', 'testing')
    delete(delete_infra=not use_existing_infra)
    empty_report_store()  # Remove any old data from Redis

    # Figure out ~10% of "normal" centers...
    fraction_of_normal_centers = \
        max(1, int(0.1 * num_registration_centers)) if num_registration_centers else 0

    # If numbers of some weird center types weren't specified, use a small
    # fraction of normal centers.
    if num_copy_centers == DEFAULT_NUM_COPY_CENTERS:
        num_copy_centers = fraction_of_normal_centers
    if num_no_reg_centers == DEFAULT_NUM_NO_REG_CENTERS:
        num_no_reg_centers = fraction_of_normal_centers

    carrier = BackendFactory()

    if election_dates:
        elections = [
            ElectionFactory(
                polling_start_time=election_date.replace(hour=8),
                polling_end_time=election_date.replace(hour=20)
            )
            for election_date in election_dates
        ]
    else:
        election_date = PAST_DAY.replace(hour=8, microsecond=123456)
        election = ElectionFactory(
            polling_start_time=election_date,
            polling_end_time=election_date.replace(hour=20)
        )
        elections = (election,)

    if not use_existing_infra:
        OfficeFactory()
        ConstituencyFactory(name_english='first')
        SubConstituencyFactory(name_english='Benghazi')

    offices = Office.objects.all()
    copy_centers = []
    no_reg_centers = []
    staff_phones = []

    if use_existing_infra:
        # Pick centers that support registrations at random.
        centers = RegistrationCenter.objects.filter(reg_open=True)\
            .exclude(center_type=RegistrationCenter.Types.COPY)\
            .order_by('?')[:num_registration_centers]
        if num_copy_centers:  # user wants some, but there might not be any
            copy_centers = RegistrationCenter.objects.\
                filter(reg_open=True, center_type=RegistrationCenter.Types.COPY)\
                .order_by('?')[:num_copy_centers]
        if num_no_reg_centers:  # user wants some, but there might not be any
            no_reg_centers = RegistrationCenter.objects.\
                filter(reg_open=False).order_by('?')[:num_no_reg_centers]
        # why like this? sliced queries and/or list
        all_kinds_of_centers = \
            list(centers) + list(copy_centers) + list(no_reg_centers)
    else:
        subconstituencies = SubConstituency.objects.exclude(pk=SPLIT_CENTER_SUBCONSTITUENCY_ID)
        subconstituencies = subconstituencies[:num_subconstituencies]

        centers = []
        for i in range(num_registration_centers):
            constituency = Constituency.objects.filter(name_english='first')[0]
            subconstituency = random.choice(subconstituencies)

            rc = RegistrationCenter(name='polling-center-%d' % i,
                                    center_id=CENTER_ID_MIN_INT_VALUE+i, constituency=constituency,
                                    subconstituency=subconstituency, office=random.choice(offices))
            rc.full_clean()
            rc.save()
            centers.append(rc)

        for i in range(num_copy_centers):
            original = random.choice(centers)
            # XXX This doesn't handle accidentally making too many copies of the same
            #     center, so make sure --num-centers is "big enough" w.r.t. --num-copy-centers.
            new_center_id = CENTER_ID_MIN_INT_VALUE + num_registration_centers + i
            copy = RegistrationCenter(name='Copy of %s' % original.name,
                                      center_id=new_center_id,
                                      constituency=original.constituency,
                                      subconstituency=original.subconstituency,
                                      office=original.office,
                                      center_type=RegistrationCenter.Types.COPY,
                                      copy_of=original)
            copy.full_clean()
            copy.save()
            copy_centers.append(copy)

        for i in range(num_no_reg_centers):
            constituency = Constituency.objects.filter(name_english='first')[0]
            subconstituency = random.choice(subconstituencies)
            center_id = CENTER_ID_MIN_INT_VALUE + num_registration_centers + num_copy_centers + i
            rc = RegistrationCenter(name='no-reg-polling-center-%d' % i,
                                    center_id=center_id,
                                    constituency=constituency,
                                    subconstituency=subconstituency,
                                    office=random.choice(offices),
                                    reg_open=False)
            rc.full_clean()
            rc.save()

        all_kinds_of_centers = centers + copy_centers + no_reg_centers

    if center_without_office:
        try:
            # by not specifying office and other infra, it will be "standalone"
            rc = RegistrationCenter(name='dummy-registration-center',
                                    center_id=UNUSED_CENTER_ID)
            rc.full_clean()
            rc.save()
        except ValidationError:
            pass  # assume that it already exists

    for election in elections:
        num_daily_reports_on_election_day = int(round(0.9 * num_daily_reports))
        centers_reported = set()
        for i in range(num_daily_reports_on_election_day):
            staff_phone_number = STAFF_PHONE_NUMBER_PATTERN % i
            from_center = random.choice(all_kinds_of_centers)
            ensure_staff_phone_exists(staff_phone_number, from_center, staff_phones,
                                      election.work_start_time + datetime.timedelta(minutes=5))

            # split votes between two options
            number_of_votes = (random.randint(1, 100), random.randint(1, 100))
            random_period_number = random.randint(FIRST_PERIOD_NUMBER, LAST_PERIOD_NUMBER)
            pr = PollingReport(election=election,
                               phone_number=staff_phone_number,
                               registration_center=from_center,
                               period_number=random_period_number,
                               num_voters=sum(number_of_votes),
                               creation_date=election.polling_start_time)
            pr.full_clean()
            pr.save()
            s = SMS(from_number=staff_phone_number, to_number=POLLING_REPORT_PHONE_NUMBER,
                    direction=INCOMING, message='my message', msg_type=SMS.POLLING_REPORT,
                    message_code=MESSAGE_1, carrier=carrier,
                    creation_date=election.polling_start_time)
            s.full_clean()
            s.save()

            if from_center in centers_reported:
                continue  # can't send but one PreliminaryVoteCount from a center

            # send a corresponding vote count
            for option, votes_for_option in enumerate(number_of_votes, start=1):
                pvc = PreliminaryVoteCount(election=election,
                                           phone_number=staff_phone_number,
                                           registration_center=from_center,
                                           option=option,
                                           num_votes=votes_for_option,
                                           creation_date=election.polling_start_time)
                pvc.full_clean()
                pvc.save()
                s = SMS(from_number=staff_phone_number,
                        to_number=PRELIMINARY_VOTE_COUNT_PHONE_NUMBER,
                        # XXX no specific message type for PreliminaryVoteCount
                        direction=INCOMING, message='my message', msg_type=SMS.POLLING_REPORT,
                        message_code=MESSAGE_1, carrier=carrier,
                        creation_date=election.polling_start_time)
                s.full_clean()
                s.save()

            centers_reported.add(from_center)

        # some daily reports on the day after
        for i in range(num_daily_reports - num_daily_reports_on_election_day):
            staff_phone_number = STAFF_PHONE_NUMBER_PATTERN % i
            rc = random.choice(all_kinds_of_centers)
            ensure_staff_phone_exists(staff_phone_number, rc, staff_phones,
                                      election.work_start_time + datetime.timedelta(minutes=5))
            report_creation_date = election.polling_start_time + datetime.timedelta(days=1)
            pr = PollingReport(election=election,
                               phone_number=staff_phone_number,
                               registration_center=rc,
                               period_number=LAST_PERIOD_NUMBER,  # day after counts as last period
                               num_voters=random.randint(1, 50),
                               creation_date=report_creation_date)
            pr.full_clean()
            pr.save()
            s = SMS(from_number=staff_phone_number, to_number=POLLING_REPORT_PHONE_NUMBER,
                    direction=INCOMING, message='my message', msg_type=SMS.POLLING_REPORT,
                    message_code=MESSAGE_1, carrier=carrier,
                    creation_date=election.polling_start_time)
            s.full_clean()
            s.save()

        # Tag some centers as inactive for the election.  We may or may not pick some that
        # sent messages as being inactive.
        num_inactive_centers_per_election = \
            min(num_inactive_centers_per_election, len(all_kinds_of_centers))
        if num_inactive_centers_per_election:
            reordered = all_kinds_of_centers
            random.shuffle(reordered)
            for i in range(num_inactive_centers_per_election):
                inactive_on_election = CenterClosedForElection(
                    registration_center=reordered[i], election=election
                )
                inactive_on_election.full_clean()
                inactive_on_election.save()

    tz = timezone(settings.TIME_ZONE)
    # construct a datetime that will change based on timezone discrepancies
    # 0-2am in Libya has a different date than the same time in UDT or EDT
    today_fragile = now().astimezone(tz).replace(hour=0, minute=59)

    # tz.normalize fixes up the date arithmetic when crossing DST boundaries
    creation_dates = \
        [tz.normalize((today_fragile -
                       datetime.timedelta(days=DAYS_BETWEEN_REGISTRATIONS * i)).astimezone(tz))
         for i in range(num_registration_dates)]

    citizens = []
    for i in range(num_registrations):
        # about 60% of registrations are for males, just as with actual data
        gender = MALE if random.randint(1, 100) <= 60 else FEMALE
        nat_id = '%d%011d' % (gender, i)

        creation_date = random.choice(creation_dates)
        modification_date = creation_date

        # Select voter ages from 18 years on up.
        voter_age = random.randint(18, 99)
        # If they were a certain age at any time yesterday, they are certainly that age at any time
        # today.
        yesterday = datetime.datetime.now().replace(tzinfo=tz) - datetime.timedelta(days=1)
        birth_date = datetime.date(yesterday.year - voter_age, yesterday.month, yesterday.day)
        civil_registry_id = random.randint(1, 99999999)
        citizen = CitizenFactory(civil_registry_id=civil_registry_id, national_id=nat_id,
                                 gender=gender, birth_date=birth_date)
        citizens.append(citizen)
        s = SMS(from_number=VOTER_PHONE_NUMBER_PATTERN % i, to_number=REGISTRATION_PHONE_NUMBER,
                citizen=citizen, direction=INCOMING,
                message='my reg message', msg_type=SMS.REGISTRATION, message_code=MESSAGE_1,
                carrier=carrier, creation_date=creation_date)
        s.full_clean()
        s.save()

        rc = random.choice(centers)

        confirmed = random.randint(1, 100) <= 80  # most are confirmed
        if confirmed:
            archive_time = None
        else:
            archive_time = random.choice(creation_dates)
        r = Registration(citizen=citizen, registration_center=rc, sms=s,
                         archive_time=archive_time,
                         creation_date=creation_date, modification_date=modification_date)
        r.full_clean()
        r.save()

    if num_registrations:  # if any data being generated
        # generate a variety of sms messages
        for i in range(NUM_RANDOM_SMS_MESSAGES):
            sms_type = random.choice(SMS.MESSAGE_TYPES)[0]
            staff_phone = random.choice(staff_phones)
            s = SMS(from_number=staff_phone.phone_number, to_number=RANDOM_MESSAGE_PHONE_NUMBER,
                    citizen=random.choice(citizens), direction=INCOMING,
                    message='my long random message',
                    msg_type=sms_type, message_code=MESSAGE_1, carrier=carrier,
                    creation_date=random.choice(creation_dates))
            s.full_clean()
            s.save()

        for election in elections:
            for rc in centers:
                i = random.randint(8888, 9999)
                staff_phone_number = STAFF_PHONE_NUMBER_PATTERN % i
                ensure_staff_phone_exists(staff_phone_number, rc, staff_phones,
                                          election.work_start_time + datetime.timedelta(minutes=5))
                center_open = CenterOpen(
                    election=election,
                    phone_number=staff_phone_number, registration_center=rc,
                    creation_date=election.polling_start_time.replace(hour=random.randint(0, 10),
                                                                      minute=23))
                center_open.full_clean()
                center_open.save()
                s = SMS(from_number=staff_phone_number, to_number=ACTIVATE_PHONE_NUMBER,
                        direction=INCOMING, message='my message', msg_type=SMS.ACTIVATE,
                        message_code=MESSAGE_1, carrier=carrier,
                        creation_date=election.polling_start_time)
                s.full_clean()
                s.save()