def post(self): my_print("==> In AppointmentPost, POST /appointments/") json_data = request.get_json() if not json_data: return { "message": "No input data received for creating an appointment" }, 400 # Should delete draft appointment, and free up slot, before booking. # Clear up a draft if one was previously created by user reserving this time. if json_data.get('appointment_draft_id'): draft_id_to_delete = int(json_data['appointment_draft_id']) Appointment.delete_draft([draft_id_to_delete]) if not application.config['DISABLE_AUTO_REFRESH']: socketio.emit('appointment_delete', draft_id_to_delete) is_blackout_appt = json_data.get('blackout_flag', 'N') == 'Y' csr = None user = None office = None # Create a citizen for later use. citizen = self.citizen_schema.load({}).data # Check if the appointment is created by public user. Can't depend on the IDP as BCeID is used by other users as well is_public_user_appointment = is_public_user() if is_public_user_appointment: office_id = json_data.get('office_id') service_id = json_data.get('service_id') user = PublicUser.find_by_username(g.oidc_token_info['username']) # Add values for contact info and notes json_data['contact_information'] = user.email telephone = f'. Phone: {user.telephone}' if user.telephone else '' json_data['comments'] = json_data.get('comments', '') + telephone citizen.user_id = user.user_id citizen.citizen_name = user.display_name office = Office.find_by_id(office_id) service = Service.query.get(int(service_id)) # Validate if the same user has other appointments for same day at same office appointments = Appointment.find_by_username_and_office_id( office_id=office_id, user_name=g.oidc_token_info['username'], start_time=json_data.get('start_time'), timezone=office.timezone.timezone_name) if appointments and len( appointments) >= office.max_person_appointment_per_day: return { "code": "MAX_NO_OF_APPOINTMENTS_REACHED", "message": "Maximum number of appointments reached" }, 400 # Check for race condition start_time = parse(json_data.get('start_time')) end_time = parse(json_data.get('end_time')) if not AvailabilityService.has_available_slots( office=office, start_time=start_time, end_time=end_time, service=service): return { "code": "CONFLICT_APPOINTMENT", "message": "Cannot create appointment due to scheduling conflict. Please pick another time." }, 400 else: csr = CSR.find_by_username(g.oidc_token_info['username']) office_id = csr.office_id office = Office.find_by_id(office_id) citizen.office_id = office_id citizen.qt_xn_citizen_ind = 0 citizen_state = CitizenState.query.filter_by( cs_state_name="Appointment booked").first() citizen.cs_id = citizen_state.cs_id citizen.start_time = datetime.now() citizen.service_count = 1 db.session.add(citizen) db.session.commit() appointment, warning = self.appointment_schema.load(json_data) if is_public_user_appointment: appointment.citizen_name = user.display_name appointment.online_flag = True if warning: logging.warning("WARNING: %s", warning) return {"message": warning}, 422 if appointment.office_id == office_id: appointment.citizen_id = citizen.citizen_id db.session.add(appointment) db.session.commit() # Generate CHES token try: ches_token = generate_ches_token() except Exception as exc: pprint(f'Error on token generation - {exc}') # If staff user is creating a blackout event then send email to all of the citizens with appointments for that period if is_blackout_appt: appointment_ids_to_delete = [] appointments_for_the_day = Appointment.get_appointment_conflicts( office_id, json_data.get('start_time'), json_data.get('end_time')) for (cancelled_appointment, office, timezone, user) in appointments_for_the_day: if cancelled_appointment.appointment_id != appointment.appointment_id and not cancelled_appointment.checked_in_time: appointment_ids_to_delete.append( cancelled_appointment.appointment_id) # Send blackout email try: pprint( 'Sending email for appointment cancellation due to blackout' ) send_email( ches_token, *get_blackout_email_contents( appointment, cancelled_appointment, office, timezone, user)) except Exception as exc: pprint(f'Error on email sending - {exc}') # Delete appointments if len(appointment_ids_to_delete) > 0: Appointment.delete_appointments(appointment_ids_to_delete) else: # Send confirmation email try: pprint('Sending email for appointment confirmation') send_email( ches_token, *get_confirmation_email_contents( appointment, office, office.timezone, user)) except Exception as exc: pprint(f'Error on email sending - {exc}') SnowPlow.snowplow_appointment(citizen, csr, appointment, 'appointment_create') result = self.appointment_schema.dump(appointment) if not application.config['DISABLE_AUTO_REFRESH']: socketio.emit('appointment_create', result.data) return {"appointment": result.data, "errors": result.errors}, 201 else: return { "The Appointment Office ID and CSR Office ID do not match!" }, 403
def post(self): json_data = request.get_json() if not json_data: return {"message": "No input data received for creating an appointment"}, 400 is_blackout_appt = json_data.get('blackout_flag', 'N') == 'Y' csr = None user = None office = None # Create a citizen for later use. citizen = self.citizen_schema.load({}).data # Check if the appointment is created by public user. Can't depend on the IDP as BCeID is used by other users as well is_public_user_appointment = is_public_user() if is_public_user_appointment: office_id = json_data.get('office_id') user = PublicUser.find_by_username(g.oidc_token_info['username']) # Add values for contact info and notes json_data['contact_information'] = user.email telephone = f'. Phone: {user.telephone}' if user.telephone else '' json_data['comments'] = json_data.get('comments', '') + telephone citizen.user_id = user.user_id citizen.citizen_name = user.display_name office = Office.find_by_id(office_id) # Validate if the same user has other appointments for same day at same office appointments = Appointment.find_by_username_and_office_id(office_id=office_id, user_name=g.oidc_token_info['username'], start_time=json_data.get('start_time'), timezone=office.timezone.timezone_name) if appointments and len(appointments) >= office.max_person_appointment_per_day: return {"code": "MAX_NO_OF_APPOINTMENTS_REACHED", "message": "Maximum number of appointments reached"}, 400 # Check for race condition start_time = parse(json_data.get('start_time')) end_time = parse(json_data.get('end_time')) if not AvailabilityService.has_available_slots(office=office, start_time=start_time, end_time=end_time): return {"code": "CONFLICT_APPOINTMENT", "message": "Cannot create appointment due to conflict in time"}, 400 else: csr = CSR.find_by_username(g.oidc_token_info['username']) office_id = csr.office_id office = Office.find_by_id(office_id) citizen.office_id = office_id citizen.qt_xn_citizen_ind = 0 citizen_state = CitizenState.query.filter_by(cs_state_name="Appointment booked").first() citizen.cs_id = citizen_state.cs_id citizen.start_time = datetime.now() citizen.service_count = 1 db.session.add(citizen) db.session.commit() appointment, warning = self.appointment_schema.load(json_data) if is_public_user_appointment: appointment.citizen_name = user.display_name appointment.online_flag = True if warning: logging.warning("WARNING: %s", warning) return {"message": warning}, 422 if appointment.office_id == office_id: appointment.citizen_id = citizen.citizen_id db.session.add(appointment) db.session.commit() # If staff user is creating a blackout event then send email to all of the citizens with appointments for that period if is_blackout_appt: appointment_ids_to_delete = [] appointments_for_the_day = Appointment.get_appointment_conflicts(office_id, json_data.get('start_time'), json_data.get('end_time')) for (cancelled_appointment, office, timezone, user) in appointments_for_the_day: if cancelled_appointment.appointment_id != appointment.appointment_id and not cancelled_appointment.checked_in_time: appointment_ids_to_delete.append(cancelled_appointment.appointment_id) # Send blackout email @copy_current_request_context def async_email(subject, email, sender, body): return send_email(subject, email, sender, body) thread = Thread(target=async_email, args=get_blackout_email_contents(appointment, cancelled_appointment, office, timezone, user)) thread.daemon = True thread.start() # Delete appointments if len(appointment_ids_to_delete) > 0: Appointment.delete_appointments(appointment_ids_to_delete) else: # Send confirmation email @copy_current_request_context def async_email(subject, email, sender, body): send_email(subject, email, sender, body) thread = Thread(target=async_email, args=get_confirmation_email_contents(appointment, office, office.timezone, user)) thread.daemon = True thread.start() SnowPlow.snowplow_appointment(citizen, csr, appointment, 'appointment_create') result = self.appointment_schema.dump(appointment) return {"appointment": result.data, "errors": result.errors}, 201 else: return {"The Appointment Office ID and CSR Office ID do not match!"}, 403