Example #1
0
    def setUp(self):
        self.referral_a = Referral(name="A", clicks=0)
        self.referral_a.save()
        self.referral_b = Referral(name="B", clicks=0)
        self.referral_b.save()
        self.referral_c = Referral(name="C", clicks=0, active=False)
        self.referral_c.save()

        self.detail_view = ReferralDetail.as_view()
        self.list_view = ReferralList.as_view()
Example #2
0
def signup(request):
    if request.method == "POST":
        username = request.POST.get("username")
        email = request.POST.get("email")
        user_n = User.objects.filter(username=username)
        user_e = User.objects.filter(email=email)
        password1 = request.POST.get("password1")
        code = request.POST.get("slug")

        if user_n.count() == 1 or user_e.count() == 1:
            messages.warning(
                request,
                "Username/email already taken or log in to complete signup")
            return redirect("register:signin")

        if code is "":
            '''If referral code is empty'''
            user = User.objects.create_user(username=username, email=email)
            Referral(user=user).save()
            user.set_password(password1)
            user.save()
            login(request, user)
            Pay(user=user, email=email).save()
            #Customer(user=user).save()
            return redirect("register:welcome")
        try:
            ref_user = Referral.objects.get(slug=code)
        except:
            messages.warning(request, "Wrong referral code")
            return redirect("register:signin")
        '''If referral code is not empty'''
        user = User.objects.create_user(username=username, email=email)
        referral = Referral(user=user,
                            referred_by=ref_user.user,
                            referred=True)
        ref_user.referred_users.add(user)
        user.set_password(password1)
        user.save()
        referral.save()
        ref_user.save()
        login(request, user)
        Pay(user=user, email=email).save()
        #Customer(user=user).save()
        message_to_customer(email)

        return redirect("register:welcome")

    else:
        return render(request, "register/signin.html")
Example #3
0
class APITestCase(TestCase):

    def setUp(self):
        self.referral_a = Referral(name="A", clicks=0)
        self.referral_a.save()
        self.referral_b = Referral(name="B", clicks=0)
        self.referral_b.save()
        self.referral_c = Referral(name="C", clicks=0, active=False)
        self.referral_c.save()

        self.detail_view = ReferralDetail.as_view()
        self.list_view = ReferralList.as_view()

    def test_can_see_active_referrals(self):
        factory = APIRequestFactory()
        request = factory.get('/api/referrals/')
        request.user = 1
        response = self.list_view(request)
        self.assertEqual(2, response.data['count'])
