4
\$\begingroup\$

I am trying to implement a Doctor/patient scheduling system. It would be great if someone can review my code and suggest how I can improve it further. I would like to know how to have a date-based calendar for this. I also want some idea on how to protect a patient record data from one doctor to another.

One more feature I would like to know is: what kind of exception should I be raising instead of True or False?

SLOT_1 = '8:00AM'
SLOT_2 = '8:30AM'
SLOT_3 = '9:00AM'
SLOT_4 = '9:30AM'
SLOT_5 = '10:00AM'
SLOT_6 = '10:30AM'
SLOT_7 = '11:00AM'
SLOT_8 = '11:30AM'
SLOT_9 = '1:00PM'
SLOT_10 = '1:30PM'
SLOT_11 = '2:00PM'
SLOT_12 = '2:30PM'
SLOT_13 = '3:00PM'
SLOT_14 = '3:30PM'
SLOT_15 = '4:00PM'
SLOT_16 = '4:30PM'

CLASS_NAME = 'NAME'
CLASS_APPOINTMENT_INFO = 'APPOINTMENT_INFO'


class Patient(object):
    CLASS_ID = 'ID'
    CLASS_PREV_APPOINTMENTS = 'PREVIOUS_APPOINTMENTS'

    def __init__(self, f_name, l_name, ssn):
        self.f_name = f_name
        self.l_name = l_name
        self.ssn = ssn
        self.patient_name = self.f_name + " " + self.l_name
        self.patient_id = self.f_name[:1] + self.l_name + ssn
        self.patient_calendar = {
            CLASS_NAME: self.patient_name,
            self.CLASS_ID: self.patient_id,
            #self.CLASS_PREV_APPOINTMENTS: {},
            CLASS_APPOINTMENT_INFO: {}
        }
    def get_patient_record(self):
        patient_record =  {
            CLASS_NAME : self.patient_name,
            self.CLASS_ID : self.patient_id,
        }
        return patient_record

    def print_patient_calendar(self):
         print self.patient_calendar


class Doctor(object):
    CLASS_SPECIALITY = 'SPECIALITY'

    def __init__(self, f_name, l_name, speciality):
        self.f_name = f_name
        self.l_name = l_name
        self.doctor_name = self.f_name + " " + self.l_name
        self.speciality = speciality
        self.doctor_calendar = {
            CLASS_NAME: self.doctor_name,
            self.CLASS_SPECIALITY: self.speciality,
            CLASS_APPOINTMENT_INFO: {},
        }

    def get_doctor_record(self):
        doctor_record =  {
            CLASS_NAME : self.doctor_name,
            self.CLASS_SPECIALITY: self.speciality
        }
        return doctor_record

    def print_doctor_calendar(self):
        print self.doctor_calendar



class Scheduler(object):

    def schedule(self,doctor,patient,time):
        self.time = time
        self.doctor = doctor
        self.patient = patient
        if self.isdoctoravailable(doctor,time) and self.ispatientavailable(patient,time):
            self.update_patient_calendar(patient,doctor,time)
            self.update_doctor_calendar(patient,doctor,time)
            print "Appointment Scheduled with Dr. " + doctor.doctor_name +  " for patient " + patient.patient_calendar[CLASS_NAME] + "\n"
            return True

    def isdoctoravailable(self,doctor,time):
        if doctor.doctor_calendar[CLASS_APPOINTMENT_INFO].has_key(time):
            print "No Appointment Available with Dr. " + doctor.doctor_name + "\n"
            return False
        else:
            return True

    def ispatientavailable(self,patient,time):
        if patient.patient_calendar[CLASS_APPOINTMENT_INFO].has_key(time):
            print "The patient " + patient.patient_name +  " already has an appointment with Dr. " + patient.patient_calendar[CLASS_APPOINTMENT_INFO][time][CLASS_NAME] + "\n"
            return False
        else:
            return True

    def update_patient_calendar(self,patient,doctor,time):
        patient.patient_calendar[CLASS_APPOINTMENT_INFO][time] = doctor.get_doctor_record()

    def update_doctor_calendar(self,patient,doctor,time):
        doctor.doctor_calendar[CLASS_APPOINTMENT_INFO][time] = patient.get_patient_record()


D1 = Doctor("Ryan", "Giggs", "Dental")
D2 = Doctor("Alex", "Fergusson","General")
P1 = Patient("Wayne", "Rooney", "1234")
P2 = Patient("Wayne", "Bridge", "1214")

S1 = Scheduler()
S1.schedule(D1,P1,SLOT_11)
S1.schedule(D1,P2,SLOT_1)

P1.print_patient_calendar()
P2.print_patient_calendar()

D1.print_doctor_calendar()
D2.print_doctor_calendar()
\$\endgroup\$
2
\$\begingroup\$

Instead of defining 16 time slots I would recommend you to use datetime module to create a list of time slots. You should also store 'date' along with time. Datetime module provides functions for easy and quick time comparisons.

The following declarations are redundant:

    CLASS_NAME = 'NAME'
    CLASS_APPOINTMENT_INFO = 'APPOINTMENT_INFO'
    .....
    CLASS_ID = 'ID'
    CLASS_PREV_APPOINTMENTS = 'PREVIOUS_APPOINTMENTS'

Remove these declarations, and you can directly use these strings instead of the variables:

      self.patient_calendar = {
        'Name': self.patient_name,
        'Id' self.patient_id,
        'Previous_appointments': {},
        'Appointment_info': {}
    } 

