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 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")
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})
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
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 })