Beispiel #1
0
 def process_batch(self, prisoners):
     prisoner_locations = []
     locations_to_delete = []
     for prisoner in prisoners:
         single_offender_id = prisoner['id']
         prisoner_number = prisoner.get('noms_id')
         if not prisoner_number:
             self.stderr.write('Offender %s has no prisoner number' % single_offender_id)
             continue
         prison_id = prisoner.get('establishment_code')
         if self.modified_only and prison_id == self.released_establishment_code:
             if self.verbosity > 1:
                 self.stdout.write('Will delete location for %s' % prisoner_number)
             locations_to_delete.append(prisoner_number)
             continue
         elif prison_id not in self.known_prisons:
             if self.verbosity > 1 and prison_id not in self.ignored_establishment_codes:
                 self.stdout.write('Unknown establishment code %s for %s' % (prison_id, prisoner_number))
             continue
         prisoner_dob = parse_date(prisoner.get('date_of_birth') or '')
         if not prisoner_dob:
             self.stderr.write('Offender %s (%s) has no date of birth' % (prisoner_number, single_offender_id))
             continue
         prisoner_name = ' '.join(prisoner.get(field) or '' for field in self.name_fields)
         prisoner_name = self.whitespace.sub(' ', prisoner_name)
         prisoner_locations.append(
             PrisonerLocation(
                 single_offender_id=single_offender_id,
                 prisoner_number=prisoner_number,
                 prison_id=prison_id,
                 prisoner_dob=prisoner_dob,
                 prisoner_name=prisoner_name,
             )
         )
     return prisoner_locations, locations_to_delete
Beispiel #2
0
def load_prisoner_locations_from_file(filename, single_offender_id=True):
    """
    Load prisoner locations matching test NOMIS data
    """
    if single_offender_id:
        extra_key = 'single_offender_id'
        extra_value = uuid.uuid4
    else:
        extra_key = 'created_by'
        extra_value = get_user_model().objects.first()
    csv_path = os.path.join(os.path.dirname(__file__), os.path.pardir,
                            'fixtures', filename)
    with open(csv_path) as f:
        csv_reader = csv.DictReader(f)
        prisoner_locations = list(csv_reader)
    for prisoner_location in prisoner_locations:
        prisoner_location[extra_key] = extra_value() if callable(
            extra_value) else extra_value
        prisoner_location['prison'] = Prison.objects.get(
            nomis_id=prisoner_location['prison'])
        prisoner_location['prisoner_dob'] = parse_date(
            prisoner_location['prisoner_dob'])
        prisoner_location['active'] = True

    PrisonerLocation.objects.bulk_create(
        map(lambda data: PrisonerLocation(**data), prisoner_locations))
Beispiel #3
0
def fetch_prisoner_location_from_nomis(
        prisoner_location: PrisonerLocation) -> Optional[PrisonerLocation]:
    try:
        new_location = nomis.get_location(prisoner_location.prisoner_number)
        if not new_location:
            logger.error(
                'Malformed response from nomis when looking up prisoner location for '
                f'{prisoner_location.prisoner_number}')
            return None
        new_prison = Prison.objects.get(nomis_id=new_location['nomis_id'])
    except requests.RequestException:
        logger.error(
            f'Cannot look up prisoner location for {prisoner_location.prisoner_number} in NOMIS'
        )
        return None
    except Prison.DoesNotExist:
        logger.error(
            f'Cannot find prison matching {new_location["nomis_id"]} in Prison table'
        )
        return None
    else:
        logger.info(
            f'Location fetched from nomis of {prisoner_location.prisoner_number} is {new_prison.nomis_id}'
        )
        # This update will only persist in python space. It is NOT committed to the database
        # This is because we should be calling credit_prisons_need_updating on any update to PrisonerLocation and that
        # takes too long to do synchronously off the back of a user-triggered API Request
        prisoner_location.prison = new_prison
        return prisoner_location