This makes code smaller and simpler to understand. The keys are self explanatory.

You must implement function which allows storing the patient and doctor information to a file. I recommend pickle module to do this.

You can define a base class PERSON which contains variablea f_name, l_name, full_name and functions which are common to both doctor and patient a. Both Doctor and Patient class extends PERSON class. Instead of get_doctor_record() and get_patient_record() define a function get_record() in PERSON. This will give the code a proper logical structure and remove redundant code.

Remove function isdoctoravailable() and ispatientavailable() from Scheduler and add a function isavailable() in PERSON. So the new schedule function would like:

 def schedule(self,doctor,patient,time):

    self.time = time
    self.doctor = doctor
    self.patient = patient
    if self.doctor.isavailable(time) and self.patient.isavailable(time):
        self.patient.update_calendar(doctor,time)
        self.doctor.update_calendar(patient,time)
        print "Appointment Scheduled with Dr. " + doctor.doctor_name +  " for patient " + patient.patient_calendar[CLASS_NAME] + "\n"
        return True

Because now you have sent all the functions other than schedule inside the Scheduler class to Person class, I don't think defining Scheduler class makes sense. An independent schedule function will look better.

The following code gives a basic idea of how your code will look like after making the above mentioned changes.

class Person(object):
  def __init__(self, f_name, l_name):
      .....
  def get_record(self):
      ....
  def print_record(self):
      ....
  def save_record(self):
      ....
  def is_available(self, time):
      ....
  def update_calendar(self, person, time):
      ....


class Patient(object, Person):

  def __init__(self, f_name, l_name, ssn):
    super(Patient, self).__init(f_name, l_name)
    self.ssn = ssn


class Doctor(object, Person):

def __init__(self, f_name, l_name, speciality):
    super(Doctor, self).__init(self, f_name, l_name)
    self.speciality = speciality



def schedule(self,doctor,patient,time):
    self.time = time
    self.doctor = doctor
    self.patient = patient
    if self.doctor.is_available(time) and self.patient.is_available(time):
        self.patient.update_calendar(patient,time)
        self.doctor.update_calendar(doctor,time)
        print "something"
        return True

 D1 = Doctor("Ryan", "Giggs", "Dental")
 D2 = Doctor("Alex", "Fergusson","General")  
 P1 = Patient("Wayne", "Rooney", "1234")
 P2 = Patient("Wayne", "Bridge", "1214")
 schedule(D1,P1,SLOT_11)
 schedule(D1,P2,SLOT_1)
 P1.print_calendar()
 P2.print_calendar()
 D1.print_calendar()
 D2.print_calendar()
\$\endgroup\$
1
\$\begingroup\$

I agree with Pranav to refactor your classes, but a bit differently.

Person class

First name, last name, full name are all common attributes of Patient and Doctor objects, which can be captured by a common parent Person class. For example:

class Person(object):
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
        self.full_name = self.first_name + " " + self.last_name
        self.calendar = Calendar()

    def is_available(self, slot):
        return self.calendar.is_available(slot)

    def make_appointment(self, slot, record):
        self.calendar.add_entry(slot, record)

    def get_public_record(self):
        return {
            'name': self.full_name,
            'booking_class': self.__class__.__name__
        }

Then Patient and Doctor could become:

class Patient(Person):
    def __init__(self, first_name, last_name, ssn):
        super(Patient, self).__init__(first_name, last_name)
        self.ssn = ssn
        self.patient_id = self.first_name[:1] + self.last_name + ssn


class Doctor(Person):
    def __init__(self, first_name, last_name, speciality):
        super(Doctor, self).__init__(first_name, last_name)
        self.speciality = speciality

    def get_public_record(self):
        record = super(Doctor, self).get_public_record()
        record['specialty'] = self.speciality
        return record

I will explain about get_public_record further down.

Calendar class

Adding a Calendar class make senses to capture the common logic of storing appointments and checking availability. As you could see in the examples above, each Person has his independent Calendar instance. Perhaps something like this:

class Calendar(object):
    def __init__(self):
        self.entries = {}

    def is_available(self, slot):
        return slot not in self.entries

    def add_entry(self, slot, record):
        if not self.is_available(slot):
            raise DoubleBookingException
        self.entries[slot] = record

    def __str__(self):
        return str(self.entries)


class DoubleBookingException(Exception):
    pass

Making an appointment

In the examples above, the Person class delegates the is_available and make_appointment calls to his internal calendar instance. This way you can handle appointments in a concise and natural way:

def schedule(doctor, patient, slot):
    if not doctor.is_available(slot):
        print 'Cannot schedule, doctor is not available:', doctor
        return
    if not patient.is_available(slot):
        print 'Cannot schedule, patient is not available:', patient
        return

    doctor.make_appointment(slot, patient.get_public_record())
    patient.make_appointment(slot, doctor.get_public_record())

Protecting patient data from doctors

The entries in a Calendar object could contain the corresponding object. But that would leak too much information from one Person to another. Since you specifically asked to protect objects from each other, the Calendar stores simply dictionary entries, much like in your original version. A Person object only reveals part of its attributes in the get_public_record method. Notice that Doctor overrides get_public_record to disclose his "specialty" in addition to the common fields.

I hope you'll find this useful. Obviously there are many ways of modeling the situation, this is just one of them.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.