def patient_detail(request, pk):

    pt = get_object_or_404(mymodels.Patient, pk=pk)

    #   Special zipped list of action item types so they can be looped over.
    #   List 1: Labels for the panel objects of the action items
    #   List 2: Action Item lists based on type (active, pending, completed)
    #   List 3: Title labels for the action items
    #   List 4: True and False determines if the link should be for
    #           done_action_item or update_action_item

    active_ais = []
    inactive_ais = []
    done_ais = []

    # Add action items for apps that are turned on in Osler's base settings
    # OSLER_TODO_LIST_MANAGERS contains app names like referral which contain
    # tasks for clinical teams to carry out (e.g., followup with patient)
    for app, model in settings.OSLER_TODO_LIST_MANAGERS:
        ai = apps.get_model(app, model)

        active_ais.extend(ai.objects.get_active(patient=pt))
        inactive_ais.extend(ai.objects.get_inactive(patient=pt))
        done_ais.extend(ai.objects.get_completed(patient=pt))

    # Calculate the total number of action items for this patient,
    # This total includes all apps that that have associated
    # tasks requiring clinical followup (e.g., referral followup request)
    total_ais = len(active_ais) + len(inactive_ais) + len(done_ais)

    zipped_ai_list = zip(['collapse5', 'collapse6', 'collapse7'],
                         [active_ais, inactive_ais, done_ais],
                         ['Active Action Items', 'Pending Action Items',
                         'Completed Action Items'],
                         [True, True, False])

    # Provide referral list for patient page (includes specialty referrals)
    referrals = Referral.objects.filter(
        patient=pt,
        followuprequest__in=FollowupRequest.objects.all()
    )

    # Add FQHC referral status
    # Note it is possible for a patient to have been referred multiple times
    # This creates some strage cases (e.g., first referral was lost to followup
    # but the second one was successful). In these cases, the last referral
    # status becomes the current status
    fqhc_referrals = Referral.objects.filter(patient=pt, kind__is_fqhc=True)
    referral_status_output = Referral.aggregate_referral_status(fqhc_referrals)

    # Pass referral follow up set to page
    referral_followups = PatientContact.objects.filter(patient=pt)
    total_followups = referral_followups.count() + len(pt.followup_set())

    appointments = Appointment.objects \
        .filter(patient=pt) \
        .order_by('clindate', 'clintime')
    # d = collections.OrderedDict()
    # for a in appointments:
    #     if a.clindate in d:
    #         d[a.clindate].append(a)
    #     else:
    #         d[a.clindate] = [a]

    future_date_appointments = appointments.filter(
        clindate__gte=datetime.date.today()).order_by('clindate', 'clintime')
    previous_date_appointments = appointments.filter(
        clindate__lt=datetime.date.today()).order_by('-clindate', 'clintime')

    future_apt = collections.OrderedDict()
    for a in future_date_appointments:
        if a.clindate in future_apt:
            future_apt[a.clindate].append(a)
        else:
            future_apt[a.clindate] = [a]

    previous_apt = collections.OrderedDict()
    for a in previous_date_appointments:
        if a.clindate in previous_apt:
            previous_apt[a.clindate].append(a)
        else:
            previous_apt[a.clindate] = [a]

    zipped_apt_list = zip(
        ['collapse8', 'collapse9'],
        [future_date_appointments, previous_date_appointments],
        ['Future Appointments', 'Past Appointments'],
        [future_apt, previous_apt])

    return render(request,
                  'pttrack/patient_detail.html',
                  {'zipped_ai_list': zipped_ai_list,
                   'total_ais': total_ais,
                   'referral_status': referral_status_output,
                   'referrals': referrals,
                   'referral_followups': referral_followups,
                   'total_followups': total_followups,
                   'patient': pt,
                   'appointments_by_date': future_apt,
                   'zipped_apt_list': zipped_apt_list})