Beispiel #4
0
def load_random_prisoner_locations(number_of_prisoners=50,
                                   single_offender_id=True):
    if single_offender_id:
        extra_key = 'single_offender_id'
        extra_value = uuid.uuid4
    else:
        extra_key = 'created_by'
        extra_value = get_user_model().objects.first()
    prisons = cycle(Prison.objects.all())
    prisoner_locations = generate_predefined_prisoner_locations(
        single_offender_id=single_offender_id)
    prisoner_locations += [{
        extra_key:
        extra_value() if callable(extra_value) else extra_value,
        'prisoner_name':
        random_prisoner_name(),
        'prisoner_number':
        random_prisoner_number(),
        'prisoner_dob':
        random_prisoner_dob(),
        'prison':
        next(prisons),
        'active':
        True,
    } for _ in range(number_of_prisoners - 2)]
    PrisonerLocation.objects.bulk_create(
        map(lambda data: PrisonerLocation(**data), prisoner_locations))
def load_prisoner_locations_from_dev_prison_api(number_of_prisoners=50):
    """
    Get prisoners locations from the dev HMPPS Prison API.

    This relies on the existance of well-known prisons in the dev API.

    See API documentation: https://api.prison.service.justice.gov.uk/swagger-ui/index.html
    """

    if settings.ENVIRONMENT == 'prod':
        raise Exception(
            'Do not load prisoner locations from production HMPPS Prison API')

    prison_ids = [
        'BWI',  # HMP Berwyn
        'NMI',  # HMP Nottingham
        'WLI',  # HMP Wayland
    ]
    created_by = get_user_model().objects.first()

    prisons = {}
    prisoners_ids = {}
    for prison_id in prison_ids:
        prisons[prison_id] = Prison.objects.get(pk=prison_id)

        resp = nomis.connector.get(f'prison/{prison_id}/live_roll')
        resp['noms_ids'].sort()  # Sort to improve reproducibility
        prisoners_ids[prison_id] = deque(resp['noms_ids'])

    prison_ids = cycle(prison_ids)
    prisoner_locations = []
    # Cycle through prisons, take a prisoner from each prison's queue
    # Until we generated enough PrisonerLocation or there are no prisoners left
    while len(prisoner_locations) < number_of_prisoners:
        empty = [len(q) == 0 for q in prisoners_ids.values()]
        if all(empty):
            break  # No more prisoners in any of these prisons

        prison_id = next(prison_ids)
        if len(prisoners_ids[prison_id]) == 0:
            continue  # No more prisoners in this prison

        prisoner_id = prisoners_ids[prison_id].popleft()
        resp = nomis.connector.get(f'offenders/{prisoner_id}')
        prisoner_location = {
            'prisoner_number': prisoner_id,
            'prisoner_name': resp['given_name'] + ' ' + resp['surname'],
            'prisoner_dob': parse_date(resp['date_of_birth']),
            'prison': prisons[prison_id],
            'active': True,
            'created_by': created_by,
        }
        prisoner_locations.append(prisoner_location)

    return PrisonerLocation.objects.bulk_create(
        map(lambda data: PrisonerLocation(**data), prisoner_locations))
def load_random_prisoner_locations(number_of_prisoners=50):
    prisons = cycle(Prison.objects.all())
    prisoner_locations = generate_predefined_prisoner_locations()
    prisoner_locations += [{
        'created_by': get_user_model().objects.first(),
        'prisoner_name': random_prisoner_name(),
        'prisoner_number': random_prisoner_number(),
        'prisoner_dob': random_prisoner_dob(),
        'prison': next(prisons),
        'active': True,
    } for _ in range(number_of_prisoners - 2)]
    return PrisonerLocation.objects.bulk_create(
        map(lambda data: PrisonerLocation(**data), prisoner_locations))
def load_prisoner_locations_from_file(filename):
    """
    Load prisoner locations matching test NOMIS data
    """

    csv_path = os.path.join(os.path.dirname(__file__), os.path.pardir,
                            'fixtures', filename)
    with open(csv_path) as f:
        csv_reader = csv.DictReader(f)
        prisoner_locations = list(csv_reader)
    for prisoner_location in prisoner_locations:
        prisoner_location['created_by'] = get_user_model().objects.first(),
        prisoner_location['prison'] = Prison.objects.get(
            nomis_id=prisoner_location['prison'])
        prisoner_location['prisoner_dob'] = parse_date(
            prisoner_location['prisoner_dob'])
        prisoner_location['active'] = True

    return PrisonerLocation.objects.bulk_create(
        map(lambda data: PrisonerLocation(**data), prisoner_locations))
 def create(self, validated_data):
     locations = [PrisonerLocation(**item) for item in validated_data]
     objects = PrisonerLocation.objects.bulk_create(locations)
     return objects