Example #5
0
    def harvest(self,
                create_tasks=True,
                create_locations=True,
                create_records=True,
                assignee=False):
        """Undertake the harvest process for this emailed referral.
        """
        from .utils import query_slip_esri

        if self.processed:
            return

        User = get_user_model()
        dbca = Agency.objects.get(slug='dbca')
        wapc = Organisation.objects.get(slug='wapc')
        assess_task = TaskType.objects.get(name='Assess a referral')
        if not assignee:
            assignee_default = User.objects.get(
                username=settings.REFERRAL_ASSIGNEE_FALLBACK)
        else:
            assignee_default = assignee
        actions = []
        attachments = self.emailattachment_set.all()
        self.log = ''

        # Emails without attachments are usually reminder notices.
        if not attachments.exists():
            s = 'Skipping harvested referral {} (no attachments)'.format(self)
            LOGGER.info(s)
            self.log = s
            self.processed = True
            self.save()
            actions.append('{} {}'.format(datetime.now().isoformat(), s))
            return actions
        # Must be an attachment named 'Application.xml' present to import.
        if not attachments.filter(name__istartswith='application.xml'):
            s = 'Skipping harvested referral {} (no XML attachment)'.format(
                self.pk)
            LOGGER.info(s)
            self.log = s
            self.processed = True
            self.save()
            actions.append('{} {}'.format(datetime.now().isoformat(), s))
            return actions
        else:
            xml_file = attachments.get(name__istartswith='application.xml')
        # Parse the attached XML file.
        try:
            d = xmltodict.parse(xml_file.attachment.read())
        except Exception as e:
            s = 'Harvested referral {} parsing of application.xml failed'.format(
                self.pk)
            LOGGER.error(s)
            LOGGER.exception(e)
            self.log = self.log + '{}\n{}\n'.format(s, e)
            self.processed = True
            self.save()
            actions.append('{} {}'.format(datetime.now().isoformat(), s))
        app = d['APPLICATION']
        reference = app['WAPC_APPLICATION_NO']

        # New/existing referral object.
        if Referral.objects.current().filter(reference__iexact=reference):
            # Note if the the reference no. exists in PRS already.
            s = 'Referral ref. {} is already in database; using existing referral'.format(
                reference)
            LOGGER.info(s)
            self.log = self.log + '{}\n'.format(s)
            actions.append('{} {}'.format(datetime.now().isoformat(), s))
            new_ref = Referral.objects.current().filter(
                reference__iexact=reference).order_by('-pk').first()
            referral_preexists = True
        else:
            # No match with existing references.
            s = 'Importing harvested referral ref. {} as new entity'.format(
                reference)
            LOGGER.info(s)
            self.log = '{}\n'.format(s)
            actions.append('{} {}'.format(datetime.now().isoformat(), s))
            new_ref = Referral(reference=reference)
            referral_preexists = False

        # Referral type
        try:
            ref_type = ReferralType.objects.filter(
                name__istartswith=app['APP_TYPE'])[0]
        except Exception:
            s = 'Referral type {} is not recognised type; skipping'.format(
                app['APP_TYPE'])
            LOGGER.warning(s)
            self.log = self.log + '{}\n'.format(s)
            self.processed = True
            self.save()
            actions.append('{} {}'.format(datetime.now().isoformat(), s))
            return actions

        # Determine the intersecting region(s).
        regions = []
        assigned = None
        # ADDRESS_DETAIL may or may not be a list :/
        if not isinstance(app['ADDRESS_DETAIL']['DOP_ADDRESS_TYPE'], list):
            addresses = [app['ADDRESS_DETAIL']['DOP_ADDRESS_TYPE']]
        else:
            addresses = app['ADDRESS_DETAIL']['DOP_ADDRESS_TYPE']
        # Address geometry:
        locations = []
        if create_locations:
            for a in addresses:
                # Use the long/lat info to intersect DBCA regions.
                try:
                    p = Point(x=float(a['LONGITUDE']), y=float(a['LATITUDE']))
                    for r in Region.objects.all():
                        if r.region_mpoly and r.region_mpoly.intersects(
                                p) and r not in regions:
                            regions.append(r)
                    intersected_region = True
                except Exception:
                    s = 'Address long/lat could not be parsed ({}, {})'.format(
                        a['LONGITUDE'], a['LATITUDE'])
                    LOGGER.warning(s)
                    self.log = self.log + '{}\n'.format(s)
                    actions.append('{} {}'.format(datetime.now().isoformat(),
                                                  s))
                    intersected_region = False
                # Use the PIN field to try returning geometry from SLIP.
                if 'PIN' in a and a['PIN']:
                    try:
                        resp = query_slip_esri(a['PIN'])
                        features = resp.json()[
                            'features']  # List of spatial features.
                        if len(features) > 0:
                            a['FEATURES'] = features
                            locations.append(
                                a)  # A dict for each address location.
                            # If we haven't yet, use the feature geom to intersect DBCA regions.
                            if not intersected_region:
                                for f in features:
                                    att = f['attributes']
                                    if 'centroid_longitude' in att and 'centroid_latitude' in att:
                                        p = Point(x=att['centroid_longitude'],
                                                  y=att['centroid_latitude'])
                                        for r in Region.objects.all():
                                            if r.region_mpoly and r.region_mpoly.intersects(
                                                    p) and r not in regions:
                                                regions.append(r)
                        s = 'Address PIN {} returned geometry from SLIP'.format(
                            a['PIN'])
                        self.log = self.log + '{}\n'.format(s)
                        LOGGER.info(s)
                    except Exception as e:
                        s = 'Error querying Landgate SLIP for spatial data (referral ref. {})'.format(
                            reference)
                        LOGGER.error(s)
                        LOGGER.error(resp.content)
                        LOGGER.exception(e)
                        self.log = self.log + '{}\n{}\n{}\n'.format(
                            s, resp.content, e)
                else:
                    s = 'Address PIN could not be parsed ({})'.format(a['PIN'])
                    LOGGER.warning(s)
                    self.log = self.log + '{}\n'.format(s)
        regions = set(regions)
        # Business rules:
        # Didn't intersect a region? Might be bad geometry in the XML.
        # Likewise if >1 region was intersected, default to Swan Region
        # and the designated fallback user.
        if len(regions) == 0:
            region = Region.objects.get(name='Swan')
            assigned = assignee_default
            s = 'No regions were intersected, defaulting to {} ({})'.format(
                region, assigned)
            LOGGER.info(s)
            self.log = self.log + '{}\n'.format(s)
        elif len(regions) > 1:
            region = Region.objects.get(name='Swan')
            assigned = assignee_default
            s = '>1 regions were intersected ({}), defaulting to {} ({})'.format(
                regions, region, assigned)
            LOGGER.info(s)
            self.log = self.log + '{}\n'.format(s)
        else:
            region = regions.pop()
            try:
                assigned = RegionAssignee.objects.get(region=region).user
            except Exception:
                s = 'No default assignee set for {}, defaulting to {}'.format(
                    region, assignee_default)
                LOGGER.info(s)
                self.log = self.log + '{}\n'.format(s)
                actions.append('{} {}'.format(datetime.now().isoformat(), s))
                assigned = assignee_default

        # Create/update the referral in PRS.
        new_ref.type = ref_type
        new_ref.agency = dbca
        new_ref.referring_org = wapc
        new_ref.reference = reference
        new_ref.description = app[
            'DEVELOPMENT_DESCRIPTION'] if 'DEVELOPMENT_DESCRIPTION' in app else ''
        new_ref.referral_date = self.received.date()
        new_ref.address = app['LOCATION'] if 'LOCATION' in app else ''
        with create_revision():
            new_ref.save()
            set_comment('Initial version.')

        if referral_preexists:
            s = 'PRS referral updated: {}'.format(new_ref)
            LOGGER.info(s)
            self.log = self.log + '{}\n'.format(s)
            actions.append('{} {}'.format(datetime.now().isoformat(), s))
        else:
            s = 'New PRS referral generated: {}'.format(new_ref)
            LOGGER.info(s)
            self.log = self.log + '{}\n'.format(s)
            actions.append('{} {}'.format(datetime.now().isoformat(), s))

        # Assign to a region.
        new_ref.regions.add(region)
        # Assign an LGA.
        try:
            new_ref.lga = LocalGovernment.objects.get(
                name=app['LOCAL_GOVERNMENT'])
            new_ref.save()
        except Exception:
            s = 'LGA {} was not recognised'.format(app['LOCAL_GOVERNMENT'])
            LOGGER.warning(s)
            self.log = self.log + '{}\n'.format(s)
            actions.append('{} {}'.format(datetime.now().isoformat(), s))

        # Add triggers to the new referral.
        if 'MRSZONE_TEXT' in app:
            triggers = [i.strip() for i in app['MRSZONE_TEXT'].split(',')]
        else:
            triggers = []
        added_trigger = False
        for i in triggers:
            # A couple of exceptions for DoP triggers follow (specific -> general trigger).
            if i.startswith('BUSH FOREVER SITE'):
                added_trigger = True
                new_ref.dop_triggers.add(
                    DopTrigger.objects.get(name='Bush Forever site'))
            elif i.startswith('DPW ESTATE'):
                added_trigger = True
                new_ref.dop_triggers.add(
                    DopTrigger.objects.get(name='Parks and Wildlife estate'))
            elif i.find('REGIONAL PARK') > -1:
                added_trigger = True
                new_ref.dop_triggers.add(
                    DopTrigger.objects.get(name='Regional Park'))
            # All other triggers (don't use exists() in case of duplicates).
            elif DopTrigger.objects.current().filter(
                    name__istartswith=i).count() == 1:
                added_trigger = True
                new_ref.dop_triggers.add(
                    DopTrigger.objects.current().get(name__istartswith=i))
        # If we didn't link any DoP triggers, link the "No Parks and Wildlife trigger" tag.
        if not added_trigger:
            new_ref.dop_triggers.add(
                DopTrigger.objects.get(name='No Parks and Wildlife trigger'))

        # Add locations to the new referral (one per polygon in each MP geometry).
        if create_locations:
            new_locations = []
            for l in locations:
                for f in l['FEATURES']:
                    poly = Polygon(f['geometry']['rings'][0])
                    geom = GEOSGeometry(poly.wkt)
                    new_loc = Location(address_suffix=l['NUMBER_FROM_SUFFIX'],
                                       road_name=l['STREET_NAME'],
                                       road_suffix=l['STREET_SUFFIX'],
                                       locality=l['SUBURB'],
                                       postcode=l['POSTCODE'],
                                       referral=new_ref,
                                       poly=geom)
                    try:  # NUMBER_FROM XML fields started to contain non-integer values :(
                        new_loc.address_no = int(
                            l['NUMBER_FROM']) if l['NUMBER_FROM'] else None
                    except:
                        pass  # Just ignore the value if it can't be parsed as an integer.
                    with create_revision():
                        new_loc.save()
                        set_comment('Initial version.')
                    new_locations.append(new_loc)
                    s = 'New PRS location generated: {}'.format(new_loc)
                    LOGGER.info(s)
                    self.log = self.log + '{}\n'.format(s)
                    actions.append('{} {}'.format(datetime.now().isoformat(),
                                                  s))

            # Check to see if new locations intersect with any existing locations.
            intersecting = []
            for l in new_locations:
                other_l = Location.objects.current().exclude(pk=l.pk).filter(
                    poly__isnull=False, poly__intersects=l.poly)
                if other_l.exists():
                    intersecting += list(other_l)
            # For any intersecting locations, relate the new and existing referrals.
            for l in intersecting:
                if l.referral.pk != new_ref.pk:
                    new_ref.add_relationship(l.referral)
                    s = 'New referral {} related to existing referral {}'.format(
                        new_ref.pk, l.referral.pk)
                    LOGGER.info(s)
                    self.log = self.log + '{}\n'.format(s)
                    actions.append('{} {}'.format(datetime.now().isoformat(),
                                                  s))

        # Create an "Assess a referral" task and assign it to a user.
        if create_tasks:
            new_task = Task(type=assess_task,
                            referral=new_ref,
                            start_date=new_ref.referral_date,
                            description=new_ref.description,
                            assigned_user=assigned)
            new_task.state = assess_task.initial_state
            if 'DUE_DATE' in app and app['DUE_DATE']:
                try:
                    due = datetime.strptime(app['DUE_DATE'], '%d-%b-%y')
                except Exception:
                    due = datetime.today() + timedelta(assess_task.target_days)
            else:
                due = datetime.today() + timedelta(assess_task.target_days)
            new_task.due_date = due
            with create_revision():
                new_task.save()
                set_comment('Initial version.')
            s = 'New PRS task generated: {} assigned to {}'.format(
                new_task, assigned.get_full_name())
            LOGGER.info(s)
            self.log = self.log + '{}\n'.format(s)
            actions.append('{} {}'.format(datetime.now().isoformat(), s))

            # Email the assigned user about the new task.
            new_task.email_user()
            s = 'Task assignment email sent to {}'.format(assigned.email)
            LOGGER.info(s)
            self.log = self.log + '{}\n'.format(s)
            actions.append('{} {}'.format(datetime.now().isoformat(), s))

        # Save the EmailedReferral as a record on the referral.
        if create_records:
            new_record = Record.objects.create(name=self.subject,
                                               referral=new_ref,
                                               order_date=datetime.today())
            file_name = 'emailed_referral_{}.html'.format(reference)
            new_file = ContentFile(self.body)
            new_record.uploaded_file.save(file_name, new_file)
            with create_revision():
                new_record.save()
                set_comment('Initial version.')
            s = 'New PRS record generated: {}'.format(new_record)
            LOGGER.info(s)
            self.log = self.log + '{}\n'.format(s)
            actions.append('{} {}'.format(datetime.now().isoformat(), s))

            # Add records to the referral (one per attachment).
            for i in attachments:
                new_record = Record.objects.create(name=i.name,
                                                   referral=new_ref,
                                                   order_date=datetime.today())
                # Duplicate the uploaded file.
                new_file = ContentFile(i.attachment.read())
                new_record.uploaded_file.save(i.name, new_file)
                new_record.save()
                s = 'New PRS record generated: {}'.format(new_record)
                LOGGER.info(s)
                self.log = self.log + '{}\n'.format(s)
                actions.append('{} {}'.format(datetime.now().isoformat(), s))
                # Link the attachment to the new, generated record.
                i.record = new_record
                i.save()

        # Link the emailed referral to the new or existing referral.
        self.referral = new_ref
        self.processed = True
        self.save()

        return actions
Example #6
0
File: views.py Project: wwick/osler
def patient_detail(request, pk):

    pt = get_object_or_404(mymodels.Patient, pk=pk)

    #   Special zipped list of action item types so they can be looped over.
    #   List 1: Labels for the panel objects of the action items
    #   List 2: Action Item lists based on type (active, pending, completed)
    #   List 3: Title labels for the action items
    #   List 4: True and False determines if the link should be for
    #           done_action_item or update_action_item

    active_ais = []
    inactive_ais = []
    done_ais = []

    # Add action items for apps that are turned on in Osler's base settings
    # OSLER_TODO_LIST_MANAGERS contains app names like referral which contain
    # tasks for clinical teams to carry out (e.g., followup with patient)
    for app, model in settings.OSLER_TODO_LIST_MANAGERS:
        ai = apps.get_model(app, model)

        active_ais.extend(ai.objects.get_active(patient=pt))
        inactive_ais.extend(ai.objects.get_inactive(patient=pt))
        done_ais.extend(ai.objects.get_completed(patient=pt))

    # Calculate the total number of action items for this patient,
    # This total includes all apps that that have associated
    # tasks requiring clinical followup (e.g., referral followup request)
    total_ais = len(active_ais) + len(inactive_ais) + len(done_ais)

    zipped_ai_list = zip(['collapse5', 'collapse6', 'collapse7'],
                         [active_ais, inactive_ais, done_ais], [
                             'Active Action Items', 'Pending Action Items',
                             'Completed Action Items'
                         ], [True, True, False])

    # Provide referral list for patient page (includes specialty referrals)
    referrals = Referral.objects.filter(
        patient=pt, followuprequest__in=FollowupRequest.objects.all())

    # Add FQHC referral status
    # Note it is possible for a patient to have been referred multiple times
    # This creates some strage cases (e.g., first referral was lost to followup
    # but the second one was successful). In these cases, the last referral
    # status becomes the current status
    fqhc_referrals = Referral.objects.filter(patient=pt, kind__is_fqhc=True)
    referral_status_output = Referral.aggregate_referral_status(fqhc_referrals)

    # Pass referral follow up set to page
    referral_followups = PatientContact.objects.filter(patient=pt)
    total_followups = referral_followups.count() + len(pt.followup_set())

    appointments = Appointment.objects \
        .filter(patient=pt) \
        .order_by('clindate', 'clintime')
    # d = collections.OrderedDict()
    # for a in appointments:
    #     if a.clindate in d:
    #         d[a.clindate].append(a)
    #     else:
    #         d[a.clindate] = [a]

    future_date_appointments = appointments.filter(
        clindate__gte=datetime.date.today()).order_by('clindate', 'clintime')
    previous_date_appointments = appointments.filter(
        clindate__lt=datetime.date.today()).order_by('-clindate', 'clintime')

    future_apt = collections.OrderedDict()
    for a in future_date_appointments:
        if a.clindate in future_apt:
            future_apt[a.clindate].append(a)
        else:
            future_apt[a.clindate] = [a]

    previous_apt = collections.OrderedDict()
    for a in previous_date_appointments:
        if a.clindate in previous_apt:
            previous_apt[a.clindate].append(a)
        else:
            previous_apt[a.clindate] = [a]

    zipped_apt_list = zip(
        ['collapse8', 'collapse9'],
        [future_date_appointments, previous_date_appointments],
        ['Future Appointments', 'Past Appointments'],
        [future_apt, previous_apt])

    return render(
        request, 'pttrack/patient_detail.html', {
            'zipped_ai_list': zipped_ai_list,
            'total_ais': total_ais,
            'referral_status': referral_status_output,
            'referrals': referrals,
            'referral_followups': referral_followups,
            'total_followups': total_followups,
            'patient': pt,
            'appointments_by_date': future_apt,
            'zipped_apt_list': zipped_apt_list
        })