import math
import os
import sys
import threading
import traceback
import uuid
from datetime import date, datetime, timedelta

import pdfkit
import pymysql
import requests
from flask import (Flask, Response, json, jsonify, redirect, render_template,
				   request, url_for, make_response)

from database.booking_activity_log import BookingActivity
from database.booking_details import Detail
from database.donation import Donation
from database.booking_guest_types import GuestType
from database.booking_guests import BookingGuest
from database.booking_payments import BookingPayment
from database.booking_promo_code import PromoCode
from database.booking_status import BookingStatus
from database.booking_tickets import Ticket
from database.booking_types import BookingType
from database.bookings import Booking
from database.bookings_notes import Note
from database.check_in_vehicles import CheckInVehicle
from database.contact_list import ContactList
from database.credit_note import CreditNote
from database.credit_note_facilities import CreditNoteFacility
from database.credit_note_guests import CreditNoteGuest
from database.credit_note_inventory import CreditNoteInventory
from database.credit_note_vehicles import CreditNoteVehicle
from database.destination import Destination
from database.facility import Facility
from database.gate import Gate
from database.gatepass import Gatepass
from database.gatepass_details import GatepassDetail
from database.gatepass_guests import GatepassGuest
from database.gatepass_vehicles import GatepassVehicle
from database.group import Group
from database.inventory import Inventory
from database.invoice import Invoice
from database.mandatory_payment_prices import MandatoryPaymentPrices
from database.mandatory_payments import Mandatory
from database.member import Member
from database.modify import Modify
from database.partner import Partner
from database.payment_methods import PaymentMethod
from database.salesforce import SalesforceData
from database.school import School
from database.school_booking import SchoolBooking
from database.sun import Sun
from database.transaction import Transaction
from database.vehicle import Vehicle
from database.vehicle_details import VehicleDetail
from database.entry_mode import EntryMode
from database.booking_account import BookingAccount
from functions.async_functions import AsyncRequests
from functions.booking_snippets import *
from functions.currency_operators import *
from functions.date_operators import *
from functions.validation import *
# File imports
from routes import (FromCache, app, bookings_logger, db, db_cache,
					receipt_print_options, sessionTracking, ticketGenerator)
from routes.salesforce_v2 import send_single_visit_salesforce
from routes.seed_functions import (BookingGuestTypesSeed, BookingStatusSeed,
								   BookingTypeSeed, MandatoryPaymentsSeed)
from variables import *
from routes.salesforce_v2 import send_booking_info_to_salesforce
from routes.booking_ban import check_booking_ban
from routes.booking_finances import add_booking_user

def close(self):
	self.session.close()


def convertAmount(currency_to, currency_from, amount, buying_rate,
				  selling_rate, date):
	amount = round(amount, 2)

	if currency_to == currency_from:
		return float(amount)
	elif currency_to != currency_from:
		if currency_from == "162fface-f5f1-41de-913b-d2bb784dda3a":
			post_data = {"currency_id": currency_to, "date": date}

			get_rates = requests.post(get_currency_rate_at_time,
									  json=post_data)

			buying_rate = get_rates.json()["data"][0]["buy_amount"]

			value = float(amount) / float(buying_rate)
			return float(value)

		elif currency_to == "162fface-f5f1-41de-913b-d2bb784dda3a":
			value = float(amount) * float(selling_rate)
			return float(value)


def currencyPostProcessor(currencyTo, currencyFrom, amount, buyingRate,
						  sellingRate):
	"""
	Different from currencyHandler in that it does not get the current buying/selling rate,
	but works with buying/selling rate that's already been saved.
	"""
	if currencyTo == currencyFrom:
		return float(amount)
	elif currencyTo != currencyFrom:
		if currencyFrom == "162fface-f5f1-41de-913b-d2bb784dda3a":
			value = float(amount) / float(buyingRate)
			return float(value)

		elif currencyTo == "162fface-f5f1-41de-913b-d2bb784dda3a":
			value = float(amount) * float(sellingRate)
			return float(value)


def currencyHandler(currencyTo, currencyFrom, amount):
	if currencyTo == currencyFrom:
		return amount
	elif currencyTo != currencyFrom:
		if currencyFrom == "162fface-f5f1-41de-913b-d2bb784dda3a":
			get_rate = requests.get(get_buy_sell_rate.format(currencyTo))

			try:
				buying = get_rate.json()["data"][0]["currency_buy_amount"]
				selling = get_rate.json()["data"][0]["currency_sell_amount"]

				value = float(amount) / float(buying)
				return float(value)
			except Exception:
				value = 0
				return float(value)

		elif currencyTo == "162fface-f5f1-41de-913b-d2bb784dda3a":
			get_rate = requests.get(get_buy_sell_rate.format(currencyFrom))

			try:
				buying = get_rate.json()["data"][0]["currency_buy_amount"]
				selling = get_rate.json()["data"][0]["currency_sell_amount"]

				value = float(amount) * float(selling)
				return float(value)
			except Exception:
				value = 0
				return float(value)

		else:
			get_from_rate = requests.get(
				get_buy_sell_rate.format(currencyFrom))
			get_to_rate = requests.get(get_buy_sell_rate.format(currencyTo))

			try:
				from_buying = get_from_rate.json(
				)["data"][0]["currency_buy_amount"]
				from_selling = get_from_rate.json(
				)["data"][0]["currency_sell_amount"]

				to_buying = get_to_rate.json(
				)["data"][0]["currency_buy_amount"]
				to_selling = get_to_rate.json(
				)["data"][0]["currency_sell_amount"]

				temp_from = float(amount) * float(from_selling)
				temp_to = float(temp_from) / float(to_buying)
				value = temp_to
				return float(value)
			except Exception:
				value = 0
				return float(value)


def send_booking_email(email_data, partner=None):
	email_response = []

	# recipient = email_data["recipient"]
	for recipient in email_data["recipient"]:
		sender = email_data["sender"]

		booking_details = {}
		booking_details["booking_ref_code"] = email_data["booking_ref_code"]
		booking_details["booking_id"] = email_data["booking_id"]
		booking_details["first_name"] = email_data["first_name"]
		booking_details["last_name"] = email_data["last_name"]
		booking_details["check_in_date"] = email_data["check_in_date"]
		booking_details["check_out_date"] = email_data["check_out_date"]
		booking_details["num_of_guests"] = email_data["num_of_guests"]
		booking_details["num_of_vehicles"] = email_data["num_of_vehicles"]
		booking_details["client"] = email_data[
			"first_name"] + " " + email_data["last_name"]
		booking_details["copyright_year"] = datetime.now().strftime("%Y")

		# bookingTotal(booking_details, email_data["booking_id"])

		sg = sendgrid.SendGridAPIClient(apikey=app.config["SENDGRID_API_KEY"])

		from_email = Email(sender)
		to_email = Email(recipient)
		subject = email_data["subject"]
		content = Content(
			"text/html",
			render_template("booking_confirmation.html",
							data=booking_details,
							activities=email_data["inventory_info"],
							facilities=email_data["facility_info"],
							guests=email_data["guest_info"],
							vehicles=email_data["vehicle_info"]))
		mail = Mail(from_email, subject, to_email, content)

		if partner:
			pass
		else:
			try:
				response = sg.client.mail.send.post(request_body=mail.get())

				email_response.append(str(response))

				booking_activity = BookingActivity(
					booking_activity_public_id=str(uuid.uuid4()),
					booking_id=email_data["booking_id"],
					booking_activity_description="Notification email sent to "
					+ recipient + " from " + sender,
					session_id=None,
					created_at=datetime.now())

				db.session.add(booking_activity)

				db.session.commit()
				close(db)

			except Exception as e:
				# messages.append(str(e))
				# return jsonify({"message": messages})
				error_tuple = sys.exc_info()
				trace = traceback.format_exc()
				raise Exception("User email notification: " + str(e) +
								". Trace: " + trace)

	get_contacts = db.session.query(ContactList)\
	 .filter(ContactList.deletion_marker == None)\
	 .all()

	if get_contacts:
		for single_email in get_contacts:
			email_source = Email(sender)
			email_destination = Email(single_email.contact_email)
			subject = "Reservation Details"
			content = Content(
				"text/html",
				render_template("booking_notification.html",
								data=booking_details,
								activities=email_data["inventory_info"],
								facilities=email_data["facility_info"],
								guests=email_data["guest_info"],
								vehicles=email_data["vehicle_info"]))
			info_mail = Mail(email_source, subject, email_destination, content)

			try:
				resp = sg.client.mail.send.post(request_body=info_mail.get())

				email_response.append(str(resp))

				booking_activity = BookingActivity(
					booking_activity_public_id=str(uuid.uuid4()),
					booking_id=email_data["booking_id"],
					booking_activity_description="Notification email sent to "
					+ single_email.contact_email + " from " + sender,
					session_id=None,
					created_at=datetime.now())

				db.session.add(booking_activity)

				db.session.commit()
				close(db)

			except Exception as e:
				# pass
				error_tuple = sys.exc_info()
				trace = traceback.format_exc()
				raise Exception("Global contact notification: " + str(e) +
								". Trace: " + trace)

	return jsonify({'message': email_response})


def send_booking_cancellation_email(email_data):
	email_response = []

	for recipient in email_data["recipient"]:
		sender = email_data["sender"]

		booking_details = {}
		booking_details["booking_ref_code"] = email_data["booking_ref_code"]
		booking_details["client"] = email_data["done_by"]
		booking_details["today"] = datetime.now().strftime("%B %Y")
		booking_details["copyright_year"] = datetime.now().strftime("%Y")

		sg = sendgrid.SendGridAPIClient(apikey=app.config["SENDGRID_API_KEY"])

		from_email = Email(sender)
		to_email = Email(recipient)
		subject = email_data["subject"]
		content = Content(
			"text/html",
			render_template("booking_cancellation.html", data=booking_details))
		mail = Mail(from_email, subject, to_email, content)

		try:
			response = sg.client.mail.send.post(request_body=mail.get())

			email_response.append(str(response))

			booking_activity = BookingActivity(
				booking_activity_public_id=str(uuid.uuid4()),
				booking_id=email_data["booking_id"],
				booking_activity_description=
				"Booking cancellation email sent to " + recipient + " from " +
				sender,
				session_id=None,
				created_at=datetime.now())

			db.session.add(booking_activity)

			db.session.commit()
			close(db)

		except Exception:
			pass


def send_booking_update_email(email_data):
	email_response = []

	for recipient in email_data["recipient"]:
		sender = email_data["sender"]

		booking_details = {}
		booking_details["booking_id"] = email_data["booking_id"]
		booking_details["booking_ref_code"] = email_data["booking_ref_code"]
		booking_details["client"] = email_data["done_by"]
		booking_details["today"] = datetime.now().strftime("%B %Y")
		booking_details["copyright_year"] = datetime.now().strftime("%Y")

		sg = sendgrid.SendGridAPIClient(apikey=app.config["SENDGRID_API_KEY"])

		from_email = Email(sender)
		to_email = Email(recipient)
		subject = email_data["subject"]
		content = Content(
			"text/html",
			render_template("booking_update.html", data=booking_details))
		mail = Mail(from_email, subject, to_email, content)

		try:
			response = sg.client.mail.send.post(request_body=mail.get())

			email_response.append(str(response))

			booking_activity = BookingActivity(
				booking_activity_public_id=str(uuid.uuid4()),
				booking_id=email_data["booking_id"],
				booking_activity_description="Booking update email sent to " +
				recipient + " from " + sender,
				session_id=None,
				created_at=datetime.now())

			db.session.add(booking_activity)

			db.session.commit()
			close(db)

		except Exception:
			pass


#######################
#### Booking Types ####
#######################
@app.route("/bookings/back/types/view")
def view_all_back_booking_types():
	if db.session.query(BookingType)\
	 .filter(BookingType.deletion_marker==None)\
	 .filter(BookingType.booking_type_public_id == "7769748C")\
	 .count() == 0:
		BookingTypeSeed.seed_default_booking_types_methods()

	if db.session.query(BookingType)\
	   .filter(BookingType.deletion_marker==None)\
	   .count() == 0:
		output = []
		output.append("There are currently no booking in the system.")
		return jsonify({"message": output}), 200

	return_booking_types = db.session.query(BookingType)\
	   .filter(BookingType.deletion_marker == None)\
	   .filter(BookingType.booking_type_back == 1)\
	   .all()

	output = []

	for single in return_booking_types:
		return_data = {}
		return_data["booking_type_public_id"] = single.booking_type_public_id
		return_data["booking_type_name"] = single.booking_type_name
		return_data[
			"booking_type_description"] = single.booking_type_description
		return_data["session_id"] = single.session_id
		return_data["created_at"] = single.created_at
		return_data["updated_at"] = single.updated_at

		output.append(return_data)

	return jsonify({"data": output}), 200


@app.route("/bookings/public/types/view")
def view_all_public_booking_types():
	if db.session.query(BookingType)\
	 .filter(BookingType.deletion_marker==None)\
	 .filter(BookingType.booking_type_public_id == "7769748C")\
	 .count() == 0:
		BookingTypeSeed.seed_default_booking_types_methods()

	if db.session.query(BookingType)\
	   .filter(BookingType.deletion_marker==None)\
	   .count() == 0:
		output = []
		output.append("There are currently no booking in the system.")
		return jsonify({"message": output}), 200

	return_booking_types = db.session.query(BookingType)\
	   .filter(BookingType.deletion_marker == None)\
	   .filter(BookingType.booking_type_public == 1)\
	   .all()

	output = []

	for single in return_booking_types:
		return_data = {}
		return_data["booking_type_public_id"] = single.booking_type_public_id
		return_data["booking_type_name"] = single.booking_type_name
		return_data[
			"booking_type_description"] = single.booking_type_description
		return_data["session_id"] = single.session_id
		return_data["created_at"] = single.created_at
		return_data["updated_at"] = single.updated_at

		output.append(return_data)

	return jsonify({"data": output}), 200


#########################
#### Member Bookings ####
#########################
@app.route("/bookings/member/view/<member_id>")
def view_single_member_bookings(member_id):
	get_member_bookings = db.session.query(Member.booking_id)\
	  .filter(Member.member_id == member_id)\
	  .all()

	return_bookings = db.session.query(Booking)\
	 .filter(Booking.booking_public_id.in_(get_member_bookings))\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	if not return_bookings:
		output = []
		output.append("There are currently no bookings in the system.")
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		try:
			return_user = requests.post(get_user_from_aumra,\
			 json = {"users_ids": id_array})
		except (requests.exceptions.ConnectionError,
				requests.exceptions.Timeout,
				requests.exceptions.ConnectTimeout) as connection_error:
			pass

		current_year = datetime.now().year
		counter = 0
		for single in return_bookings:

			visit_date = single.booking_check_in_date
			visit_year = visit_date.now().year
			if current_year == visit_year:
				counter += 1
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.b_type.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code

			booking_info = {}
			bookingTotal(booking_info, single.booking_public_id)

			return_data["guests"] = booking_info["guests"]
			return_data["guest_total"] = booking_info["guest_total"]
			return_data["vehicles"] = booking_info["vehicles"]
			return_data["vehicle_total"] = booking_info["vehicle_total"]
			return_data["accommodations"] = booking_info["facility_bookings"]
			return_data["activities"] = booking_info["inventory_bookings"]
			return_data["booking_currency"] = booking_info[
				"booking_currency_name"]
			return_data["booking_total"] = booking_info["total_cost"]

			check_to_invoice = db.session.query(Invoice)\
			  .filter(Invoice.deletion_marker == None)\
			  .filter(Invoice.booking_id == single.booking_public_id)\
			  .first()

			if check_to_invoice:
				if single.deletion_marker == 1:
					return_data["booking_status"] = "Cancelled"
					return_data[
						"booking_color"] = "background-color: {}; color: #fff".format(
							app.config["CANCELLED"])
				else:
					return_data["booking_status"] = "To Invoice"
					return_data[
						"booking_color"] = "background-color: {}; color: #fff".format(
							app.config["TO_INVOICE"])

			else:
				if single.checked_out == 1:
					return_data["booking_status"] = "Checked Out"
					return_data[
						"booking_color"] = "background-color: {}; color: #fff".format(
							app.config["CHECKED_OUT"])
				elif single.checked_in == 1:
					return_data["booking_status"] = "Checked In"
					return_data[
						"booking_color"] = "background-color:{}; color: #fff".format(
							app.config["CHECKED_IN"])
				elif single.deletion_marker == 1:
					return_data["booking_status"] = "Cancelled"
					return_data[
						"booking_color"] = "background-color: {}; color: #fff".format(
							app.config["CANCELLED"])
				else:
					if single.b_status.booking_status_name == "Unconfirmed":
						return_data[
							"booking_color"] = "background-color: {}; color: #fff".format(
								app.config["UNCONFIRMED"])
					elif single.b_status.booking_status_name == "Confirmed":
						return_data[
							"booking_color"] = "background-color: {}; color: #fff".format(
								app.config["CONFIRMED"])
					elif single.b_status.booking_status_name == "No-Show":
						return_data[
							"booking_color"] = "background-color: {}; color: #fff".format(
								app.config["NO_SHOW"])
					elif single.b_status.booking_status_name == "Abandoned":
						return_data[
							"booking_color"] = "background-color: {}; color: #fff".format(
								app.config["ABANDONED"])
					elif single.b_status.booking_status_name == "Updated":
						return_data[
							"booking_color"] = "background-color: {}; color: #fff".format(
								app.config["UPDATED"])
					elif single.b_status.booking_status_name == "Deposit":
						return_data[
							"booking_color"] = "background-color: {}; color: #fff".format(
								app.config["DEPOSIT"])
					elif single.b_status.booking_status_name == "Complimentary":
						return_data[
							"booking_color"] = "background-color: {}; color: #fff".format(
								app.config["COMPLIMENTARY"])
					else:
						return_data[
							"booking_color"] = "background-color: #fff; color: #000000"
					return_data[
						"booking_status"] = single.b_status.booking_status_name
			return_data["booking_status_id"] = single.status

			if single.session_id:
				try:
					for user in return_user.json()["data"]:
						if user["public_id"] == single.session_id:
							return_data["session_user"] = user["full_name"]
							return_data["session_id"] = single.session_id

				except (IndexError, KeyError) as user_error:
					return_data["session_user"] = "N/A"
					return_data["session_id"] = single.session_id

				except (AttributeError,
						UnboundLocalError) as network_related_errors:
					return_data["session_user"] = "Network Error"
					return_data["session_id"] = single.session_id
			else:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			return_data["created_at"] = single.created_at
			return_data["updated_at"] = single.updated_at
			return_data["visit_number"] = counter
			output.append(return_data)

		return jsonify({"data": output}), 200


##################
#### Bookings ####
##################
@app.route("/bookings/new", methods=["POST"])
# # @bookings_logger.logWrapper()
def add_new_booking():
	if db.session.query(BookingStatus)\
	 .filter(BookingStatus.deletion_marker==None)\
	 .filter(BookingStatus.booking_status_public_id == "3b5376e0-a4dc-476e-aebc-6280b44b756a")\
	 .count() == 0:
		BookingStatusSeed.seed_default_booking_status()

	if db.session.query(GuestType)\
	 .filter(GuestType.deletion_marker==None)\
	 .filter(GuestType.booking_guest_type_public_id == "2df20a96")\
	 .count() == 0:
		BookingGuestTypesSeed.seed_default_booking_guest_types_methods()

	today = datetime.now().strftime("%Y-%m-%d")

	# Field validation
	validation_list = [{
		"field": "type",
		"alias": "Booking type"
	}, {
		"field": "check_in",
		"alias": "Check-in date"
	}, {
		"field": "check_out",
		"alias": "Check-out date"
	}, {
		"field": "currency"
	}]

	messages = fieldValidation(request.json, validation_list)

	try:
		booking_type = "7769748C"

		try:
			member_entry_discount = float(request.json["entry_discount"])
		except ValueError:
			member_entry_discount = 0

		if request.json["member"]["corporate"]:
			first_name = request.json["member"]["company_name"].title()
			last_name = request.json["member"]["memberID"]
			email = request.json["member"]["email"].lower()
			phone = request.json["member"]["phone_number"]

			member_details_list = [{
				"field": "company_name",
				"alias": "Corporate member company name"
			}, {
				"field": "contact_person_name",
				"alias": "Corporate member contact person"
			}, {
				"field": "email",
				"alias": "Corporate member email address"
			}, {
				"field": "phone_number",
				"alias": "Corporate member phone number"
			}]
		else:
			first_name = request.json["member"]["first_name"].title()
			last_name = request.json["member"]["surname"].title()
			email = request.json["member"]["email"].lower()
			phone = request.json["member"]["tel_number"]

			member_details_list = [{
				"field": "first_name",
				"alias": "Member first name"
			}, {
				"field": "surname",
				"alias": "Member last name"
			}, {
				"field": "email",
				"alias": "Member email address"
			}, {
				"field": "tel_number",
				"alias": "Member phone number"
			}]

		messages = messages + fieldValidation(request.json["member"],
											  member_details_list)

	except Exception:
		first_name = request.json["first_name"].title()
		last_name = request.json["last_name"].title()
		email = request.json["email"].lower()
		phone = request.json["phone"]

		booking_type = request.json["type"]
		member_entry_discount = 0

		details_list = [{
			"field": "first_name",
			"alias": "First name"
		}, {
			"field": "last_name",
			"alias": "Last name"
		}, {
			"field": "email",
			"alias": "Email address"
		}, {
			"field": "phone",
			"alias": "Phone number"
		}]

		messages = messages + fieldValidation(request.json, details_list)

	if messages:
		return jsonify({"messages": messages}), 422

	seven_days_ago = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")

	# Date validation change
	# if request.json["check_in"] < today:
	# 	message = []
	# 	message.append("The booking check-in date cannot be in the past.")
	# 	return jsonify({"message": message}), 422
	# if request.json["check_out"] < today:
	# 	message = []
	# 	message.append("The booking check-out date cannot be in the past.")
	# 	return jsonify({"message": message}), 422

	if request.json["check_out"] < request.json["check_in"]:
		message = []
		message.append(
			"The check-out date cannot come before the check-in date.")
		return jsonify({"message": message}), 422

	try:
		promo_code_json = request.json["promo_code"]

	except Exception:
		promo_code_json = None

	## TODO: Fully integrate
	if promo_code_json:
		try:
			post_data = {
				"promo_code": promo_code_json,
				"check_in_date": request.json["check_in"],
				"check_out_date": request.json["check_out"]
			}

			check_promo_validity = requests.post(promo_code_search,
												 json=post_data)

			if check_promo_validity.status_code != 200:
				return jsonify(
					{"message": check_promo_validity.json()["message"]}), 422

			elif check_promo_validity.status_code == 200:
				promo_code_data = check_promo_validity.json()["data"][0]
				promo_code_public_id = check_promo_validity.json(
				)["data"][0]["public_id"]

		except Exception:
			message = []
			message.append(
				"There was an issue getting the promo code details. Please try again or leave the promo code field blank."
			)
			return jsonify({"message": message}), 422

	else:
		promo_code_data = None

	promo_discount = None
	promo_code = None
	promo_code_public_id = None

	guest_sum = []

	for each_guest in request.json["guests"]:
		try:
			guest_numbers = int(each_guest["payment_guests"])
		except Exception:
			guest_numbers = 0
		guest_sum.append(guest_numbers)

	phone_validation = validatePhoneNumber(phone)

	if phone_validation[0]:
		phone = phone_validation[1]

	else:
		message = []
		message.append(phone_validation[1])
		return jsonify({"message": message}), 422

	valid_email = validateEmail(email)

	if not valid_email:
		message = []
		message.append("The email address provided is invalid.")
		return jsonify({"message": message}), 422
	try:
		check_booking_ban(email, phone)
	except Exception as e:
		trace = traceback.format_exc()
		return jsonify({"message": str(e), "trace": trace}), 422
	# Generating date from string using a simple, custom function
	check_in_date = GenerateDateFromString.generateDate(
		request.json["check_in"])
	check_out_date = GenerateDateFromString.generateDate(
		request.json["check_out"])

	# Getting date difference using a simple, custom function
	temp_date_diff = DateOperations.returnDateDifferenceInDays(
		check_out_date, check_in_date)

	if temp_date_diff == 0:
		date_diff = 1
	elif temp_date_diff > 0:
		date_diff = temp_date_diff
	booking_id = str(uuid.uuid4())
	gatepass_id = str(uuid.uuid4())
	booking_ref = str(uuid.uuid4())[:10]

	if booking_type == "GB601X10":
		status = get_booking_status_id("Abandoned")
	else:
		status = get_booking_status_id("Unconfirmed")

	try:
		session_id = request.json["session_id"]
	except Exception:
		session_id = None

	get_booking_exchange_rate = requests.get(
		get_buy_sell_rate.format(request.json["currency_id"]))
	booking_buying_rate = get_booking_exchange_rate.json(
	)["data"][0]["currency_buy_amount"]
	booking_selling_rate = get_booking_exchange_rate.json(
	)["data"][0]["currency_sell_amount"]

	booking = Booking(booking_public_id=booking_id,
					  booking_type=booking_type,
					  booking_check_in_date=request.json["check_in"],
					  booking_check_out_date=request.json["check_out"],
					  booking_done_by=first_name + " " + last_name,
					  booking_ref_code=booking_ref,
					  status=status,
					  currency=request.json["currency_id"],
					  currency_buying_rate_at_time=booking_buying_rate,
					  currency_selling_rate_at_time=booking_selling_rate,
					  session_id=session_id,
					  created_at=datetime.now(),
					  updated_at=datetime.now())

	db.session.add(booking)

	booking_activity = BookingActivity(
		booking_activity_public_id=str(uuid.uuid4()),
		booking_id=booking_id,
		booking_activity_description="Booking created",
		session_id=session_id,
		created_at=datetime.now())

	db.session.add(booking_activity)

	## Facility booking handler
	facility_email_data = []

	booking_info = {}
	booking_info["booking_id"] = booking_id
	booking_info["booking_ref"] = booking_ref
	booking_info["first_name"] = first_name
	booking_info["last_name"] = last_name

	try:
		facilityBooking(request.json,
						booking_info,
						facility_email_data,
						currency_id=True,
						promo_code_details=promo_code_data)
	except Exception as e:
		trace = traceback.format_exc()
		return jsonify({"message": str(e), "trace": trace}), 422

	## Activity booking handler
	inventory_email_data = []

	try:
		inventoryBooking(request.json,
						 booking_info,
						 inventory_email_data,
						 currency_id=True,
						 promo_code_details=promo_code_data)
	except Exception as e:
		trace = traceback.format_exc()
		return jsonify({"message": str(e), "trace": trace}), 422

	try:
		for gatepass_guest in request.json["guests"]:
			get_guest_type = db.session.query(Mandatory)\
			   .filter(Mandatory.deletion_marker == None)\
			   .filter(Mandatory.payment_public_id == gatepass_guest["payment_public_id"])\
			   .first()

			try:
				guest_count = int(gatepass_guest["payment_guests"])
			except Exception:
				guest_count = 0

			guest = BookingGuest(booking_guest_public_id=str(uuid.uuid4()),
								 booking_id=booking_id,
								 guest_type=get_booking_guest_type_id(
									 get_guest_type.payment_person.lower()),
								 guest_count=guest_count)

			db.session.add(guest)

	except KeyError as guest_error:
		print("There was an error getting: " + str(guest_error))

	try:
		additional_note = request.json["additional_note"]
	except KeyError as guest_key_error:
		additional_note = None

	try:
		address = request.json["address"]
	except KeyError as address_key_error:
		address = None

	try:
		address = request.json["member"]["postal_address"] + " - " + str(
			request.json["member"]["postal_code"])
	except KeyError as member_address_key_error:
		address = None

	try:
		country_code = request.json["code"]
	except KeyError as country_code_key_error:
		country_code = None

	try:
		country = request.json["country_details"]['name']
	except KeyError as country_key_error:
		country = None
	try:
		city = request.json["city"]
	except KeyError as city_key_error:
		city = None
	try:
		entry_mode = request.json["entry_mode"]
	except KeyError as entry_mode_error:
		entry_mode = None
	try:
		entry_point = request.json["entry_point"]
	except KeyError as entry_point_error:
		entry_point = None

	try:
		mode_registration = request.json["mode_registration"]
	except KeyError as mode_registration_error:
		mode_registration = None
	try:
		kra_pin_number = request.json["kra_pin_number"]
	except KeyError as mode_registration_error:
		kra_pin_number = None
	# if len(additional_note) >= 255:
	# 	additional_note = additional_note[:254]
	# else:
	# 	additional_note = additional_note

	detail = Detail(booking_details_public_id=str(uuid.uuid4()),
					booking_id=booking_id,
					first_name=first_name,
					last_name=last_name,
					email_address=email,
					phone_number=phone,
					country=country,
					country_code=country_code,
					city=city,
					address=address,
					additional_note=additional_note,
					entry_mode=entry_mode,
					entry_point=entry_point,
					mode_registration=mode_registration,
					kra_pin_number=kra_pin_number,
					session_id=session_id,
					created_at=datetime.now(),
					updated_at=datetime.now())

	db.session.add(detail)

	try:
		note = request.json["note"]
	except Exception:
		note = None

	if note:
		new_note = Note(booking_notes_public_id=str(uuid.uuid4()),
						booking_id=booking_id,
						note=note,
						session_id=session_id,
						created_at=datetime.now())

		db.session.add(new_note)

	try:
		## Handling public bookings where destination is sent as ''
		if request.json["destination"]:
			destination = request.json["destination"]
		else:
			destination = None
	except (KeyError) as destination_error:
		destination = None

	gatepass = Gatepass(gatepass_public_id=gatepass_id,
						gatepass_date=today,
						gatepass_done_by=first_name + " " + last_name,
						destination=destination,
						gatepass_phone_number=phone,
						gatepass_ref_code=str(uuid.uuid4())[:10],
						booking_id=booking_id,
						booking=1,
						start_date=request.json["check_in"],
						end_date=request.json["check_out"],
						gatepass_currency=request.json["currency_id"],
						gatepass_payment_status=1,
						created_at=datetime.now(),
						updated_at=datetime.now())

	db.session.add(gatepass)

	guest_info_data = []

	try:
		for each_gatepass_guest in request.json["guests"]:
			get_gatepass_fee = db.session.query(MandatoryPaymentPrices)\
			  .join(Mandatory, MandatoryPaymentPrices.payment_category == Mandatory.payment_public_id)\
			  .add_columns(MandatoryPaymentPrices.price_public_id, MandatoryPaymentPrices.payment_schedule, MandatoryPaymentPrices.payment_category,\
			   MandatoryPaymentPrices.payment_currency, MandatoryPaymentPrices.payment_price,\
			   Mandatory.payment_person)\
			  .filter(MandatoryPaymentPrices.deletion_marker == None)\
			  .filter(MandatoryPaymentPrices.payment_schedule == each_gatepass_guest["payment_schedule"])\
			  .filter(MandatoryPaymentPrices.payment_category == each_gatepass_guest["payment_public_id"])\
			  .first()

			try:
				gatepass = get_gatepass_fee.payment_price
			except (ValueError, TypeError) as no_value:
				gatepass = 0

			gatepass_amount = currencyHandler(
				request.json["currency_id"], get_gatepass_fee.payment_currency,
				gatepass)

			get_ex_rate = requests.get(
				get_buy_sell_rate.format(get_gatepass_fee.payment_currency))

			try:
				buying = get_ex_rate.json()["data"][0]["currency_buy_amount"]

			except Exception:
				buying = 1

			## This is the important section for promo codes
			if promo_code_data:
				if promo_code_data["conservancy_fee"]:
					if each_gatepass_guest[
							"payment_public_id"] in promo_code_data[
								"conservancy_fee_array"]:
						# if
						person_discount = float(
							promo_code_data["percentage_off"])
						person_discount_reason = promo_code_data["code"]
					else:
						person_discount = 0
						person_discount_reason = None
				else:
					person_discount = 0
					person_discount_reason = None

			else:
				if member_entry_discount:
					person_discount = member_entry_discount
				else:
					try:
						person_discount = float(
							each_gatepass_guest["payment_person_discount"])
					except Exception:
						person_discount = 0

				if promo_discount:
					person_discount_reason = promo_code
				else:
					try:
						person_discount_reason = each_gatepass_guest["reason"]
					except Exception:
						person_discount_reason = None

			try:
				guests = int(each_gatepass_guest["payment_guests"])
			except Exception:
				guests = 0

			gatepass_guest = GatepassGuest(
				gatepass_guest_public_id=str(uuid.uuid4()),
				gatepass_id=gatepass_id,
				gatepass_guest_type=each_gatepass_guest["payment_public_id"],
				gatepass_guest_count=guests,
				gatepass_discount_rate=person_discount,
				gatepass_discount_reason=person_discount_reason,
				gatepass_cost_per_pp=round(gatepass_amount, 2),
				gatepass_payment_schedule=each_gatepass_guest[
					"payment_schedule"],
				gatepass_no_of_nights=date_diff,
				gatepass_currency=request.json["currency_id"],
				gatepass_guest_cost_at_time=round(gatepass),
				gatepass_guest_currency_at_time=get_gatepass_fee.
				payment_currency,
				gatepass_guest_rate_at_time=buying,
				created_at=datetime.now(),
				updated_at=datetime.now())

			db.session.add(gatepass_guest)

			guest_info = {}

			try:
				guest_numbers = int(each_gatepass_guest["payment_guests"])
			except Exception:
				guest_numbers = 0

			if guest_numbers != 0:
				guest_info["guest_category"] = get_gatepass_fee.payment_person
				guest_info["guest_number"] = each_gatepass_guest[
					"payment_guests"]

				guest_info_data.append(guest_info)

	except KeyError as gatepass_guest_error:
		print("There was an error getting: " + str(gatepass_guest_error))

	gatepass_detail = GatepassDetail(gatepass_details_public_id=str(
		uuid.uuid4()),
									 gatepass_id=gatepass_id,
									 first_name=first_name,
									 last_name=last_name,
									 email_address=email,
									 phone_number=phone,
									 created_at=datetime.now(),
									 updated_at=datetime.now())

	db.session.add(gatepass_detail)

	vehicle_sum = []
	vehicle_info_data = []

	try:
		for each_vehicle in request.json["vehicles"]:
			get_cost = db.session.query(Vehicle)\
			   .filter(Vehicle.deletion_marker == None)\
			   .filter(Vehicle.vehicle_charge_public_id == each_vehicle["vehicle_charge_public_id"])\
			   .first()

			try:
				vehicle = get_cost.vehicle_charge_category_cost
			except (ValueError, TypeError) as no_value:
				vehicle = 0

			vehicle_fee = currencyHandler(
				request.json["currency_id"],
				get_cost.vehicle_charge_cost_currency, vehicle)

			get_ex_rate = requests.get(
				get_buy_sell_rate.format(
					get_cost.vehicle_charge_cost_currency))

			try:
				buying = get_ex_rate.json()["data"][0]["currency_buy_amount"]

			except Exception:
				buying = 1

			if promo_discount:
				vehicle_discount = promo_discount
			else:
				try:
					vehicle_discount = float(each_vehicle["discount"])
				except Exception:
					vehicle_discount = 0

			if promo_code:
				vehicle_discount_reason = promo_code
			else:
				try:
					vehicle_discount_reason = each_vehicle["reason"]
				except Exception:
					vehicle_discount_reason = None

			try:
				vehicles = int(each_vehicle["vehicles"])
			except Exception:
				vehicles = 0

			gatepass_vehicle = GatepassVehicle(
				gatepass_vehicle_public_id=str(uuid.uuid4()),
				gatepass_id=gatepass_id,
				gatepass_vehicle_type=each_vehicle["vehicle_charge_public_id"],
				gatepass_vehicle_count=vehicles,
				gatepass_cost_per_vehicle=round(vehicle_fee),
				gatepass_vehicle_currency=request.json["currency_id"],
				gatepass_vehicle_no_of_nights=date_diff,
				gatepass_vehicle_discount_rate=vehicle_discount,
				gatepass_vehicle_discount_reason=vehicle_discount_reason,
				gatepass_vehicle_cost_at_time=round(vehicle),
				gatepass_vehicle_currency_at_time=get_cost.
				vehicle_charge_cost_currency,
				gatepass_vehicle_rate_at_time=buying,
				created_at=datetime.now(),
				updated_at=datetime.now())

			vehicle_info = {}
			try:
				vehicle_numbers = int(each_vehicle["vehicles"])
			except Exception:
				vehicle_numbers = 0

			if vehicle_numbers != 0:
				vehicle_info[
					"vehicle_category"] = get_cost.vehicle_charge_category
				vehicle_info["vehicle_number"] = each_vehicle["vehicles"]

				vehicle_info_data.append(vehicle_info)

				vehicle_sum.append(int(each_vehicle["vehicles"]))

			db.session.add(gatepass_vehicle)

	except KeyError as vehicle_key_error:
		print("There was an error getting the following key: " +
			  str(vehicle_key_error))

	try:
		member = request.json["member"]

		if member["corporate"]:
			num_of_people = member["passengers"]
			num_of_children = 0
			num_of_vehicles = member["vehicles"]
		else:
			num_of_people = member["num_of_persons"]
			num_of_children = member["num_of_children"]
			num_of_vehicles = member["num_of_vehicles"]

		member_booking = Member(member_booking_public_id=str(uuid.uuid4()),
								booking_id=booking_id,
								member_id=member["memberID"],
								num_of_people=num_of_people,
								num_of_children=num_of_children,
								num_of_vehicles=num_of_vehicles,
								session_id=request.json["session_id"])

		db.session.add(member_booking)

	except Exception:
		pass

	try:
		if request.json["proof_of_residency"]:
			newResidencyProof(request.json["proof_of_residency"], booking_id,
							  session_id)

	except Exception as e:
		pass

	# try:
	# 	json_data = {
	# 		"first_name": first_name,
	# 		"last_name": last_name,
	# 		"email": email

	# 	}
	# 	try:
	# 		booking_total_dict = {}
	# 		booking_user_account_details ={}
	# 		try:
	# 			add_booking_user(json_data,booking_user_account_details)
	# 		except Exception as e:
	# 			print("e5")
	# 			print(e)
	# 			# trace = traceback.format_exc()
	# 			# return jsonify({"message": str(e), "trace": trace}), 422
	# 		account_details_id = booking_user_account_details["user_account_id"]
	# 		viewBookingsTotal(booking_total_dict, booking_id)

	# 		print("booking_total_dict")
	# 		print(booking_total_dict)
	# 		if account_details_id:

	# 			booking_account = BookingAccount(
	# 			booking_account_public_id=str(uuid.uuid4()),
	# 			booking_id=booking_id,
	# 			booking_total=booking_total_dict["total_cost"],
	# 			currency=request.json["currency_id"],
	# 			currency_buying_rate_at_time=booking_buying_rate,
	# 			currency_selling_rate_at_time=booking_selling_rate,
	# 			public_user_account_id = account_details_id,
	# 			session_id=request.json["session_id"],
	# 			created_at=datetime.now())

	# 			db.session.add(booking_account)
	# 		else:
	# 			# return jsonify({"message": "An error occurred.Please contact the Admin"}), 422
	# 			print("e3")

	# 	except Exception as e:
	# 		print("e4")
	# 		print(e)
	# 		# return jsonify({"message": str(e)}), 422

	# except Exception as e:
	# 	print("e4")
	# 	print(e)
	# 	# trace = traceback.format_exc()
	# 	# return jsonify({"message": str(e), "trace": trace}), 422



	try:
		if request.json["donation"]:
			get_exchange_rate = requests.get(
				get_buy_sell_rate.format(request.json["donation"]["currency"]))
			buying_rate = get_exchange_rate.json(
			)["data"][0]["currency_buy_amount"]
			selling_rate = get_exchange_rate.json(
			)["data"][0]["currency_sell_amount"]

			json_data = {
				"first_name": first_name,
				"sur_name": last_name,
				"email": email,
				"phone_number": phone,
				"frequency": "n4383h334",
				"amount": request.json["donation"]["amount"],
				"payment_method": "enjkr4k4",
				"payment_option": request.json["donation"]["donation_to"],
				"anonymity": "74a27ee4",
				"gender": "Female",
				"title": "Ms.",
				"city": city,
				"dob": "1900-01-01",
				"country": country,
				"currency": request.json["donation"]["currency"],
				"booking_public_id": booking_id,
				"booking_ref_code": booking_ref
			}

			donation_request = requests.post(post_donation, json=json_data)

			donation = Donation(
				donation_public_id=donation_request.json()
				["donation_ref_code"],
				booking_id=booking_id,
				donation_currency=request.json["donation"]["currency"],
				donation_cause=request.json["donation"]["donation_to"],
				donation_amount=request.json["donation"]["amount"],
				currency_buying_amount=buying_rate,
				currency_selling_amount=selling_rate,
				created_at=datetime.now())

			db.session.add(donation)

	except Exception:
		pass

	try:
		db.session.commit()
		close(db)

		email_array = [email]

		email_data = {}
		# email_data["recipient"] = email
		email_data["recipient"] = email_array
		email_data["sender"] = "reservations@olpejetaconservancy.org"
		email_data["subject"] = "Booking Notification (#" + booking_ref + ")"

		email_data["today"] = datetime.now().strftime("%B %Y")
		email_data["booking_ref_code"] = booking_ref
		email_data["first_name"] = first_name
		email_data["last_name"] = last_name
		email_data["check_in_date"] = check_in_date.strftime("%A, %d %b %Y")
		email_data["check_out_date"] = check_out_date.strftime("%A, %d %b %Y")
		email_data["num_of_guests"] = sum(guest_sum)
		email_data["num_of_vehicles"] = sum(vehicle_sum)
		email_data["client"] = first_name + " " + last_name
		email_data["booking_id"] = booking_id
		email_data["facility_info"] = facility_email_data
		email_data["inventory_info"] = inventory_email_data
		email_data["guest_info"] = guest_info_data
		email_data["vehicle_info"] = vehicle_info_data

		## TODO: Fix
		try:
			send_booking_email(email_data)
		except Exception as e:
			# return jsonify({"message": "Unable to send email", "error": str(e)}), 422
			pass

		if promo_code_data:
			requests.post(use_promo_code.format(promo_code_data["public_id"]),
						  json={
							  "session_id": str(session_id),
							  "number": "1",
							  "booking": booking_id
						  })

		output = []
		output.append(
			"The booking has been made. Please proceed to make your payment.")

		return_data = {}
		return_data["booking_public_id"] = booking_id
		return_data["email"] = email
		return jsonify({"message": output, "data": return_data}), 201

	except Exception as e:
		print(e)
		db.session.rollback()
		close(db)

		output = []
		output.append(
			"There was an error while creating the booking. Please try again later."
		)
		return jsonify({"message": output, "error": str(e)}), 422


@app.route("/bookings/view")
# @bookings_logger.logWrapper()
def view_all_bookings():
    try:
        page = int(request.args["page"])
    except Exception:
        page = 1

    try:
        items = int(request.args["items"])
    except Exception:
        items = 10000

    if page == 0:
        return_bookings = db.session.query(Booking, Destination.gatepass_destination_name, Detail.country)\
            .join(Gatepass, Gatepass.booking_id == Booking.booking_public_id)\
            .join(Destination, Gatepass.destination == Destination.gatepass_destination_public_id)\
            .join(Detail, Detail.booking_id == Booking.booking_public_id)\
            .order_by(Booking.booking_id.desc())\
            .options(FromCache(db_cache))\
            .all()
    else:
        return_bookings = db.session.query(Booking)\
            .order_by(Booking.booking_id.desc())\
            .options(FromCache(db_cache))\
            .paginate(page, items, False)\
            .items

    if not return_bookings:
        output = []
        output.append("There are currently no bookings in the system.")
        return jsonify({"message": output}), 200
    else:
        data = []
        id_array = []

        # Handle different return types based on pagination
        if page == 0:
            # For non-paginated results, extract objects from tuples
            booking_objects = [booking_tuple[0] for booking_tuple in return_bookings]
            destination_names = [booking_tuple[1] for booking_tuple in return_bookings]
            countries = [booking_tuple[2] for booking_tuple in return_bookings]
        else:
            # For paginated results, we only have Booking objects
            booking_objects = return_bookings
            destination_names = [None] * len(return_bookings)
            countries = [None] * len(return_bookings)

        for each_id in booking_objects:
            id_array.append(each_id.session_id)

        request_session = requests.Session()

        try:
            return_user = request_session.post(get_user_from_aumra,\
                json = {"users_ids": id_array})
        except (requests.exceptions.ConnectionError,
                requests.exceptions.Timeout,
                requests.exceptions.ConnectTimeout) as connection_error:
            pass

        for i, single in enumerate(booking_objects):
            return_data = {}
            return_data["booking_public_id"] = single.booking_public_id
            return_data["booking_type"] = single.b_type.booking_type_name
            return_data["booking_type_id"] = single.booking_type
            return_data["booking_check_in_date"] = single.booking_check_in_date
            return_data["booking_check_out_date"] = single.booking_check_out_date
            return_data["booking_ref_code"] = single.booking_ref_code

            return_data["facility_bookings"] = single.return_facilities(
                request_session)
            return_data["inventory_bookings"] = single.return_inventory(
                request_session)

            check_school_booking = db.session.query(SchoolBooking)\
                .join(School, SchoolBooking.school_id == School.school_public_id)\
                .add_columns(School.school_name)\
                .filter(SchoolBooking.booking_id == single.booking_public_id)\
                .first()

            check_org_booking = db.session.query(Group)\
                .filter(Group.booking_id == single.booking_public_id)\
                .first()

            try:
                if check_school_booking:
                    return_data["booking_done_by"] = check_school_booking.school_name
                elif check_org_booking:
                    return_data["booking_done_by"] = check_org_booking.organisation_name
                else:
                    return_data["booking_done_by"] = single.booking_done_by
            except Exception:
                return_data["booking_done_by"] = single.booking_done_by

            try:
                get_booking_details = db.session.query(Detail)\
                    .filter(Detail.booking_id == single.booking_public_id)\
                    .filter(Detail.status != get_booking_status_id("Updated"))\
                    .first()

                return_data["email_address"] = get_booking_details.email_address
                return_data["phone_number"] = get_booking_details.phone_number
            except AttributeError:
                return_data["email_address"] = ""
                return_data["phone_number"] = ""

            return_data["booking_ticket"] = single.ticket

            booking_info = {}
            bookingTotal(booking_info, single.booking_public_id)

            ##TODO: Changed
            return_data["guests"] = booking_info["guests"]
            return_data["guest_total"] = booking_info["guest_total"]

            ##TODO: Added
            return_data["vehicles"] = booking_info["vehicles"]
            return_data["vehicle_total"] = booking_info["vehicle_total"]

            ##TODO: Added
            return_data["accommodations"] = booking_info["facility_bookings"]
            return_data["activities"] = booking_info["inventory_bookings"]

            return_data["booking_currency"] = booking_info["booking_currency_name"]
            return_data["booking_total"] = booking_info["total_cost"]

            ##TODO: Added
            return_data["vat"] = booking_info["tax_breakdown"]["vat"]
            return_data["catering_levy"] = booking_info["tax_breakdown"]["catering"]
            return_data["after_tax"] = booking_info["tax_breakdown"]["after_tax"]

            check_to_invoice = db.session.query(Invoice)\
                .filter(Invoice.deletion_marker == None)\
                .filter(Invoice.booking_id == single.booking_public_id)\
                .first()

            if check_to_invoice:
                if single.deletion_marker == 1:
                    return_data["booking_status"] = "Cancelled"
                    return_data["booking_color"] = "background-color: {}; color: #fff".format(
                        app.config["CANCELLED"])
                else:
                    return_data["booking_status"] = "To Invoice"
                    return_data["booking_color"] = "background-color: {}; color: #fff".format(
                        app.config["TO_INVOICE"])
            else:
                if single.checked_out == 1:
                    return_data["booking_status"] = "Checked Out"
                    return_data["booking_color"] = "background-color: {}; color: #fff".format(
                        app.config["CHECKED_OUT"])
                elif single.checked_in == 1:
                    return_data["booking_status"] = "Checked In"
                    return_data["booking_color"] = "background-color:{}; color: #fff".format(
                        app.config["CHECKED_IN"])
                elif single.deletion_marker == 1:
                    return_data["booking_status"] = "Cancelled"
                    return_data["booking_color"] = "background-color: {}; color: #fff".format(
                        app.config["CANCELLED"])
                else:
                    if single.b_status.booking_status_name == "Unconfirmed":
                        return_data["booking_color"] = "background-color: {}; color: #fff".format(
                            app.config["UNCONFIRMED"])
                    elif single.b_status.booking_status_name == "Confirmed":
                        return_data["booking_color"] = "background-color: {}; color: #fff".format(
                            app.config["CONFIRMED"])
                    elif single.b_status.booking_status_name == "No-Show":
                        return_data["booking_color"] = "background-color: {}; color: #fff".format(
                            app.config["NO_SHOW"])
                    elif single.b_status.booking_status_name == "Abandoned":
                        return_data["booking_color"] = "background-color: {}; color: #fff".format(
                            app.config["ABANDONED"])
                    elif single.b_status.booking_status_name == "Updated":
                        return_data["booking_color"] = "background-color: {}; color: #fff".format(
                            app.config["UPDATED"])
                    elif single.b_status.booking_status_name == "Deposit":
                        return_data["booking_color"] = "background-color: {}; color: #fff".format(
                            app.config["DEPOSIT"])
                    elif single.b_status.booking_status_name == "Complimentary":
                        return_data["booking_color"] = "background-color: {}; color: #fff".format(
                            app.config["COMPLIMENTARY"])
                    elif single.b_status.booking_status_name == "Postponed":
                        return_data["booking_color"] = "background-color: {}; color: #fff".format(
                            app.config["POSTPONED"])
                    else:
                        return_data["booking_color"] = "background-color: #fff; color: #000000"
                    return_data["booking_status"] = single.b_status.booking_status_name
            return_data["booking_status_id"] = single.status

            if single.session_id:
                if single.session_id == "guest":
                    return_data["session_user"] = "Public"
                    return_data["session_id"] = single.session_id
                else:
                    try:
                        for user in return_user.json()["data"]:
                            if user["public_id"] == single.session_id:
                                return_data["session_user"] = user["full_name"]
                                return_data["session_id"] = single.session_id
                    except (IndexError, KeyError) as user_error:
                        return_data["session_user"] = "N/A"
                        return_data["session_id"] = single.session_id
                    except (AttributeError, UnboundLocalError) as network_related_errors:
                        return_data["session_user"] = "Network Error"
                        return_data["session_id"] = single.session_id
            else:
                return_data["session_user"] = "N/A"
                return_data["session_id"] = single.session_id

            return_data["created_at"] = single.created_at
            return_data["updated_at"] = single.updated_at
            
            # Handle destination name
            if page == 0:
                return_data["destination"] = destination_names[i]
            else:
                # For paginated results, we need to query the destination separately
                destination = db.session.query(Destination.gatepass_destination_name)\
                    .join(Gatepass, Gatepass.destination == Destination.gatepass_destination_public_id)\
                    .filter(Gatepass.booking_id == single.booking_public_id)\
                    .first()
                return_data["destination"] = destination.gatepass_destination_name if destination else None
            
            # Handle country information
            if page == 0:
                return_data["country"] = countries[i]
            else:
                # For paginated results, query country separately
                country_detail = db.session.query(Detail.country)\
                    .filter(Detail.booking_id == single.booking_public_id)\
                    .first()
                return_data["country"] = country_detail.country if country_detail else None
            
            get_partner_booking = db.session.query(Partner)\
                .filter(Partner.deletion_marker == None)\
                .filter(Partner.booking_id == single.booking_public_id)\
                .options(FromCache(db_cache))\
                .first()
            
            if get_partner_booking:
                return_data["partner_booking_ref"] = get_partner_booking.partner_booking_ref

                partner_info = get_details_partner(
                    get_partner_booking.partner_id)
                try:
                    return_data["partner_type"] = partner_info["partner_type"][0]
                    return_data["partner_name"] = partner_info["name"]
                except Exception:
                    return_data["partner_type"] = None
                    return_data["partner_name"] = None
            else:
                return_data["partner_booking_ref"] = None
                return_data["partner_type"] = None
                return_data["partner_name"] = None

            if single.member_details:
                booking_details = single.member_details.first()

                if booking_details:
                    member_info = get_details_member(booking_details.member_id)
                    try:
                        return_data["member_name"] = member_info["full_name"]
                        return_data["membership_level"] = member_info["level"]
                    except Exception:
                        return_data["member_name"] = "Corporate"
                        return_data["membership_level"] = "Corporate"
                else:
                    return_data["member_name"] = None
                    return_data["membership_level"] = None
            else:
                return_data["member_name"] = None
                return_data["membership_level"] = None

            if single.payment_status == 1:
                return_data["booking_payment_status"] = "Paid"
            if single.payment_status == 2:
                return_data["booking_payment_status"] = "Incomplete Payment"
            if single.payment_status == 3:
                return_data["booking_payment_status"] = "Complimentary"
            if single.payment_status == 4:
                return_data["booking_payment_status"] = "To Invoice"
            if not single.payment_status:
                return_data["booking_payment_status"] = "Not Paid"

            get_credit_notes = db.session.query(CreditNote)\
                .filter(CreditNote.deletion_marker == None)\
                .filter(CreditNote.booking_id == single.booking_public_id)\
                .all()

            if get_credit_notes:
                return_data["credit_note_issued"] = True
            else:
                return_data["credit_note_issued"] = False

            data.append(return_data)

        return jsonify({"data": data}), 200

@app.route("/booking/cost/<booking_id>")
def get_single_booking_cost(booking_id):
	data = []
	return_data = {}

	try:
		bookingTotal(return_data, booking_id, batchfile=True)

		data.append(return_data)

		return jsonify({"data": data}), 200

	except Exception as e:
		trace = traceback.format_exc()
		return jsonify({"error": str(e), "trace": trace}), 422


@app.route("/booking/total-cost/<booking_id>")
def get_single_booking_total(booking_id):
	data = []
	return_data = {}
	try:
		viewBookingsTotal(return_data, booking_id)
		data.append(return_data)
		return jsonify({"data": return_data}), 200

	except Exception as e:
		trace = traceback.format_exc()
		return jsonify({"error": str(e), "trace": trace}), 422


@app.route("/bookings/view/<booking_id>")
# @bookings_logger.logWrapper()
def view_single_booking(booking_id):
	try:
		get_member_booking = db.session.query(Member)\
		 .filter(Member.deletion_marker == None)\
		 .filter(Member.booking_id == booking_id)\
		 .first()

		if get_member_booking:
			member_data = {}
			bookingTotal(member_data, booking_id)

			if member_data["total_cost"] == 0:
				get_booking = db.session.query(Booking)\
				   .filter(Booking.deletion_marker == None)\
				   .filter(Booking.payment_status == None)\
				   .filter(Booking.booking_public_id == booking_id)\
				   .first()

				if get_booking:
					get_booking.payment_status = 1

					db.session.commit()

	except Exception:
		get_member_booking = None
		# pass

	return_bookings = db.session.query(Booking)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.booking_ref_code, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.payment_status,\
	  Booking.currency, Booking.deletion_marker, Booking.currency_buying_rate_at_time,\
	  Booking.currency_selling_rate_at_time,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name,)\
	 .filter(Booking.booking_public_id == booking_id)\
	 .options(FromCache(db_cache))\
	 .all()

	if not return_bookings:
		message = []
		message.append(
			"The selected booking does not appear to exist in the system.")
		return jsonify({"message": message}), 200

	else:
		data = []
		id_array = []

		for single in return_bookings:
			return_data = {}

			## Basic booking details
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data[
				"actual_booking_check_in_date"] = single.actual_booking_check_in_date
			return_data[
				"actual_booking_check_out_date"] = single.actual_booking_check_out_date
			return_data[
				"check_in_date"] = single.booking_check_in_date.strftime(
					"%A, %d %b %Y")
			return_data[
				"check_out_date"] = single.booking_check_out_date.strftime(
					"%A, %d %b %Y")
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code
			return_data["created_at"] = single.created_at
			return_data["currency_buying_rate_at_time"] = round(
				float(single.currency_buying_rate_at_time), 3)
			return_data["currency_selling_rate_at_time"] = round(
				float(single.currency_selling_rate_at_time), 3)
			## Booking status
			if single.checked_out == 1:
				return_data["status"] = "Checked Out"
			elif single.checked_in == 1:
				return_data["status"] = "Checked In"
			elif single.deletion_marker == 1:
				return_data["status"] = "Cancelled"
			else:
				return_data["status"] = single.booking_status_name

			## Booking currency
			currency = requests.get(get_currency.format(single.currency))
			# currency = asyncRequests.launchGetRequest(
			# 	url=get_currency, request_id=single.currency)

			try:
				return_data["currency"] = currency.json(
				)["data"][0]["currency_name"]
			except Exception:
				return_data["currency"] = ""
			return_data["currency_id"] = single.currency

			get_gatepass = db.session.query(Gatepass)\
			 .filter(Gatepass.booking_id == single.booking_public_id)\
			 .filter(Gatepass.status != get_booking_status_id("Updated"))\
			 .first()
			
		if get_gatepass:
			get_gatepass_guests = db.session.query(GatepassGuest)\
				.filter(GatepassGuest.gatepass_id == get_gatepass.gatepass_public_id)\
				.filter(GatepassGuest.gatepass_guest_count > 0)\
				.first()

			if get_gatepass:
				## Booking destination
				try:
					return_data["destination_id"] = get_gatepass.destination
					return_data["destination"], = db.session.query(Destination.gatepass_destination_name)\
					 .filter(Destination.gatepass_destination_public_id == get_gatepass.destination)\
					 .options(FromCache(db_cache))\
					 .first()
					return_data["destination_set"] = True
				except TypeError:
					return_data["destination_id"] = None
					return_data["destination"] = None
					return_data["destination_set"] = False
			else:
				return_data["destination_id"] = None
				return_data["destination"] = None
				return_data["destination_set"] = False
			
			if get_gatepass_guests:
				try:
					return_data["gatepass_guest_count"] = get_gatepass_guests.gatepass_guest_count
					
				except TypeError:
					return_data["gatepass_guest_count"] = 0
			else:
				return_data["gatepass_guest_count"] = 0
            
			get_booking_details = db.session.query(Detail)\
			 .filter(Detail.booking_id == single.booking_public_id)\
			 .filter(Detail.status != get_booking_status_id("Updated"))\
			 .first()

			if get_booking_details:
				## Booking details such as a user's first name, last name etc
				detail_data = {}
				detail_data["first_name"] = get_booking_details.first_name
				detail_data["last_name"] = get_booking_details.last_name
				detail_data[
					"email_address"] = get_booking_details.email_address
				detail_data["phone_number"] = get_booking_details.phone_number
				detail_data["city"] = get_booking_details.city
				detail_data["country"] = get_booking_details.country
				detail_data[
					"additional_note"] = get_booking_details.additional_note
				entry_mode = get_booking_details.entry_mode
				if entry_mode:
					detail_data["entry_mode"] = True
					get_entry_mode = db.session.query(EntryMode)\
					   .filter(EntryMode.deletion_marker == None)\
					   .filter(EntryMode.entry_mode_public_id == get_booking_details.entry_mode)\
					   .first()
					try:
						detail_data[
							"entry_mode_name"] = get_entry_mode.entry_mode_name
						detail_data[
							"entry_mode_public_id"] = get_entry_mode.entry_mode_public_id
					except Exception as e:
						detail_data["entry_mode_name"] = ''
						detail_data["entry_mode_public_id"] = ''

					get_entry_point = db.session.query(Gate)\
					 .filter(Gate.deletion_marker == None)\
					 .filter(Gate.gate_public_id == get_booking_details.entry_point)\
					 .first()
					try:
						detail_data["gate_name"] = get_entry_point.gate_name
						detail_data[
							"gate_public_id"] = get_entry_point.gate_public_id
					except Exception as e:
						detail_data["gate_name"] = ''
						detail_data["gate_public_id"] = ''
					detail_data[
						"mode_registration"] = get_booking_details.mode_registration
				else:
					detail_data["entry_mode"] = False
				detail_data["kra_pin_number"] = get_booking_details.kra_pin_number
			else:
				detail_data = {}
				detail_data["first_name"] = ""
				detail_data["last_name"] = ""
				detail_data["email_address"] = ""
				detail_data["phone_number"] = ""
				detail_data["city"] = ""
				detail_data["country"] = ""
				detail_data["additional_note"] = ""
				detail_data["entry_mode_name"] = ''
				detail_data["entry_mode_public_id"] = ''
				detail_data["gate_name"] = ''
				detail_data["gate_public_id"] = ''
				detail_data["kra_pin_number"] = ''

			return_data["booking_details"] = detail_data

			## Appending the booking session ID to id_array
			id_array.append(single.session_id)

			get_logs = db.session.query(BookingActivity)\
			   .filter(BookingActivity.deletion_marker == None)\
			   .filter(BookingActivity.booking_id == single.booking_public_id)\
			   .order_by(BookingActivity.created_at.desc())\
			   .options(FromCache(db_cache))\
			   .all()

			if not get_logs:
				pass
			else:
				for one_activity in get_logs:
					if one_activity.session_id:
						id_array.append(one_activity.session_id)

			post_data = {"users_ids": id_array}
			# return_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)

			return_user = requests.post(get_user_from_aumra, json=post_data)

			logs = []

			if not get_logs:
				pass
			else:
				name = None
				for single_activity in get_logs:
					return_activity = {}
					return_activity[
						"booking_activity_public_id"] = single_activity.booking_activity_public_id
					return_activity["booking_id"] = single_activity.booking_id
					return_activity[
						"booking_activity_description"] = single_activity.booking_activity_description
					return_activity["session_id"] = single_activity.session_id
					return_activity["created_at"] = single_activity.created_at

					if single_activity.session_id:
						try:
							for user in return_user.json()["data"]:
								if user["public_id"] == single_activity.session_id:
									name = user["full_name"]

						except (IndexError, KeyError) as e:
							name = "N/A"

						except (AttributeError, UnboundLocalError) as e:
							name = "Network Error"
					else:
						name = None

					return_activity["session_user"] = name

					logs.append(return_activity)

			return_data["booking_activity"] = logs

			## Querying booking notes
			get_notes = db.session.query(Note)\
			 .filter(Note.deletion_marker == None)\
			 .filter(Note.ranger_note == None)\
			 .filter(Note.booking_id == single.booking_public_id)\
			 .options(FromCache(db_cache))\
			 .all()

			if not get_notes:
				pass
			else:
				for one_note in get_notes:
					## Append booking note session IDs to id_array
					id_array.append(one_note.session_id)

			## Query Aumra service
			post_data = {"users_ids": id_array}
			# return_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)
			return_user = requests.post(get_user_from_aumra, json=post_data)
			## Booking session ID
			if single.session_id:
				if single.session_id == "guest":
					return_data[
						"session_user"] = single.booking_done_by + " (Public Booking)"
					return_data["session_id"] = single.session_id
				else:
					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single.session_id:
								return_data["session_user"] = user["full_name"]
								return_data["session_id"] = single.session_id

					except (IndexError, KeyError) as user_error:
						return_data["session_user"] = "N/A"
						return_data["session_id"] = single.session_id

					except (AttributeError,
							UnboundLocalError) as network_related_errors:
						return_data["session_user"] = "Network Error"
						return_data["session_id"] = single.session_id
			else:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			## Adding booking notes
			notes = []

			if not get_notes:
				pass
			else:
				for single_note in get_notes:
					return_notes = {}
					return_notes[
						"booking_note_public_id"] = single_note.booking_notes_public_id
					return_notes["note"] = single_note.note
					return_notes["show_on_invoice"] = bool(
						single_note.show_on_invoice)

					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single_note.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"

					except (AttributeError, UnboundLocalError):
						name = "Network Error"

					return_notes["user"] = name
					return_notes["created_at"] = single_note.created_at

					notes.append(return_notes)

			return_data["booking_notes"] = notes

			## Querying booking ranger  notes
			get_ranger_notes = db.session.query(Note)\
			 .filter(Note.deletion_marker == None)\
			 .filter(Note.ranger_note == 1)\
			 .filter(Note.booking_id == single.booking_public_id)\
			 .options(FromCache(db_cache))\
			 .all()

			if not get_ranger_notes:
				pass
			else:
				for one_note in get_ranger_notes:
					## Append booking note session IDs to id_array
					id_array.append(one_note.session_id)

			## Query Aumra service
			post_data = {"users_ids": id_array}
			# return_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)
			return_user = requests.post(get_user_from_aumra, json=post_data)

			## Booking session ID
			if single.session_id:
				if single.session_id == "guest":
					return_data[
						"session_user"] = single.booking_done_by + " (Public Booking)"
					return_data["session_id"] = single.session_id
				else:
					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single.session_id:
								return_data["session_user"] = user["full_name"]
								return_data["session_id"] = single.session_id

					except (IndexError, KeyError) as user_error:
						return_data["session_user"] = "N/A"
						return_data["session_id"] = single.session_id

					except (AttributeError,
							UnboundLocalError) as network_related_errors:
						return_data["session_user"] = "Network Error"
						return_data["session_id"] = single.session_id
			else:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			## Adding booking ranger notes
			ranger_notes = []

			if not get_ranger_notes:
				pass
			else:
				for single_note in get_ranger_notes:
					return_notes = {}
					return_notes[
						"booking_note_public_id"] = single_note.booking_notes_public_id
					return_notes["note"] = single_note.note
					return_notes["alert"] = single_note.alert
					return_notes["ranger_note"] = single_note.ranger_note
					return_notes["show_on_invoice"] = bool(
						single_note.show_on_invoice)

					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single_note.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"

					except (AttributeError, UnboundLocalError):
						name = "Network Error"

					return_notes["user"] = name
					return_notes["created_at"] = single_note.created_at

					ranger_notes.append(return_notes)

			return_data["booking_ranger_notes"] = ranger_notes
			bookingTotal(return_data, single.booking_public_id)

			get_all_booking_payments = db.session.query(Transaction)\
			 .join(PaymentMethod, Transaction.transaction_payment_method == PaymentMethod.payment_method_public_id)\
			 .add_columns(Transaction.transaction_original_cost, Transaction.transaction_total, Transaction.transaction_balance,\
			   Transaction.transaction_date, Transaction.transaction_payment_currency, Transaction.transaction_total_currency,\
			  Transaction.session_id, Transaction.payment_currency_buying_rate_at_time, Transaction.payment_currency_selling_rate_at_time,\
			  Transaction.transaction_booking_public_id,\
			  PaymentMethod.payment_method_name)\
			 .filter(Transaction.deletion_marker == None)\
			 .filter(Transaction.booking_id == booking_id)\
			 .order_by(Transaction.transaction_booking_id.asc())\
			 .options(FromCache(db_cache))\
			 .all()

			transaction_ids = []
			for single_id in get_all_booking_payments:
				transaction_ids.append(single_id.session_id)

			post_data = {"users_ids": transaction_ids}
			# return_transaction_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)
			return_transaction_user = requests.post(get_user_from_aumra,
													json=post_data)

			booking_payments_list = []

			total_payments = []
			total_payments.append(0)
			# conv_total_payments = []
			# conv_total_payments.append(0)
			for each_payment in get_all_booking_payments:
				booking_payments = {}

				# payment_date = each_payment.transaction_date.strftime(
				# 	"%Y-%m-%d")
				payment_date = single.created_at.strftime("%Y-%m-%d")
				try:
					converted_transaction_value = convertAmount(single.currency, each_payment.transaction_payment_currency, each_payment.transaction_total,\
					 each_payment.payment_currency_buying_rate_at_time, each_payment.payment_currency_selling_rate_at_time, payment_date)
				except Exception:
					converted_transaction_value = convertAmount(single.currency, each_payment.transaction_payment_currency, each_payment.transaction_total,\
					 single.currency_buying_rate_at_time, single.currency_selling_rate_at_time, payment_date)

				balance = round(
					((return_data["total_cost"] - sum(total_payments)) -
					 converted_transaction_value), 2)

				# booking_payments["transaction_original_cost"] = float(each_payment.transaction_original_cost)
				booking_payments["transaction_original_cost"] = float(
					return_data["total_cost"])

				try:
					converted_original_cost = convertAmount(each_payment.transaction_payment_currency, single.currency, float(return_data["total_cost"]),\
					 single.currency_buying_rate_at_time, single.currency_selling_rate_at_time, payment_date)
				except Exception as e:
					booking_payments["original_cost_exception"] = str(e)
					converted_original_cost = float(return_data["total_cost"])

				booking_payments[
					"converted_transaction_original_cost"] = converted_original_cost

				booking_payments["transaction_total"] = float(
					each_payment.transaction_total)
				booking_payments["converted_transaction_total"] = float(
					converted_transaction_value)
				# booking_payments["transaction_balance"] = float(each_payment.transaction_balance)
				booking_payments[
					"base_transaction_balance"] = converted_original_cost - float(
						each_payment.transaction_total)

				try:
					_temp = converted_original_cost - float(
						each_payment.transaction_total)
					converted_balance = convertAmount(single.currency, each_payment.transaction_payment_currency, _temp,\
					 each_payment.payment_currency_buying_rate_at_time, each_payment.payment_currency_selling_rate_at_time, payment_date)
				except Exception as e:
					_temp = converted_original_cost - float(
						each_payment.transaction_total)
					booking_payments["balance_exception"] = str(e)
					converted_balance = balance

				booking_payments["converted_balance"] = converted_balance
				# booking_payments["transaction_balance"] = round(converted_balance, 2)
				booking_payments["transaction_balance"] = balance
				booking_payments[
					"transaction_date"] = each_payment.transaction_date
				booking_payments[
					"payment_method"] = each_payment.payment_method_name

				# booking_payments["balance"] = balance
				# booking_payments["sum_of_payments"] = sum(total_payments)

				get_booking_payment = db.session.query(BookingPayment)\
				  .filter(BookingPayment.transaction_id == each_payment.transaction_booking_public_id)\
				  .first()

				try:
					if get_booking_payment.card_first_four:
						trans_code = get_booking_payment.card_first_four + "..." + get_booking_payment.card_last_four
					else:
						trans_code = get_booking_payment.mpesa_reference
				except Exception:
					trans_code = None

				booking_payments["transaction_code"] = trans_code

				transaction_payment_currency = requests.get(
					get_currency.format(
						each_payment.transaction_payment_currency))
				transaction_total_currency = requests.get(
					get_currency.format(
						each_payment.transaction_total_currency))

				try:
					booking_payments[
						"transaction_payment_currency"] = transaction_payment_currency.json(
						)["data"][0]["currency_name"]
				except Exception:
					booking_payments[
						"transaction_payment_currency"] = transaction_total_currency.json(
						)["data"][0]["currency_name"]

				booking_payments[
					"transaction_total_currency"] = transaction_total_currency.json(
					)["data"][0]["currency_name"]

				booking_payments["currency"] = transaction_total_currency.json(
				)["data"][0]["currency_name"]

				try:
					if each_payment.session_id:
						for user in return_transaction_user.json()["data"]:
							if user["public_id"] == each_payment.session_id:
								booking_payments["session_user"] = user[
									"full_name"]
								booking_payments[
									"session_id"] = each_payment.session_id
					else:
						booking_payments["session_user"] = None
						booking_payments["session_id"] = None
				except Exception:
					booking_payments["session_user"] = "Online transaction"
					booking_payments["session_id"] = None

				booking_payments_list.append(booking_payments)
				total_payments.append(converted_transaction_value)
				# conv_total_payments.append(converted_balance)

			booking_payments_list = sorted(
				booking_payments_list,
				key=lambda order: order["transaction_date"],
				reverse=True)
			return_data["booking_payments"] = booking_payments_list

			if single.booking_public_id == "300169b7-bdc2-4a2a-9397-873e6270fa3a":
				booking_payments_list[0]["transaction_balance"] = 0

			residency_db= db.session.query(ResidencyProof)\
			  .filter(ResidencyProof.booking_id == single.booking_public_id)\
			  .filter(ResidencyProof.deletion_marker == None)\
			  .options(FromCache(db_cache))\
			  .all()
			if not residency_db:
				return_data["residency_proof"] = []
			else:
				residency_proof_id_arr = []
				residency_proof = []
				for residency in residency_db:
					## Append booking note session IDs to id_array
					residency_proof_id_arr.append(residency.session_id)
				post_data = {"users_ids": residency_proof_id_arr}
				return_user_proofs = requests.post(get_user_from_aumra,
												   json=post_data)

				for residency in residency_db:
					residency_obj = {}
					residency_obj["first_name"] = residency.first_name
					residency_obj["last_name"] = residency.last_name
					residency_obj["document_id"] = residency.document_id
					residency_obj["created_at"] = residency.created_at
					residency_obj[
						"residency_proof_public_id"] = residency.residency_proof_public_id
					residency_obj["proof_point"] = residency.proof_point
					residency_obj[
						"residency_booking_id"] = single.booking_public_id
					residency_id = residency.residency_id


					get_residence_name = db.session.query(Mandatory)\
					 .add_columns(Mandatory.payment_person,Mandatory.payment_public_id )\
					 .filter(Mandatory.payment_public_id == residency_id)\
					 .options(FromCache(db_cache))\
					 .first()
					residency_obj["residency"] = {
						"payment_person": get_residence_name.payment_person,
						"payment_public_id":
						get_residence_name.payment_public_id
					}

					try:
						for user in return_user_proofs.json()["data"]:
							if user["public_id"] == residency.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"

					except (AttributeError, UnboundLocalError):
						name = "Network Error"

					verify = residency.verified
					if verify == 1:
						residency_obj["verified"] = 'Yes'
						residency_obj["user"] = name

					else:
						residency_obj["verified"] = 'No'
						residency_obj["user"] = ''
					residency_obj["created_at"] = residency.created_at

					residency_proof.append(residency_obj)
				return_data["residency_proof"] = residency_proof


			get_all_booking_donations = db.session.query(Donation)\
			  .filter(Donation.deletion_marker == None)\
			  .filter(Donation.booking_id == booking_id)\
			  .all()

			donations = []
			donation_data = []
			if get_all_booking_donations:
				for single_donation in get_all_booking_donations:
					return_donation_data = {}
					return_donation_data[
						"donation_public_id"] = single_donation.donation_public_id
					return_donation_data[
						"donation_currency"] = single_donation.donation_currency
					return_donation_data["donation_amount"] = float(
						single_donation.donation_amount)
					return_donation_data[
						"donation_cause"] = single_donation.donation_cause

					currency_details = get_details_currency(
						single_donation.donation_currency)
					return_donation_data[
						"donation_currency_name"] = currency_details.json(
						)["data"][0]["currency_name"]

					cause_details = get_details_donation_cause(
						single_donation.donation_cause)
					return_donation_data[
						"donation_cause_name"] = cause_details.json()["name"]

					donation_data.append(return_donation_data)

					donation_amount = currencyPostProcessor(single.currency, single_donation.donation_currency, single_donation.donation_amount,\
					 single_donation.currency_buying_amount, single_donation.currency_selling_amount)

					donations.append(donation_amount)

			donation_total = sum(donations)

			return_data["donations"] = donation_data

			if get_all_booking_payments:

				return_data["booking_payment_balance"] = round(
					float(booking_payments_list[0]["transaction_balance"]), 2)
			else:
				return_data["booking_payment_balance"] = round(
					(float(return_data["total_cost"]) + donation_total), 2)

			if single.payment_status == 1:
				return_data["booking_payment_status"] = "Paid"
			if single.payment_status == 2:
				return_data["booking_payment_status"] = "Incomplete Payment"
			if single.payment_status == 3:
				return_data["booking_payment_status"] = "Complimentary"
			if single.payment_status == 4:
				return_data["booking_payment_status"] = "To Invoice"
			elif not single.payment_status:
				return_data["booking_payment_status"] = "Not Paid"

			get_partner_booking = db.session.query(Partner)\
			  .filter(Partner.deletion_marker == None)\
			  .filter(Partner.booking_id == single.booking_public_id)\
			  .options(FromCache(db_cache))\
			  .first()

			if get_partner_booking:
				return_data[
					"partner_booking_ref"] = get_partner_booking.partner_booking_ref
				return_data["partner_id"] = get_partner_booking.partner_id
				return_data["agent_email"] = get_partner_booking.agent_email

				partner_details = requests.get(
					get_partner_details.format(get_partner_booking.partner_id))
				try:
					return_data["partner_name"] = partner_details.json(
					)["name"]
				except Exception:
					return_data["partner_name"] = None
				paid_by = get_partner_booking.paid_by
				if paid_by == 1:
					return_data[
						"paid_by"] = return_data["partner_name"] + ' To Pay'
				elif paid_by == 0:
					return_data["paid_by"] = 'Guest To Pay'
				else:
					return_data["paid_by"] = 'Not Specified'
			else:
				return_data["partner_booking_ref"] = None
				return_data["partner_id"] = None
				return_data["partner_name"] = None
				return_data["paid_by"] = 'Not Specified'

			check_school_booking = db.session.query(SchoolBooking)\
			   .join(School, SchoolBooking.school_id == School.school_public_id)\
			   .add_columns(School.school_name, School.school_level, School.school_type,\
			  School.school_gender, School.school_code, School.closest_city_town,\
			 School.school_public_id, School.primary_contact, School.primary_contact_email,\
			 School.primary_contact_phone, School.secondary_contact, School.secondary_contact_email,\
			 School.secondary_contact_phone)\
			   .filter(SchoolBooking.deletion_marker == None)\
			   .filter(SchoolBooking.booking_id == single.booking_public_id)\
			   .first()

			if check_school_booking:
				return_data["school_booking"] = True

				school_details = []
				return_school_details = {}
				return_school_details[
					"school_public_id"] = check_school_booking.school_public_id
				return_school_details[
					"school_name"] = check_school_booking.school_name
				return_school_details[
					"school_level"] = check_school_booking.school_level
				return_school_details[
					"school_type"] = check_school_booking.school_type
				return_school_details[
					"school_gender"] = check_school_booking.school_gender
				return_school_details[
					"school_code"] = check_school_booking.school_code
				return_school_details[
					"closest_city_town"] = check_school_booking.closest_city_town
				return_school_details[
					"primary_contact"] = check_school_booking.primary_contact
				return_school_details[
					"primary_contact_email"] = check_school_booking.primary_contact_email
				return_school_details[
					"primary_contact_phone"] = check_school_booking.primary_contact_phone
				return_school_details[
					"secondary_contact"] = check_school_booking.secondary_contact
				return_school_details[
					"secondary_contact_email"] = check_school_booking.secondary_contact_email
				return_school_details[
					"secondary_contact_phone"] = check_school_booking.secondary_contact_phone

				school_details.append(return_school_details)

				return_data["school_booking_details"] = school_details
			else:
				return_data["school_booking"] = False

			check_org_booking = db.session.query(Group)\
			   .filter(Group.deletion_marker == None)\
			   .filter(Group.booking_id == single.booking_public_id)\
			   .first()

			if check_org_booking:
				return_data["corporate_booking"] = True

				org_details = []
				return_org_details = {}
				return_org_details[
					"organisation_name"] = check_org_booking.organisation_name
				return_org_details[
					"organisation_email"] = check_org_booking.organisation_email

				org_details.append(return_org_details)

				return_data["corporate_booking_details"] = org_details
			else:
				return_data["corporate_booking"] = False

			get_details = db.session.query(CheckInVehicle)\
			   .filter(CheckInVehicle.deletion_marker == None)\
			   .filter(CheckInVehicle.booking_id == single.booking_public_id)\
			   .all()

			vehicle_details = []
			for single_detail in get_details:
				vehicle_details.append(single_detail.return_json())

			return_data["vehicle_details"] = vehicle_details

			try:

				if get_member_booking:
					return_data["member_booking"] = True

					query_member_details = get_details_member(
						get_member_booking.member_id)
					return_data["member_details"] = query_member_details

				else:
					return_data["member_booking"] = False
					return_data["member_details"] = {}

			except Exception:
				pass

			# return_data["len_get_booking"] = len(get_booking)

			get_credit_notes = db.session.query(CreditNote)\
			  .filter(CreditNote.deletion_marker == None)\
			  .filter(CreditNote.booking_id == single.booking_public_id)\
			  .all()

			credit_notes = []
			for single_credit_note in get_credit_notes:
				return_credit = {}
				return_credit[
					"credit_note_ref"] = single_credit_note.credit_note_ref
				return_credit[
					"credit_note_public_id"] = single_credit_note.credit_note_public_id
				return_credit[
					"credit_note_currency"] = single_credit_note.credit_note_currency
				# return_credit["credit_note_amount"] = float(single_credit_note.credit_note_amount)
				return_credit[
					"credit_note_reason"] = single_credit_note.credit_note_reason
				return_credit["created_at"] = single_credit_note.created_at
				return_credit["session_id"] = single_credit_note.session_id

				credit_note_details = {}
				creditNoteTotal(single_credit_note.credit_note_public_id,
								single.booking_public_id, credit_note_details)

				return_credit["credit_note_amount"] = float(
					credit_note_details["total"])

				currency = get_details_currency(
					single_credit_note.credit_note_currency)
				return_credit["credit_note_currency_name"] = currency.json(
				)["data"][0]["currency_name"]

				user_details = get_details_user(single_credit_note.session_id)
				return_credit["user"] = user_details.json(
				)["first_name"] + " " + user_details.json()["last_name"]

				credit_notes.append(return_credit)

			return_data["credit_notes"] = credit_notes

			if get_credit_notes:
				return_data["credit_note_issued"] = True
			else:
				return_data["credit_note_issued"] = False

			data.append(return_data)

		return jsonify({"data": data}), 200

@app.route("/bookings/view-detail/<booking_id>")
# @bookings_logger.logWrapper()
def view_booking_detail(booking_id):

	return_bookings = db.session.query(Booking)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.booking_ref_code, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.payment_status,\
	  Booking.currency, Booking.deletion_marker, Booking.currency_buying_rate_at_time,\
	  Booking.currency_selling_rate_at_time,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name,)\
	 .filter(Booking.booking_public_id == booking_id)\
	 .options(FromCache(db_cache))\
	 .all()

	if not return_bookings:
		message = []
		message.append(
			"The selected booking does not appear to exist in the system.")
		return jsonify({"message": message}), 200

	else:
		data = []
		for single in return_bookings:
			return_data = {}

			## Basic booking details
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data[
				"actual_booking_check_in_date"] = single.actual_booking_check_in_date
			return_data[
				"check_in_date"] = single.booking_check_in_date.strftime(
					"%A, %d %b %Y")
			return_data[
				"check_out_date"] = single.booking_check_out_date.strftime(
					"%A, %d %b %Y")
			return_data[
				"actual_booking_check_out_date"] = single.actual_booking_check_out_date
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code
			return_data["created_at"] = single.created_at
			return_data[
				"currency_buying_rate_at_time"] = single.currency_buying_rate_at_time
			return_data[
				"currency_selling_rate_at_time"] = single.currency_selling_rate_at_time

			## Booking status
			if single.checked_out == 1:
				return_data["status"] = "Checked Out"
			elif single.checked_in == 1:
				return_data["status"] = "Checked In"
			elif single.deletion_marker == 1:
				return_data["status"] = "Cancelled"
			else:
				return_data["status"] = single.booking_status_name

			get_gatepass = db.session.query(Gatepass)\
			 .filter(Gatepass.booking_id == single.booking_public_id)\
			 .filter(Gatepass.status != get_booking_status_id("Updated"))\
			 .first()

			if get_gatepass:
				## Booking destination
				try:
					return_data["destination_id"] = get_gatepass.destination
					return_data["destination"], = db.session.query(Destination.gatepass_destination_name)\
					 .filter(Destination.gatepass_destination_public_id == get_gatepass.destination)\
					 .options(FromCache(db_cache))\
					 .first()
					return_data["destination_set"] = True
				except TypeError:
					return_data["destination_id"] = None
					return_data["destination"] = None
					return_data["destination_set"] = False
			else:
				return_data["destination_id"] = None
				return_data["destination"] = None
				return_data["destination_set"] = False

			get_booking_details = db.session.query(Detail)\
			 .filter(Detail.booking_id == single.booking_public_id)\
			 .filter(Detail.status != get_booking_status_id("Updated"))\
			 .first()


			if get_booking_details:
				## Booking details such as a user's first name, last name etc
				detail_data = {}
				detail_data["first_name"] = get_booking_details.first_name
				detail_data["last_name"] = get_booking_details.last_name
				detail_data[
					"email_address"] = get_booking_details.email_address
				detail_data["phone_number"] = get_booking_details.phone_number
				detail_data["city"] = get_booking_details.city
				detail_data["country"] = get_booking_details.country
				detail_data[
					"additional_note"] = get_booking_details.additional_note
				entry_mode = get_booking_details.entry_mode
				if entry_mode:
					detail_data["entry_mode"] = True
					get_entry_mode = db.session.query(EntryMode)\
					   .filter(EntryMode.deletion_marker == None)\
					   .filter(EntryMode.entry_mode_public_id == get_booking_details.entry_mode)\
					   .first()
					try:
						detail_data[
							"entry_mode_name"] = get_entry_mode.entry_mode_name
						detail_data[
							"entry_mode_public_id"] = get_entry_mode.entry_mode_public_id
					except Exception as e:
						detail_data["entry_mode_name"] = ''
						detail_data["entry_mode_public_id"] = ''

					get_entry_point = db.session.query(Gate)\
					 .filter(Gate.deletion_marker == None)\
					 .filter(Gate.gate_public_id == get_booking_details.entry_point)\
					 .first()
					try:
						detail_data["gate_name"] = get_entry_point.gate_name
						detail_data[
							"gate_public_id"] = get_entry_point.gate_public_id
					except Exception as e:
						detail_data["gate_name"] = ''
						detail_data["gate_public_id"] = ''
					detail_data[
						"mode_registration"] = get_booking_details.mode_registration
				else:
					detail_data["entry_mode"] = False

			else:
				detail_data = {}
				detail_data["first_name"] = ""
				detail_data["last_name"] = ""
				detail_data["email_address"] = ""
				detail_data["phone_number"] = ""
				detail_data["city"] = ""
				detail_data["country"] = ""
				detail_data["additional_note"] = ""

			return_data["booking_details"] = detail_data

			viewBookingsTotal(return_data, single.booking_public_id)

			try:
				return_data["currency"] = return_data["booking_currency"]
			except Exception:
				return_data["currency"] = ""

			return_data["currency_id"] = single.currency



			get_all_booking_payments = db.session.query(Transaction)\
			 .join(PaymentMethod, Transaction.transaction_payment_method == PaymentMethod.payment_method_public_id)\
			 .add_columns(Transaction.transaction_original_cost, Transaction.transaction_total, Transaction.transaction_balance,\
			   Transaction.transaction_date, Transaction.transaction_payment_currency, Transaction.transaction_total_currency,\
			  Transaction.session_id, Transaction.payment_currency_buying_rate_at_time, Transaction.payment_currency_selling_rate_at_time,\
			  Transaction.transaction_booking_public_id,\
			  PaymentMethod.payment_method_name)\
			 .filter(Transaction.deletion_marker == None)\
			 .filter(Transaction.booking_id == booking_id)\
			 .order_by(Transaction.transaction_booking_id.asc())\
			 .options(FromCache(db_cache))\
			 .all()

			transaction_ids = []
			for single_id in get_all_booking_payments:
				transaction_ids.append(single_id.session_id)

			booking_payments_list = []

			total_payments = []
			total_payments.append(0)
			for each_payment in get_all_booking_payments:
				booking_payments = {}

				payment_date = each_payment.transaction_date.strftime(
					"%Y-%m-%d")

				try:
					converted_transaction_value = convertAmount(single.currency, each_payment.transaction_payment_currency, each_payment.transaction_total,\
					 each_payment.payment_currency_buying_rate_at_time, each_payment.payment_currency_selling_rate_at_time, payment_date)
				except Exception:
					converted_transaction_value = convertAmount(single.currency, each_payment.transaction_payment_currency, each_payment.transaction_total,\
					 single.currency_buying_rate_at_time, single.currency_selling_rate_at_time, payment_date)

				balance = round(
					((return_data["total_cost"] - sum(total_payments)) -
					 converted_transaction_value), 2)

				# booking_payments["transaction_original_cost"] = float(each_payment.transaction_original_cost)
				booking_payments["transaction_original_cost"] = float(
					return_data["total_cost"])

				try:
					converted_original_cost = convertAmount(each_payment.transaction_payment_currency, single.currency, float(return_data["total_cost"]),\
					 single.currency_buying_rate_at_time, single.currency_selling_rate_at_time, payment_date)
				except Exception as e:
					booking_payments["original_cost_exception"] = str(e)
					converted_original_cost = float(return_data["total_cost"])

				booking_payments[
					"converted_transaction_original_cost"] = float(converted_original_cost)

				booking_payments["transaction_total"] = float(
					each_payment.transaction_total)
				booking_payments["converted_transaction_total"] = float(
					converted_transaction_value)
				# booking_payments["transaction_balance"] = float(each_payment.transaction_balance)
				booking_payments[
					"base_transaction_balance"] = converted_original_cost - float(
						each_payment.transaction_total)

				try:
					_temp = converted_original_cost - float(
						each_payment.transaction_total)
					converted_balance = convertAmount(single.currency, each_payment.transaction_payment_currency, _temp,\
					 each_payment.payment_currency_buying_rate_at_time, each_payment.payment_currency_selling_rate_at_time, payment_date)
				except Exception as e:
					_temp = converted_original_cost - float(
						each_payment.transaction_total)
					booking_payments["balance_exception"] = str(e)
					converted_balance = balance

				booking_payments["converted_balance"] = float(converted_balance)
				# booking_payments["transaction_balance"] = round(converted_balance, 2)
				booking_payments["transaction_balance"] =float(balance)
				booking_payments[
					"transaction_date"] = each_payment.transaction_date
				booking_payments[
					"payment_method"] = each_payment.payment_method_name

				booking_payments_list.append(booking_payments)
			get_all_booking_donations = db.session.query(Donation)\
			  .filter(Donation.deletion_marker == None)\
			  .filter(Donation.booking_id == booking_id)\
			  .all()

			donations = []
			donation_data = []
			if get_all_booking_donations:
				for single_donation in get_all_booking_donations:
					return_donation_data = {}
					return_donation_data[
						"donation_public_id"] = single_donation.donation_public_id
					return_donation_data[
						"donation_currency"] = single_donation.donation_currency
					return_donation_data["donation_amount"] = float(
						single_donation.donation_amount)
					return_donation_data[
						"donation_cause"] = single_donation.donation_cause

					currency_details = get_details_currency(
						single_donation.donation_currency)
					return_donation_data[
						"donation_currency_name"] = currency_details.json(
						)["data"][0]["currency_name"]

					cause_details = get_details_donation_cause(
						single_donation.donation_cause)
					return_donation_data[
						"donation_cause_name"] = cause_details.json()["name"]

					donation_data.append(return_donation_data)

					donation_amount = currencyPostProcessor(single.currency, single_donation.donation_currency, single_donation.donation_amount,\
					 single_donation.currency_buying_amount, single_donation.currency_selling_amount)

					donations.append(donation_amount)

			donation_total = sum(donations)

			return_data["donations"] = donation_data

			if get_all_booking_payments:

				return_data["booking_payment_balance"] = round(
					float(booking_payments_list[0]["transaction_balance"]), 2)
			else:
				return_data["booking_payment_balance"] = round(
					(float(return_data["total_cost"]) + donation_total), 2)

			if single.payment_status == 1:
				return_data["booking_payment_status"] = "Paid"
			if single.payment_status == 2:
				return_data["booking_payment_status"] = "Incomplete Payment"
			if single.payment_status == 3:
				return_data["booking_payment_status"] = "Complimentary"
			if single.payment_status == 4:
				return_data["booking_payment_status"] = "To Invoice"
			elif not single.payment_status:
				return_data["booking_payment_status"] = "Not Paid"

			get_partner_booking = db.session.query(Partner)\
			  .filter(Partner.deletion_marker == None)\
			  .filter(Partner.booking_id == single.booking_public_id)\
			  .options(FromCache(db_cache))\
			  .first()

			if get_partner_booking:
				return_data[
					"partner_booking_ref"] = get_partner_booking.partner_booking_ref
				return_data["partner_id"] = get_partner_booking.partner_id
				return_data["agent_email"] = get_partner_booking.agent_email
				partner_details = requests.get(
					get_partner_details.format(get_partner_booking.partner_id))
				try:
					return_data["partner_name"] = partner_details.json(
					)["name"]
				except Exception:
					return_data["partner_name"] = None
				paid_by = get_partner_booking.paid_by
				if paid_by == 1:
					return_data[
						"paid_by"] = return_data["partner_name"] + ' To Pay'
				elif paid_by == 0:
					return_data["paid_by"] = 'Guest To Pay'
				else:
					return_data["paid_by"] = 'Not Specified'

			else:
				return_data["partner_booking_ref"] = None
				return_data["partner_id"] = None
				return_data["partner_name"] = None

			check_school_booking = db.session.query(SchoolBooking)\
			   .join(School, SchoolBooking.school_id == School.school_public_id)\
			   .add_columns(School.school_name, School.school_level, School.school_type,\
			  School.school_gender, School.school_code, School.closest_city_town,\
			 School.school_public_id, School.primary_contact, School.primary_contact_email,\
			 School.primary_contact_phone, School.secondary_contact, School.secondary_contact_email,\
			 School.secondary_contact_phone)\
			   .filter(SchoolBooking.deletion_marker == None)\
			   .filter(SchoolBooking.booking_id == single.booking_public_id)\
			   .first()

			if check_school_booking:
				return_data["school_booking"] = True

				school_details = []
				return_school_details = {}
				return_school_details[
					"school_public_id"] = check_school_booking.school_public_id
				return_school_details[
					"school_name"] = check_school_booking.school_name
				return_school_details[
					"school_level"] = check_school_booking.school_level
				return_school_details[
					"school_type"] = check_school_booking.school_type
				return_school_details[
					"school_gender"] = check_school_booking.school_gender
				return_school_details[
					"school_code"] = check_school_booking.school_code
				return_school_details[
					"closest_city_town"] = check_school_booking.closest_city_town
				return_school_details[
					"primary_contact"] = check_school_booking.primary_contact
				return_school_details[
					"primary_contact_email"] = check_school_booking.primary_contact_email
				return_school_details[
					"primary_contact_phone"] = check_school_booking.primary_contact_phone
				return_school_details[
					"secondary_contact"] = check_school_booking.secondary_contact
				return_school_details[
					"secondary_contact_email"] = check_school_booking.secondary_contact_email
				return_school_details[
					"secondary_contact_phone"] = check_school_booking.secondary_contact_phone

				school_details.append(return_school_details)

				return_data["school_booking_details"] = school_details
			else:
				return_data["school_booking"] = False

			check_org_booking = db.session.query(Group)\
			   .filter(Group.deletion_marker == None)\
			   .filter(Group.booking_id == single.booking_public_id)\
			   .first()

			if check_org_booking:
				return_data["corporate_booking"] = True

				org_details = []
				return_org_details = {}
				return_org_details[
					"organisation_name"] = check_org_booking.organisation_name
				return_org_details[
					"organisation_email"] = check_org_booking.organisation_email

				org_details.append(return_org_details)

				return_data["corporate_booking_details"] = org_details
			else:
				return_data["corporate_booking"] = False

			get_details = db.session.query(CheckInVehicle)\
			   .filter(CheckInVehicle.deletion_marker == None)\
			   .filter(CheckInVehicle.booking_id == single.booking_public_id)\
			   .all()

			vehicle_details = []
			for single_detail in get_details:
				single_detail_dict = {}
				single_detail_dict[
					"check_vehicle_driver"] = single_detail.check_vehicle_driver
				single_detail_dict[
					"check_vehicle_phone_number"] = single_detail.check_vehicle_phone_number
				single_detail_dict[
					"check_vehicle_reg"] = single_detail.check_vehicle_reg
				single_detail_dict[
					"check_vehicle_disc"] = single_detail.check_vehicle_disc
				single_detail_dict[
					"check_vehicle_public_id"] = single_detail.check_vehicle_public_id

				get_gatepass_source = db.session.query(Gatepass)\
				.join(Gate, Gatepass.gatepass_source == Gate.gate_public_id)\
				.add_columns(Gate.gate_name,Gate.entry_mode_id,)\
				.filter(Gatepass.booking_id == single.booking_public_id)\
				.filter(Gatepass.status != get_booking_status_id("Updated"))\
				.filter(Gatepass.deletion_marker == None)\
				.first()

				single_detail_dict[
					"gatepass_source"] = get_gatepass_source.gate_name

				entry_mode = db.session.query(EntryMode)\
				 .filter(EntryMode.deletion_marker == None)\
				 .filter(EntryMode.entry_mode_public_id == get_gatepass_source.entry_mode_id)\
				 .first()

				single_detail_dict["entry_mode"] = entry_mode.entry_mode_name
				vehicle_details.append(single_detail_dict)

			return_data["vehicle_details"] = vehicle_details

			get_credit_notes = db.session.query(CreditNote)\
			  .filter(CreditNote.deletion_marker == None)\
			  .filter(CreditNote.booking_id == single.booking_public_id)\
			  .first()

			if get_credit_notes:
				return_data["credit_note_issued"] = True
			else:
				return_data["credit_note_issued"] = False

			data.append(return_data)

		return jsonify({"data": data}), 200

@app.route("/bookings/view-more-details/<booking_id>")
# @bookings_logger.logWrapper()
def view_booking_more_detail(booking_id):


	return_bookings = db.session.query(Booking)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.booking_ref_code, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.payment_status,\
	  Booking.currency, Booking.deletion_marker, Booking.currency_buying_rate_at_time,\
	  Booking.currency_selling_rate_at_time)\
	 .filter(Booking.booking_public_id == booking_id)\
	 .options(FromCache(db_cache))\
	 .all()

	if not return_bookings:
		message = []
		message.append(
			"The selected booking does not appear to exist in the system.")
		return jsonify({"message": message}), 200

	else:
		data = []
		id_array = []

		for single in return_bookings:
			return_data = {}

			get_logs = db.session.query(BookingActivity)\
			   .filter(BookingActivity.deletion_marker == None)\
			   .filter(BookingActivity.booking_id == single.booking_public_id)\
			   .order_by(BookingActivity.created_at.desc())\
			   .options(FromCache(db_cache))\
			   .all()

			if not get_logs:
				pass
			else:
				for one_activity in get_logs:
					if one_activity.session_id:
						id_array.append(one_activity.session_id)

			post_data = {"users_ids": id_array}
			return_user = requests.post(get_user_from_aumra, json=post_data)

			logs = []

			if not get_logs:
				pass
			else:
				name = None
				for single_activity in get_logs:
					return_activity = {}
					return_activity[
						"booking_activity_public_id"] = single_activity.booking_activity_public_id
					return_activity["booking_id"] = single_activity.booking_id
					return_activity[
						"booking_activity_description"] = single_activity.booking_activity_description
					return_activity["session_id"] = single_activity.session_id
					return_activity["created_at"] = single_activity.created_at

					if single_activity.session_id:
						try:
							for user in return_user.json()["data"]:
								if user["public_id"] == single_activity.session_id:
									name = user["full_name"]

						except (IndexError, KeyError) as e:
							name = "N/A"

						except (AttributeError, UnboundLocalError) as e:
							name = "Network Error"
					else:
						name = None

					return_activity["session_user"] = name

					logs.append(return_activity)

			return_data["booking_activity"] = logs

			## Querying booking notes
			get_notes = db.session.query(Note)\
			 .filter(Note.deletion_marker == None)\
			 .filter(Note.ranger_note == None)\
			 .filter(Note.booking_id == single.booking_public_id)\
			 .options(FromCache(db_cache))\
			 .all()

			if not get_notes:
				pass
			else:
				for one_note in get_notes:
					id_array.append(one_note.session_id)

			## Query Aumra service
			post_data = {"users_ids": id_array}
			return_user = requests.post(get_user_from_aumra, json=post_data)
			## Booking session ID
			if single.session_id:
				if single.session_id == "guest":
					return_data[
						"session_user"] = single.booking_done_by + " (Public Booking)"
					return_data["session_id"] = single.session_id
				else:
					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single.session_id:
								return_data["session_user"] = user["full_name"]
								return_data["session_id"] = single.session_id

					except (IndexError, KeyError) as user_error:
						return_data["session_user"] = "N/A"
						return_data["session_id"] = single.session_id

					except (AttributeError,
							UnboundLocalError) as network_related_errors:
						return_data["session_user"] = "Network Error"
						return_data["session_id"] = single.session_id
			else:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			## Adding booking notes
			notes = []

			if not get_notes:
				pass
			else:
				for single_note in get_notes:
					return_notes = {}
					return_notes[
						"booking_note_public_id"] = single_note.booking_notes_public_id
					return_notes["note"] = single_note.note
					return_notes["show_on_invoice"] = bool(
						single_note.show_on_invoice)

					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single_note.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"

					except (AttributeError, UnboundLocalError):
						name = "Network Error"

					return_notes["user"] = name
					return_notes["created_at"] = single_note.created_at

					notes.append(return_notes)

			return_data["booking_notes"] = notes

			## Querying booking ranger  notes
			get_ranger_notes = db.session.query(Note)\
			 .filter(Note.deletion_marker == None)\
			 .filter(Note.ranger_note == 1)\
			 .filter(Note.booking_id == single.booking_public_id)\
			 .options(FromCache(db_cache))\
			 .all()

			if not get_ranger_notes:
				pass
			else:
				for one_note in get_ranger_notes:
					id_array.append(one_note.session_id)

			## Query Aumra service
			post_data = {"users_ids": id_array}
			return_user = requests.post(get_user_from_aumra, json=post_data)

			## Booking session ID
			if single.session_id:
				if single.session_id == "guest":
					return_data[
						"session_user"] = single.booking_done_by + " (Public Booking)"
					return_data["session_id"] = single.session_id
				else:
					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single.session_id:
								return_data["session_user"] = user["full_name"]
								return_data["session_id"] = single.session_id

					except (IndexError, KeyError) as user_error:
						return_data["session_user"] = "N/A"
						return_data["session_id"] = single.session_id

					except (AttributeError,
							UnboundLocalError) as network_related_errors:
						return_data["session_user"] = "Network Error"
						return_data["session_id"] = single.session_id
			else:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			## Adding booking ranger notes
			ranger_notes = []

			if not get_ranger_notes:
				pass
			else:
				for single_note in get_ranger_notes:
					return_notes = {}
					return_notes[
						"booking_note_public_id"] = single_note.booking_notes_public_id
					return_notes["note"] = single_note.note
					return_notes["alert"] = single_note.alert
					return_notes["ranger_note"] = single_note.ranger_note
					return_notes["show_on_invoice"] = bool(
						single_note.show_on_invoice)
					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single_note.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"
					except (AttributeError, UnboundLocalError):
						name = "Network Error"
					return_notes["user"] = name
					return_notes["created_at"] = single_note.created_at

					ranger_notes.append(return_notes)

			return_data["booking_ranger_notes"] = ranger_notes
			get_all_booking_payments = db.session.query(Transaction)\
			 .join(PaymentMethod, Transaction.transaction_payment_method == PaymentMethod.payment_method_public_id)\
			 .add_columns(Transaction.transaction_original_cost, Transaction.transaction_total, Transaction.transaction_balance,\
			   Transaction.transaction_date, Transaction.transaction_payment_currency, Transaction.transaction_total_currency,\
			  Transaction.session_id, Transaction.payment_currency_buying_rate_at_time, Transaction.payment_currency_selling_rate_at_time,\
			  Transaction.transaction_booking_public_id,\
			  PaymentMethod.payment_method_name)\
			 .filter(Transaction.deletion_marker == None)\
			 .filter(Transaction.booking_id == booking_id)\
			 .order_by(Transaction.transaction_booking_id.asc())\
			 .options(FromCache(db_cache))\
			 .all()

			transaction_ids = []
			for single_id in get_all_booking_payments:
				transaction_ids.append(single_id.session_id)

			post_data = {"users_ids": transaction_ids}
			return_transaction_user = requests.post(get_user_from_aumra,
													json=post_data)

			booking_payments_list = []

			total_payments = []
			total_payments.append(0)
			for each_payment in get_all_booking_payments:
				booking_payments = {}
				payment_date = each_payment.transaction_date.strftime(
					"%Y-%m-%d")
				try:
					converted_transaction_value = convertAmount(single.currency, each_payment.transaction_payment_currency, each_payment.transaction_total,\
					 each_payment.payment_currency_buying_rate_at_time, each_payment.payment_currency_selling_rate_at_time, payment_date)
				except Exception:
					converted_transaction_value = convertAmount(single.currency, each_payment.transaction_payment_currency, each_payment.transaction_total,\
					 single.currency_buying_rate_at_time, single.currency_selling_rate_at_time, payment_date)
				viewBookingsTotal(return_data, single.booking_public_id)
				balance = round(
					((return_data["total_cost"] - sum(total_payments)) -
					 converted_transaction_value), 2)
				booking_payments["transaction_original_cost"] = float(
					return_data["total_cost"])
				booking_payments["transaction_total"] = float(
					each_payment.transaction_total)
				booking_payments["transaction_balance"] = balance
				booking_payments[
					"transaction_date"] = each_payment.transaction_date
				booking_payments[
					"payment_method"] = each_payment.payment_method_name

				get_booking_payment = db.session.query(BookingPayment)\
				  .filter(BookingPayment.transaction_id == each_payment.transaction_booking_public_id)\
				  .first()
				try:
					if get_booking_payment.card_first_four:
						trans_code = get_booking_payment.card_first_four + "..." + get_booking_payment.card_last_four
					else:
						trans_code = get_booking_payment.mpesa_reference
				except Exception:
					trans_code = None

				booking_payments["transaction_code"] = trans_code
				transaction_payment_currency = requests.get(
					get_currency.format(
						each_payment.transaction_payment_currency))
				transaction_total_currency = requests.get(
					get_currency.format(
						each_payment.transaction_total_currency))

				try:
					booking_payments[
						"transaction_payment_currency"] = transaction_payment_currency.json(
						)["data"][0]["currency_name"]
				except Exception:
					booking_payments[
						"transaction_payment_currency"] = transaction_total_currency.json(
						)["data"][0]["currency_name"]

				booking_payments[
					"transaction_total_currency"] = transaction_total_currency.json(
					)["data"][0]["currency_name"]

				booking_payments["currency"] = transaction_total_currency.json(
				)["data"][0]["currency_name"]

				try:
					if each_payment.session_id:
						for user in return_transaction_user.json()["data"]:
							if user["public_id"] == each_payment.session_id:
								booking_payments["session_user"] = user[
									"full_name"]
								booking_payments[
									"session_id"] = each_payment.session_id
					else:
						booking_payments["session_user"] = None
						booking_payments["session_id"] = None
				except Exception:
					booking_payments["session_user"] = "Online transaction"
					booking_payments["session_id"] = None

				booking_payments_list.append(booking_payments)
				total_payments.append(converted_transaction_value)
				# conv_total_payments.append(converted_balance)

			booking_payments_list = sorted(
				booking_payments_list,
				key=lambda order: order["transaction_date"],
				reverse=True)
			return_data["booking_payments"] = booking_payments_list



			residency_db= db.session.query(ResidencyProof)\
			  .filter(ResidencyProof.booking_id == single.booking_public_id)\
			  .filter(ResidencyProof.deletion_marker == None)\
			  .options(FromCache(db_cache))\
			  .all()
			if not residency_db:
				return_data["residency_proof"] = []
			else:
				residency_proof_id_arr = []
				residency_proof = []
				for residency in residency_db:
					## Append booking note session IDs to id_array
					residency_proof_id_arr.append(residency.session_id)
				post_data = {"users_ids": residency_proof_id_arr}
				return_user_proofs = requests.post(get_user_from_aumra,
												   json=post_data)

				for residency in residency_db:
					residency_obj = {}
					residency_obj["first_name"] = residency.first_name
					residency_obj["last_name"] = residency.last_name
					residency_obj["document_id"] = residency.document_id
					residency_obj["created_at"] = residency.created_at
					residency_obj[
						"residency_proof_public_id"] = residency.residency_proof_public_id
					residency_obj["proof_point"] = residency.proof_point
					residency_obj[
						"residency_booking_id"] = single.booking_public_id
					residency_id = residency.residency_id


					get_residence_name = db.session.query(Mandatory)\
					 .add_columns(Mandatory.payment_person,Mandatory.payment_public_id )\
					 .filter(Mandatory.payment_public_id == residency_id)\
					 .options(FromCache(db_cache))\
					 .first()
					residency_obj["residency"] = {
						"payment_person": get_residence_name.payment_person,
						"payment_public_id":
						get_residence_name.payment_public_id
					}

					try:
						for user in return_user_proofs.json()["data"]:
							if user["public_id"] == residency.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"

					except (AttributeError, UnboundLocalError):
						name = "Network Error"

					verify = residency.verified
					if verify == 1:
						residency_obj["verified"] = 'Yes'
						residency_obj["user"] = name

					else:
						residency_obj["verified"] = 'No'
						residency_obj["user"] = ''
					residency_obj["created_at"] = residency.created_at
					residency_proof.append(residency_obj)
				return_data["residency_proof"] = residency_proof



			get_credit_notes = db.session.query(CreditNote)\
			  .filter(CreditNote.deletion_marker == None)\
			  .filter(CreditNote.booking_id == single.booking_public_id)\
			  .all()

			credit_notes = []
			for single_credit_note in get_credit_notes:
				return_credit = {}
				return_credit[
					"credit_note_ref"] = single_credit_note.credit_note_ref
				return_credit[
					"credit_note_public_id"] = single_credit_note.credit_note_public_id
				return_credit[
					"credit_note_currency"] = single_credit_note.credit_note_currency
				return_credit[
					"credit_note_reason"] = single_credit_note.credit_note_reason
				return_credit["created_at"] = single_credit_note.created_at
				return_credit["session_id"] = single_credit_note.session_id

				credit_note_details = {}
				creditNoteTotal(single_credit_note.credit_note_public_id,
								single.booking_public_id, credit_note_details)

				return_credit["credit_note_amount"] = float(
					credit_note_details["total"])

				currency = get_details_currency(
					single_credit_note.credit_note_currency)
				return_credit["credit_note_currency_name"] = currency.json(
				)["data"][0]["currency_name"]

				user_details = get_details_user(single_credit_note.session_id)
				return_credit["user"] = user_details.json(
				)["first_name"] + " " + user_details.json()["last_name"]

				credit_notes.append(return_credit)

			return_data["credit_notes"] = credit_notes

			if get_credit_notes:
				return_data["credit_note_issued"] = True
			else:
				return_data["credit_note_issued"] = False

			data.append(return_data)

		return jsonify({"data": data}), 200


@app.route("/bookings/view/payment/<booking_id>")
# @bookings_logger.logWrapper()
def view_single_booking_payments(booking_id):
	try:
		get_member_booking = db.session.query(Member)\
		 .filter(Member.deletion_marker == None)\
		 .filter(Member.booking_id == booking_id)\
		 .first()

		if get_member_booking:
			member_data = {}
			bookingTotal(member_data, booking_id)

			if member_data["total_cost"] == 0:
				get_booking = db.session.query(Booking)\
				   .filter(Booking.deletion_marker == None)\
				   .filter(Booking.payment_status == None)\
				   .filter(Booking.booking_public_id == booking_id)\
				   .first()

				if get_booking:
					get_booking.payment_status = 1

					db.session.commit()

	except Exception:
		get_member_booking = None
		# pass

	return_bookings = db.session.query(Booking)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.booking_ref_code, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.payment_status,\
	  Booking.currency, Booking.deletion_marker, Booking.currency_buying_rate_at_time,\
	  Booking.currency_selling_rate_at_time,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name,)\
	 .filter(Booking.booking_public_id == booking_id)\
	 .options(FromCache(db_cache))\
	 .all()

	if not return_bookings:
		message = []
		message.append(
			"The selected booking does not appear to exist in the system.")
		return jsonify({"message": message}), 200

	else:
		data = []
		id_array = []
		inventory_total_cost_array = []
		total_cost_array = []

		asyncRequests = AsyncRequests()

		for single in return_bookings:
			return_data = {}

			## Basic booking details
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data[
				"actual_booking_check_in_date"] = single.actual_booking_check_in_date
			return_data[
				"actual_booking_check_out_date"] = single.actual_booking_check_out_date
			return_data[
				"check_in_date"] = single.booking_check_in_date.strftime(
					"%A, %d %b %Y")
			return_data[
				"check_out_date"] = single.booking_check_out_date.strftime(
					"%A, %d %b %Y")
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code
			return_data["created_at"] = single.created_at
			return_data["currency_buying_rate_at_time"] = round(
				float(single.currency_buying_rate_at_time), 3)
			return_data["currency_selling_rate_at_time"] = round(
				float(single.currency_selling_rate_at_time), 3)
			## Booking status
			if single.checked_out == 1:
				return_data["status"] = "Checked Out"
			elif single.checked_in == 1:
				return_data["status"] = "Checked In"
			elif single.deletion_marker == 1:
				return_data["status"] = "Cancelled"
			else:
				return_data["status"] = single.booking_status_name

			## Booking currency
			currency = requests.get(get_currency.format(single.currency))
			# currency = asyncRequests.launchGetRequest(
			# 	url=get_currency, request_id=single.currency)

			try:
				return_data["currency"] = currency.json(
				)["data"][0]["currency_name"]
			except Exception:
				return_data["currency"] = ""
			return_data["currency_id"] = single.currency

			get_gatepass = db.session.query(Gatepass)\
			 .filter(Gatepass.booking_id == single.booking_public_id)\
			 .filter(Gatepass.status != get_booking_status_id("Updated"))\
			 .first()

			if get_gatepass:
				## Booking destination
				try:
					return_data["destination_id"] = get_gatepass.destination
					return_data["destination"], = db.session.query(Destination.gatepass_destination_name)\
					 .filter(Destination.gatepass_destination_public_id == get_gatepass.destination)\
					 .options(FromCache(db_cache))\
					 .first()
					return_data["destination_set"] = True
				except TypeError:
					return_data["destination_id"] = None
					return_data["destination"] = None
					return_data["destination_set"] = False
			else:
				return_data["destination_id"] = None
				return_data["destination"] = None
				return_data["destination_set"] = False

			get_booking_details = db.session.query(Detail)\
			 .filter(Detail.booking_id == single.booking_public_id)\
			 .filter(Detail.status != get_booking_status_id("Updated"))\
			 .first()

			if get_booking_details:
				## Booking details such as a user's first name, last name etc
				detail_data = {}
				detail_data["first_name"] = get_booking_details.first_name
				detail_data["last_name"] = get_booking_details.last_name
				detail_data[
					"email_address"] = get_booking_details.email_address
				detail_data["phone_number"] = get_booking_details.phone_number
				detail_data["city"] = get_booking_details.city
				detail_data["country"] = get_booking_details.country
				detail_data[
					"additional_note"] = get_booking_details.additional_note
			else:
				detail_data = {}
				detail_data["first_name"] = ""
				detail_data["last_name"] = ""
				detail_data["email_address"] = ""
				detail_data["phone_number"] = ""
				detail_data["city"] = ""
				detail_data["country"] = ""
				detail_data["additional_note"] = ""

			return_data["booking_details"] = detail_data

			## Appending the booking session ID to id_array
			id_array.append(single.session_id)

			get_logs = db.session.query(BookingActivity)\
			   .filter(BookingActivity.deletion_marker == None)\
			   .filter(BookingActivity.booking_id == single.booking_public_id)\
			   .order_by(BookingActivity.created_at.desc())\
			   .options(FromCache(db_cache))\
			   .all()

			if not get_logs:
				pass
			else:
				for one_activity in get_logs:
					if one_activity.session_id:
						id_array.append(one_activity.session_id)

			post_data = {"users_ids": id_array}
			# return_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)

			return_user = requests.post(get_user_from_aumra, json=post_data)

			logs = []

			if not get_logs:
				pass
			else:
				name = None
				for single_activity in get_logs:
					return_activity = {}
					return_activity[
						"booking_activity_public_id"] = single_activity.booking_activity_public_id
					return_activity["booking_id"] = single_activity.booking_id
					return_activity[
						"booking_activity_description"] = single_activity.booking_activity_description
					return_activity["session_id"] = single_activity.session_id
					return_activity["created_at"] = single_activity.created_at

					if single_activity.session_id:
						try:
							for user in return_user.json()["data"]:
								if user["public_id"] == single_activity.session_id:
									name = user["full_name"]

						except (IndexError, KeyError) as e:
							name = "N/A"

						except (AttributeError, UnboundLocalError) as e:
							name = "Network Error"
					else:
						name = None

					return_activity["session_user"] = name

					logs.append(return_activity)

			return_data["booking_activity"] = logs

			## Querying booking notes
			get_notes = db.session.query(Note)\
			 .filter(Note.deletion_marker == None)\
			 .filter(Note.ranger_note == None)\
			 .filter(Note.booking_id == single.booking_public_id)\
			 .options(FromCache(db_cache))\
			 .all()

			if not get_notes:
				pass
			else:
				for one_note in get_notes:
					## Append booking note session IDs to id_array
					id_array.append(one_note.session_id)

			## Query Aumra service
			post_data = {"users_ids": id_array}
			# return_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)
			return_user = requests.post(get_user_from_aumra, json=post_data)
			## Booking session ID
			if single.session_id:
				if single.session_id == "guest":
					return_data[
						"session_user"] = single.booking_done_by + " (Public Booking)"
					return_data["session_id"] = single.session_id
				else:
					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single.session_id:
								return_data["session_user"] = user["full_name"]
								return_data["session_id"] = single.session_id

					except (IndexError, KeyError) as user_error:
						return_data["session_user"] = "N/A"
						return_data["session_id"] = single.session_id

					except (AttributeError,
							UnboundLocalError) as network_related_errors:
						return_data["session_user"] = "Network Error"
						return_data["session_id"] = single.session_id
			else:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			## Adding booking notes
			notes = []

			if not get_notes:
				pass
			else:
				for single_note in get_notes:
					return_notes = {}
					return_notes[
						"booking_note_public_id"] = single_note.booking_notes_public_id
					return_notes["note"] = single_note.note
					return_notes["show_on_invoice"] = bool(
						single_note.show_on_invoice)

					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single_note.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"

					except (AttributeError, UnboundLocalError):
						name = "Network Error"

					return_notes["user"] = name
					return_notes["created_at"] = single_note.created_at

					notes.append(return_notes)

			return_data["booking_notes"] = notes

			## Querying booking ranger  notes
			get_ranger_notes = db.session.query(Note)\
			 .filter(Note.deletion_marker == None)\
			 .filter(Note.ranger_note == 1)\
			 .filter(Note.booking_id == single.booking_public_id)\
			 .options(FromCache(db_cache))\
			 .all()

			if not get_ranger_notes:
				pass
			else:
				for one_note in get_ranger_notes:
					## Append booking note session IDs to id_array
					id_array.append(one_note.session_id)

			## Query Aumra service
			post_data = {"users_ids": id_array}
			# return_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)
			return_user = requests.post(get_user_from_aumra, json=post_data)

			## Booking session ID
			if single.session_id:
				if single.session_id == "guest":
					return_data[
						"session_user"] = single.booking_done_by + " (Public Booking)"
					return_data["session_id"] = single.session_id
				else:
					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single.session_id:
								return_data["session_user"] = user["full_name"]
								return_data["session_id"] = single.session_id

					except (IndexError, KeyError) as user_error:
						return_data["session_user"] = "N/A"
						return_data["session_id"] = single.session_id

					except (AttributeError,
							UnboundLocalError) as network_related_errors:
						return_data["session_user"] = "Network Error"
						return_data["session_id"] = single.session_id
			else:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			## Adding booking ranger notes
			ranger_notes = []

			if not get_ranger_notes:
				pass
			else:
				for single_note in get_ranger_notes:
					return_notes = {}
					return_notes[
						"booking_note_public_id"] = single_note.booking_notes_public_id
					return_notes["note"] = single_note.note
					return_notes["alert"] = single_note.alert
					return_notes["ranger_note"] = single_note.ranger_note
					return_notes["show_on_invoice"] = bool(
						single_note.show_on_invoice)

					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single_note.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"

					except (AttributeError, UnboundLocalError):
						name = "Network Error"

					return_notes["user"] = name
					return_notes["created_at"] = single_note.created_at

					ranger_notes.append(return_notes)

			return_data["booking_ranger_notes"] = ranger_notes
			bookingTotal(return_data, single.booking_public_id)

			get_all_booking_payments = db.session.query(Transaction)\
			 .join(PaymentMethod, Transaction.transaction_payment_method == PaymentMethod.payment_method_public_id)\
			 .add_columns(Transaction.transaction_original_cost, Transaction.transaction_total, Transaction.transaction_balance,\
			   Transaction.transaction_date, Transaction.transaction_payment_currency, Transaction.transaction_total_currency,\
			  Transaction.session_id, Transaction.payment_currency_buying_rate_at_time, Transaction.payment_currency_selling_rate_at_time,\
			  Transaction.transaction_booking_public_id,\
			  PaymentMethod.payment_method_name)\
			 .filter(Transaction.deletion_marker == None)\
			 .filter(Transaction.booking_id == booking_id)\
			 .order_by(Transaction.transaction_booking_id.asc())\
			 .options(FromCache(db_cache))\
			 .all()

			transaction_ids = []
			for single_id in get_all_booking_payments:
				transaction_ids.append(single_id.session_id)

			post_data = {"users_ids": transaction_ids}
			# return_transaction_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)
			return_transaction_user = requests.post(get_user_from_aumra,
													json=post_data)

			booking_payments_list = []

			total_payments = []
			total_payments.append(0)
			# conv_total_payments = []
			# conv_total_payments.append(0)
			for each_payment in get_all_booking_payments:
				booking_payments = {}

				payment_date = each_payment.transaction_date.strftime(
					"%Y-%m-%d")

				try:
					converted_transaction_value = convertAmount(single.currency, each_payment.transaction_payment_currency, each_payment.transaction_total,\
					 each_payment.payment_currency_buying_rate_at_time, each_payment.payment_currency_selling_rate_at_time, payment_date)
				except Exception:
					converted_transaction_value = convertAmount(single.currency, each_payment.transaction_payment_currency, each_payment.transaction_total,\
					 single.currency_buying_rate_at_time, single.currency_selling_rate_at_time, payment_date)

				balance = round(
					((return_data["total_cost"] - sum(total_payments)) -
					 converted_transaction_value), 2)

				# booking_payments["transaction_original_cost"] = float(each_payment.transaction_original_cost)
				booking_payments["transaction_original_cost"] = float(
					return_data["total_cost"])

				try:
					converted_original_cost = convertAmount(each_payment.transaction_payment_currency, single.currency, float(return_data["total_cost"]),\
					 single.currency_buying_rate_at_time, single.currency_selling_rate_at_time, payment_date)
				except Exception as e:
					booking_payments["original_cost_exception"] = str(e)
					converted_original_cost = float(return_data["total_cost"])

				booking_payments[
					"converted_transaction_original_cost"] = converted_original_cost

				booking_payments["transaction_total"] = float(
					each_payment.transaction_total)
				booking_payments["converted_transaction_total"] = float(
					converted_transaction_value)
				# booking_payments["transaction_balance"] = float(each_payment.transaction_balance)
				booking_payments[
					"base_transaction_balance"] = converted_original_cost - float(
						each_payment.transaction_total)

				try:
					_temp = converted_original_cost - float(
						each_payment.transaction_total)
					converted_balance = convertAmount(single.currency, each_payment.transaction_payment_currency, _temp,\
					 each_payment.payment_currency_buying_rate_at_time, each_payment.payment_currency_selling_rate_at_time, payment_date)
				except Exception as e:
					_temp = converted_original_cost - float(
						each_payment.transaction_total)
					booking_payments["balance_exception"] = str(e)
					converted_balance = balance

				booking_payments["converted_balance"] = converted_balance
				# booking_payments["transaction_balance"] = round(converted_balance, 2)
				booking_payments["transaction_balance"] = balance
				booking_payments[
					"transaction_date"] = each_payment.transaction_date
				booking_payments[
					"payment_method"] = each_payment.payment_method_name

				# booking_payments["balance"] = balance
				# booking_payments["sum_of_payments"] = sum(total_payments)

				get_booking_payment = db.session.query(BookingPayment)\
				  .filter(BookingPayment.transaction_id == each_payment.transaction_booking_public_id)\
				  .first()

				try:
					if get_booking_payment.card_first_four:
						trans_code = get_booking_payment.card_first_four + "..." + get_booking_payment.card_last_four
					else:
						trans_code = get_booking_payment.mpesa_reference
				except Exception:
					trans_code = None

				booking_payments["transaction_code"] = trans_code

				transaction_payment_currency = requests.get(
					get_currency.format(
						each_payment.transaction_payment_currency))
				transaction_total_currency = requests.get(
					get_currency.format(
						each_payment.transaction_total_currency))

				try:
					booking_payments[
						"transaction_payment_currency"] = transaction_payment_currency.json(
						)["data"][0]["currency_name"]
				except Exception:
					booking_payments[
						"transaction_payment_currency"] = transaction_total_currency.json(
						)["data"][0]["currency_name"]

				booking_payments[
					"transaction_total_currency"] = transaction_total_currency.json(
					)["data"][0]["currency_name"]

				booking_payments["currency"] = transaction_total_currency.json(
				)["data"][0]["currency_name"]

				try:
					if each_payment.session_id:
						for user in return_transaction_user.json()["data"]:
							if user["public_id"] == each_payment.session_id:
								booking_payments["session_user"] = user[
									"full_name"]
								booking_payments[
									"session_id"] = each_payment.session_id
					else:
						booking_payments["session_user"] = None
						booking_payments["session_id"] = None
				except Exception:
					booking_payments["session_user"] = "Online transaction"
					booking_payments["session_id"] = None

				booking_payments_list.append(booking_payments)
				total_payments.append(converted_transaction_value)
				# conv_total_payments.append(converted_balance)

			booking_payments_list = sorted(
				booking_payments_list,
				key=lambda order: order["transaction_date"],
				reverse=True)
			return_data["booking_payments"] = booking_payments_list

			if single.booking_public_id == "300169b7-bdc2-4a2a-9397-873e6270fa3a":
				booking_payments_list[0]["transaction_balance"] = 0

			get_all_booking_donations = db.session.query(Donation)\
			  .filter(Donation.deletion_marker == None)\
			  .filter(Donation.booking_id == booking_id)\
			  .all()

			donations = []
			donation_data = []
			if get_all_booking_donations:
				for single_donation in get_all_booking_donations:
					return_donation_data = {}
					return_donation_data[
						"donation_public_id"] = single_donation.donation_public_id
					return_donation_data[
						"donation_currency"] = single_donation.donation_currency
					return_donation_data["donation_amount"] = float(
						single_donation.donation_amount)
					return_donation_data[
						"donation_cause"] = single_donation.donation_cause

					currency_details = get_details_currency(
						single_donation.donation_currency)
					return_donation_data[
						"donation_currency_name"] = currency_details.json(
						)["data"][0]["currency_name"]

					cause_details = get_details_donation_cause(
						single_donation.donation_cause)
					return_donation_data[
						"donation_cause_name"] = cause_details.json()["name"]

					donation_data.append(return_donation_data)

					donation_amount = currencyPostProcessor(single.currency, single_donation.donation_currency, single_donation.donation_amount,\
					 single_donation.currency_buying_amount, single_donation.currency_selling_amount)

					donations.append(donation_amount)

			donation_total = sum(donations)

			return_data["donations"] = donation_data

			if get_all_booking_payments:

				return_data["booking_payment_balance"] = round(
					float(booking_payments_list[0]["transaction_balance"]), 2)
			else:
				return_data["booking_payment_balance"] = round(
					(float(return_data["total_cost"]) + donation_total), 2)

			if single.payment_status == 1:
				return_data["booking_payment_status"] = "Paid"
			if single.payment_status == 2:
				return_data["booking_payment_status"] = "Incomplete Payment"
			if single.payment_status == 3:
				return_data["booking_payment_status"] = "Complimentary"
			if single.payment_status == 4:
				return_data["booking_payment_status"] = "To Invoice"
			elif not single.payment_status:
				return_data["booking_payment_status"] = "Not Paid"

			get_partner_booking = db.session.query(Partner)\
			  .filter(Partner.deletion_marker == None)\
			  .filter(Partner.booking_id == single.booking_public_id)\
			  .options(FromCache(db_cache))\
			  .first()

			if get_partner_booking:
				return_data[
					"partner_booking_ref"] = get_partner_booking.partner_booking_ref
				return_data["partner_id"] = get_partner_booking.partner_id
				return_data["agent_email"] = get_partner_booking.agent_email

				partner_details = requests.get(
					get_partner_details.format(get_partner_booking.partner_id))
				try:
					return_data["partner_name"] = partner_details.json(
					)["name"]
				except Exception:
					return_data["partner_name"] = None
			else:
				return_data["partner_booking_ref"] = None
				return_data["partner_id"] = None
				return_data["partner_name"] = None

			check_school_booking = db.session.query(SchoolBooking)\
			   .join(School, SchoolBooking.school_id == School.school_public_id)\
			   .add_columns(School.school_name, School.school_level, School.school_type,\
			  School.school_gender, School.school_code, School.closest_city_town,\
			 School.school_public_id, School.primary_contact, School.primary_contact_email,\
			 School.primary_contact_phone, School.secondary_contact, School.secondary_contact_email,\
			 School.secondary_contact_phone)\
			   .filter(SchoolBooking.deletion_marker == None)\
			   .filter(SchoolBooking.booking_id == single.booking_public_id)\
			   .first()

			if check_school_booking:
				return_data["school_booking"] = True

				school_details = []
				return_school_details = {}
				return_school_details[
					"school_public_id"] = check_school_booking.school_public_id
				return_school_details[
					"school_name"] = check_school_booking.school_name
				return_school_details[
					"school_level"] = check_school_booking.school_level
				return_school_details[
					"school_type"] = check_school_booking.school_type
				return_school_details[
					"school_gender"] = check_school_booking.school_gender
				return_school_details[
					"school_code"] = check_school_booking.school_code
				return_school_details[
					"closest_city_town"] = check_school_booking.closest_city_town
				return_school_details[
					"primary_contact"] = check_school_booking.primary_contact
				return_school_details[
					"primary_contact_email"] = check_school_booking.primary_contact_email
				return_school_details[
					"primary_contact_phone"] = check_school_booking.primary_contact_phone
				return_school_details[
					"secondary_contact"] = check_school_booking.secondary_contact
				return_school_details[
					"secondary_contact_email"] = check_school_booking.secondary_contact_email
				return_school_details[
					"secondary_contact_phone"] = check_school_booking.secondary_contact_phone

				school_details.append(return_school_details)

				return_data["school_booking_details"] = school_details
			else:
				return_data["school_booking"] = False

			check_org_booking = db.session.query(Group)\
			   .filter(Group.deletion_marker == None)\
			   .filter(Group.booking_id == single.booking_public_id)\
			   .first()

			if check_org_booking:
				return_data["corporate_booking"] = True

				org_details = []
				return_org_details = {}
				return_org_details[
					"organisation_name"] = check_org_booking.organisation_name
				return_org_details[
					"organisation_email"] = check_org_booking.organisation_email

				org_details.append(return_org_details)

				return_data["corporate_booking_details"] = org_details
			else:
				return_data["corporate_booking"] = False

			get_details = db.session.query(CheckInVehicle)\
			   .filter(CheckInVehicle.deletion_marker == None)\
			   .filter(CheckInVehicle.booking_id == single.booking_public_id)\
			   .all()

			vehicle_details = []
			for single_detail in get_details:
				vehicle_details.append(single_detail.return_json())

			return_data["vehicle_details"] = vehicle_details

			try:

				if get_member_booking:
					return_data["member_booking"] = True

					query_member_details = get_details_member(
						get_member_booking.member_id)
					return_data["member_details"] = query_member_details

				else:
					return_data["member_booking"] = False
					return_data["member_details"] = {}

			except Exception:
				pass

			# return_data["len_get_booking"] = len(get_booking)

			get_credit_notes = db.session.query(CreditNote)\
			  .filter(CreditNote.deletion_marker == None)\
			  .filter(CreditNote.booking_id == single.booking_public_id)\
			  .all()

			credit_notes = []
			for single_credit_note in get_credit_notes:
				return_credit = {}
				return_credit[
					"credit_note_ref"] = single_credit_note.credit_note_ref
				return_credit[
					"credit_note_public_id"] = single_credit_note.credit_note_public_id
				return_credit[
					"credit_note_currency"] = single_credit_note.credit_note_currency
				# return_credit["credit_note_amount"] = float(single_credit_note.credit_note_amount)
				return_credit[
					"credit_note_reason"] = single_credit_note.credit_note_reason
				return_credit["created_at"] = single_credit_note.created_at
				return_credit["session_id"] = single_credit_note.session_id

				credit_note_details = {}
				creditNoteTotal(single_credit_note.credit_note_public_id,
								single.booking_public_id, credit_note_details)

				return_credit["credit_note_amount"] = float(
					credit_note_details["total"])

				currency = get_details_currency(
					single_credit_note.credit_note_currency)
				return_credit["credit_note_currency_name"] = currency.json(
				)["data"][0]["currency_name"]

				user_details = get_details_user(single_credit_note.session_id)
				return_credit["user"] = user_details.json(
				)["first_name"] + " " + user_details.json()["last_name"]

				credit_notes.append(return_credit)

			return_data["credit_notes"] = credit_notes

			if get_credit_notes:
				return_data["credit_note_issued"] = True
			else:
				return_data["credit_note_issued"] = False

			data.append(return_data)

		return jsonify({"data": data}), 200


@app.route("/bookings/inspection/view/<booking_id>")
# @bookings_logger.logWrapper()
def view_single_inspection_booking(booking_id):

	try:
		get_member_booking = db.session.query(Member)\
		 .filter(Member.deletion_marker == None)\
		 .filter(Member.booking_id == booking_id)\
		 .first()

		if get_member_booking:
			member_data = {}
			bookingTotal(member_data, booking_id)

			if member_data["total_cost"] == 0:
				get_booking = db.session.query(Booking)\
				   .filter(Booking.deletion_marker == None)\
				   .filter(Booking.payment_status == None)\
				   .filter(Booking.booking_public_id == booking_id)\
				   .first()

				if get_booking:
					get_booking.payment_status = 1

					db.session.commit()

	except Exception:
		get_member_booking = None
		# pass

	return_bookings = db.session.query(Booking)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.booking_ref_code, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.payment_status,\
	  Booking.currency, Booking.deletion_marker, Booking.currency_buying_rate_at_time,\
	  Booking.currency_selling_rate_at_time,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name,)\
	 .filter(Booking.booking_public_id == booking_id)\
	 .options(FromCache(db_cache))\
	 .all()

	if not return_bookings:
		message = []
		message.append(
			"The selected booking does not appear to exist in the system.")
		return jsonify({"message": message}), 200

	else:
		data = []
		id_array = []

		asyncRequests = AsyncRequests()

		for single in return_bookings:
			return_data = {}

			## Basic booking details
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data[
				"actual_booking_check_in_date"] = single.actual_booking_check_in_date
			return_data[
				"actual_booking_check_out_date"] = single.actual_booking_check_out_date
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code
			return_data["created_at"] = single.created_at
			return_data["currency_buying_rate_at_time"] = round(
				float(single.currency_buying_rate_at_time), 3)
			return_data["currency_selling_rate_at_time"] = round(
				float(single.currency_selling_rate_at_time), 3)

			## Booking status
			if single.checked_out == 1:
				return_data["status"] = "Checked Out"
			elif single.checked_in == 1:
				return_data["status"] = "Checked In"
			elif single.deletion_marker == 1:
				return_data["status"] = "Cancelled"
			else:
				return_data["status"] = single.booking_status_name

			## Booking currency
			currency = requests.get(get_currency.format(single.currency))
			# currency = asyncRequests.launchGetRequest(
			# 	url=get_currency, request_id=single.currency)

			try:
				return_data["currency"] = currency.json(
				)["data"][0]["currency_name"]
			except Exception:
				return_data["currency"] = ""
			return_data["currency_id"] = single.currency

			get_gatepass = db.session.query(Gatepass)\
			 .filter(Gatepass.booking_id == single.booking_public_id)\
			 .filter(Gatepass.status != get_booking_status_id("Updated"))\
			 .first()

			if get_gatepass:
				## Booking destination
				try:
					return_data["destination_id"] = get_gatepass.destination
					return_data["destination"], = db.session.query(Destination.gatepass_destination_name)\
					 .filter(Destination.gatepass_destination_public_id == get_gatepass.destination)\
					 .options(FromCache(db_cache))\
					 .first()
					return_data["destination_set"] = True
				except TypeError:
					return_data["destination_id"] = None
					return_data["destination"] = None
					return_data["destination_set"] = False
			else:
				return_data["destination_id"] = None
				return_data["destination"] = None
				return_data["destination_set"] = False

			get_booking_details = db.session.query(Detail)\
			 .filter(Detail.booking_id == single.booking_public_id)\
			 .filter(Detail.status != get_booking_status_id("Updated"))\
			 .first()

			if get_booking_details:
				## Booking details such as a user's first name, last name etc
				detail_data = {}
				detail_data["first_name"] = get_booking_details.first_name
				detail_data["last_name"] = get_booking_details.last_name
				detail_data[
					"email_address"] = get_booking_details.email_address
				detail_data["phone_number"] = get_booking_details.phone_number
				detail_data["city"] = get_booking_details.city
				detail_data["country"] = get_booking_details.country
				detail_data[
					"additional_note"] = get_booking_details.additional_note
			else:
				detail_data = {}
				detail_data["first_name"] = ""
				detail_data["last_name"] = ""
				detail_data["email_address"] = ""
				detail_data["phone_number"] = ""
				detail_data["city"] = ""
				detail_data["country"] = ""
				detail_data["additional_note"] = ""

			return_data["booking_details"] = detail_data

			## Appending the booking session ID to id_array
			id_array.append(single.session_id)

			get_logs = db.session.query(BookingActivity)\
			   .filter(BookingActivity.deletion_marker == None)\
			   .filter(BookingActivity.booking_id == single.booking_public_id)\
			   .order_by(BookingActivity.created_at.desc())\
			   .options(FromCache(db_cache))\
			   .all()

			if not get_logs:
				pass
			else:
				for one_activity in get_logs:
					if one_activity.session_id:
						id_array.append(one_activity.session_id)

			post_data = {"users_ids": id_array}
			# return_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)
			return_user = requests.post(get_user_from_aumra, json=post_data)
			logs = []

			if not get_logs:
				pass
			else:
				name = None
				for single_activity in get_logs:
					return_activity = {}
					return_activity[
						"booking_activity_public_id"] = single_activity.booking_activity_public_id
					return_activity["booking_id"] = single_activity.booking_id
					return_activity[
						"booking_activity_description"] = single_activity.booking_activity_description
					return_activity["session_id"] = single_activity.session_id
					return_activity["created_at"] = single_activity.created_at

					if single_activity.session_id:
						try:
							for user in return_user.json()["data"]:
								if user["public_id"] == single_activity.session_id:
									name = user["full_name"]

						except (IndexError, KeyError) as e:
							name = "N/A"

						except (AttributeError, UnboundLocalError) as e:
							name = "Network Error"
					else:
						name = None

					return_activity["session_user"] = name

					logs.append(return_activity)

			return_data["booking_activity"] = logs

			## Querying booking notes
			get_notes = db.session.query(Note)\
			 .filter(Note.deletion_marker == None)\
			 .filter(Note.ranger_note == None)\
			 .filter(Note.booking_id == single.booking_public_id)\
			 .options(FromCache(db_cache))\
			 .all()

			if not get_notes:
				pass
			else:
				for one_note in get_notes:
					## Append booking note session IDs to id_array
					id_array.append(one_note.session_id)

			## Query Aumra service
			post_data = {"users_ids": id_array}
			# return_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)
			return_user = requests.post(get_user_from_aumra, json=post_data)
			## Booking session ID
			if single.session_id:
				if single.session_id == "guest":
					return_data[
						"session_user"] = single.booking_done_by + " (Public Booking)"
					return_data["session_id"] = single.session_id
				else:
					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single.session_id:
								return_data["session_user"] = user["full_name"]
								return_data["session_id"] = single.session_id

					except (IndexError, KeyError) as user_error:
						return_data["session_user"] = "N/A"
						return_data["session_id"] = single.session_id

					except (AttributeError,
							UnboundLocalError) as network_related_errors:
						return_data["session_user"] = "Network Error"
						return_data["session_id"] = single.session_id
			else:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			## Adding booking notes
			notes = []

			if not get_notes:
				pass
			else:
				for single_note in get_notes:
					return_notes = {}
					return_notes[
						"booking_note_public_id"] = single_note.booking_notes_public_id
					return_notes["note"] = single_note.note
					return_notes["show_on_invoice"] = bool(
						single_note.show_on_invoice)

					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single_note.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"

					except (AttributeError, UnboundLocalError):
						name = "Network Error"

					return_notes["user"] = name
					return_notes["created_at"] = single_note.created_at

					notes.append(return_notes)

			return_data["booking_notes"] = notes

			## Querying booking ranger  notes
			get_ranger_notes = db.session.query(Note)\
			 .filter(Note.deletion_marker == None)\
			 .filter(Note.ranger_note == 1)\
			 .filter(Note.booking_id == single.booking_public_id)\
			 .options(FromCache(db_cache))\
			 .all()

			if not get_ranger_notes:
				pass
			else:
				for one_note in get_ranger_notes:
					## Append booking note session IDs to id_array
					id_array.append(one_note.session_id)

			## Query Aumra service
			post_data = {"users_ids": id_array}
			# return_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)
			return_user = requests.post(get_user_from_aumra, json=post_data)
			## Booking session ID
			if single.session_id:
				if single.session_id == "guest":
					return_data[
						"session_user"] = single.booking_done_by + " (Public Booking)"
					return_data["session_id"] = single.session_id
				else:
					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single.session_id:
								return_data["session_user"] = user["full_name"]
								return_data["session_id"] = single.session_id

					except (IndexError, KeyError) as user_error:
						return_data["session_user"] = "N/A"
						return_data["session_id"] = single.session_id

					except (AttributeError,
							UnboundLocalError) as network_related_errors:
						return_data["session_user"] = "Network Error"
						return_data["session_id"] = single.session_id
			else:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			## Adding booking ranger notes
			ranger_notes = []

			if not get_ranger_notes:
				pass
			else:
				for single_note in get_ranger_notes:
					return_notes = {}
					return_notes[
						"booking_note_public_id"] = single_note.booking_notes_public_id
					return_notes["note"] = single_note.note
					return_notes["alert"] = single_note.alert
					return_notes["ranger_note"] = single_note.ranger_note
					return_notes["show_on_invoice"] = bool(
						single_note.show_on_invoice)

					try:
						for user in return_user.json()["data"]:
							if user["public_id"] == single_note.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"

					except (AttributeError, UnboundLocalError):
						name = "Network Error"

					return_notes["user"] = name
					return_notes["created_at"] = single_note.created_at

					ranger_notes.append(return_notes)

			return_data["booking_ranger_notes"] = ranger_notes
			bookingTotal(return_data, single.booking_public_id)

			get_all_booking_payments = db.session.query(Transaction)\
			 .join(PaymentMethod, Transaction.transaction_payment_method == PaymentMethod.payment_method_public_id)\
			 .add_columns(Transaction.transaction_original_cost, Transaction.transaction_total, Transaction.transaction_balance,\
			   Transaction.transaction_date, Transaction.transaction_payment_currency, Transaction.transaction_total_currency,\
			  Transaction.session_id, Transaction.payment_currency_buying_rate_at_time, Transaction.payment_currency_selling_rate_at_time,\
			  Transaction.transaction_booking_public_id,\
			  PaymentMethod.payment_method_name)\
			 .filter(Transaction.deletion_marker == None)\
			 .filter(Transaction.booking_id == booking_id)\
			 .order_by(Transaction.transaction_booking_id.asc())\
			 .options(FromCache(db_cache))\
			 .all()

			transaction_ids = []

			post_data = {"users_ids": transaction_ids}
			# return_transaction_user = asyncRequests.launchPostRequest(
			# 	url=get_user_from_aumra, json=post_data)
			return_transaction_user = requests.post(get_user_from_aumra,
													json=post_data)
			booking_payments_list = []

			total_payments = []
			total_payments.append(0)
			for each_payment in get_all_booking_payments:
				booking_payments = {}

				payment_date = each_payment.transaction_date.strftime(
					"%Y-%m-%d")

				try:
					converted_transaction_value = convertAmount(single.currency, each_payment.transaction_payment_currency, each_payment.transaction_total,\
					 each_payment.payment_currency_buying_rate_at_time, each_payment.payment_currency_selling_rate_at_time, payment_date)
				except Exception:
					converted_transaction_value = convertAmount(single.currency, each_payment.transaction_payment_currency, each_payment.transaction_total,\
					 single.currency_buying_rate_at_time, single.currency_selling_rate_at_time, payment_date)

				balance = round(
					((return_data["total_cost"] - sum(total_payments)) -
					 converted_transaction_value), 2)

				booking_payments["transaction_original_cost"] = float(
					return_data["total_cost"])

				try:
					converted_original_cost = convertAmount(each_payment.transaction_payment_currency, single.currency, float(return_data["total_cost"]),\
					 single.currency_buying_rate_at_time, single.currency_selling_rate_at_time, payment_date)
				except Exception as e:
					booking_payments["original_cost_exception"] = str(e)
					converted_original_cost = float(return_data["total_cost"])

				booking_payments[
					"converted_transaction_original_cost"] = converted_original_cost

				booking_payments["transaction_total"] = float(
					each_payment.transaction_total)
				booking_payments["converted_transaction_total"] = float(
					converted_transaction_value)
				booking_payments[
					"base_transaction_balance"] = converted_original_cost - float(
						each_payment.transaction_total)

				try:
					_temp = converted_original_cost - float(
						each_payment.transaction_total)
					converted_balance = convertAmount(single.currency, each_payment.transaction_payment_currency, _temp,\
					 each_payment.payment_currency_buying_rate_at_time, each_payment.payment_currency_selling_rate_at_time, payment_date)
				except Exception as e:
					_temp = converted_original_cost - float(
						each_payment.transaction_total)
					booking_payments["balance_exception"] = str(e)
					converted_balance = balance

				booking_payments["converted_balance"] = converted_balance

				booking_payments["transaction_balance"] = balance
				booking_payments[
					"transaction_date"] = each_payment.transaction_date
				booking_payments[
					"payment_method"] = each_payment.payment_method_name

				get_booking_payment = db.session.query(BookingPayment)\
				  .filter(BookingPayment.transaction_id == each_payment.transaction_booking_public_id)\
				  .first()

				try:
					if get_booking_payment.card_first_four:
						trans_code = get_booking_payment.card_first_four + "..." + get_booking_payment.card_last_four
					else:
						trans_code = get_booking_payment.mpesa_reference
				except Exception:
					trans_code = None

				booking_payments["transaction_code"] = trans_code

				transaction_payment_currency = requests.get(
					get_currency.format(
						each_payment.transaction_payment_currency))
				transaction_total_currency = requests.get(
					get_currency.format(
						each_payment.transaction_total_currency))

				try:
					booking_payments[
						"transaction_payment_currency"] = transaction_payment_currency.json(
						)["data"][0]["currency_name"]
				except Exception:
					booking_payments[
						"transaction_payment_currency"] = transaction_total_currency.json(
						)["data"][0]["currency_name"]

				booking_payments[
					"transaction_total_currency"] = transaction_total_currency.json(
					)["data"][0]["currency_name"]

				booking_payments["currency"] = transaction_total_currency.json(
				)["data"][0]["currency_name"]

				try:
					if each_payment.session_id:
						for user in return_transaction_user.json()["data"]:
							if user["public_id"] == each_payment.session_id:
								booking_payments["session_user"] = user[
									"full_name"]
								booking_payments[
									"session_id"] = each_payment.session_id
					else:
						booking_payments["session_user"] = None
						booking_payments["session_id"] = None
				except Exception:
					booking_payments["session_user"] = "Online transaction"
					booking_payments["session_id"] = None

				booking_payments_list.append(booking_payments)
				total_payments.append(converted_transaction_value)
				# conv_total_payments.append(converted_balance)

			booking_payments_list = sorted(
				booking_payments_list,
				key=lambda order: order["transaction_date"],
				reverse=True)
			return_data["booking_payments"] = booking_payments_list

			residency_db= db.session.query(ResidencyProof)\
			  .filter(ResidencyProof.booking_id == single.booking_public_id)\
			  .filter(ResidencyProof.deletion_marker == None)\
			  .options(FromCache(db_cache))\
			  .all()
			if not residency_db:
				return_data["residency_proof"] = []
			else:
				residency_proof_id_arr = []
				residency_proof = []
				for residency in residency_db:
					## Append booking note session IDs to id_array
					residency_proof_id_arr.append(residency.session_id)
				post_data = {"users_ids": residency_proof_id_arr}
				return_user_proofs = requests.post(get_user_from_aumra,
												   json=post_data)

				for residency in residency_db:
					residency_obj = {}
					residency_obj["first_name"] = residency.first_name
					residency_obj["last_name"] = residency.last_name
					residency_obj["document_id"] = residency.document_id
					residency_obj["created_at"] = residency.created_at
					residency_obj[
						"residency_proof_public_id"] = residency.residency_proof_public_id
					residency_obj["proof_point"] = residency.proof_point
					residency_obj[
						"residency_booking_id"] = single.booking_public_id
					residency_id = residency.residency_id


					get_residence_name = db.session.query(Mandatory)\
					 .add_columns(Mandatory.payment_person,Mandatory.payment_public_id )\
					 .filter(Mandatory.payment_public_id == residency_id)\
					 .options(FromCache(db_cache))\
					 .first()
					residency_obj["residency"] = {
						"payment_person": get_residence_name.payment_person,
						"payment_public_id":
						get_residence_name.payment_public_id
					}

					try:
						for user in return_user_proofs.json()["data"]:
							if user["public_id"] == residency.session_id:
								name = user["full_name"]

					except (IndexError, KeyError):
						name = "N/A"

					except (AttributeError, UnboundLocalError):
						name = "Network Error"

					verify = residency.verified
					if verify == 1:
						residency_obj["verified"] = 'Yes'
						residency_obj["user"] = name

					else:
						residency_obj["verified"] = 'No'
						residency_obj["user"] = ''
					inspected = residency.inspected

					if inspected == 1:
						residency_obj["inspected"] = True
						user_info = {}
						inspected_by = residency.inspected_by

						try:
							getBookingSessionUser(inspected_by, user_info)
							return_data["inspected_by"] = user_info[
								"session_user"]
							return_data["inspection_user_id"] = user_info[
								"inspected_by"]
						except Exception as e:
							return_data["inspected_by"] = ''
							return_data["inspection_user_id"] = ''
					else:
						return_data["inspected"] = False
						return_data["inspected_by"] = ''
						return_data["inspection_user_id"] = ''

					return_data["notes"] = ''
					residency_obj["created_at"] = residency.created_at

					residency_proof.append(residency_obj)
				return_data["residency_proof"] = residency_proof

			if single.booking_public_id == "300169b7-bdc2-4a2a-9397-873e6270fa3a":
				booking_payments_list[0]["transaction_balance"] = 0

			if single.payment_status == 1:
				return_data["booking_payment_status"] = "Paid"
			if single.payment_status == 2:
				return_data["booking_payment_status"] = "Incomplete Payment"
			if single.payment_status == 3:
				return_data["booking_payment_status"] = "Complimentary"
			if single.payment_status == 4:
				return_data["booking_payment_status"] = "To Invoice"
			elif not single.payment_status:
				return_data["booking_payment_status"] = "Not Paid"

			get_partner_booking = db.session.query(Partner)\
			  .filter(Partner.deletion_marker == None)\
			  .filter(Partner.booking_id == single.booking_public_id)\
			  .options(FromCache(db_cache))\
			  .first()

			if get_partner_booking:
				return_data[
					"partner_booking_ref"] = get_partner_booking.partner_booking_ref
				return_data["partner_id"] = get_partner_booking.partner_id
				return_data["agent_email"] = get_partner_booking.agent_email

				partner_details = requests.get(
					get_partner_details.format(get_partner_booking.partner_id))
				try:
					return_data["partner_name"] = partner_details.json(
					)["name"]
				except Exception:
					return_data["partner_name"] = None
			else:
				return_data["partner_booking_ref"] = None
				return_data["partner_id"] = None
				return_data["partner_name"] = None

			check_school_booking = db.session.query(SchoolBooking)\
			   .join(School, SchoolBooking.school_id == School.school_public_id)\
			   .add_columns(School.school_name, School.school_level, School.school_type,\
			  School.school_gender, School.school_code, School.closest_city_town,\
			 School.school_public_id, School.primary_contact, School.primary_contact_email,\
			 School.primary_contact_phone, School.secondary_contact, School.secondary_contact_email,\
			 School.secondary_contact_phone)\
			   .filter(SchoolBooking.deletion_marker == None)\
			   .filter(SchoolBooking.booking_id == single.booking_public_id)\
			   .first()

			if check_school_booking:
				return_data["school_booking"] = True

				school_details = []
				return_school_details = {}
				return_school_details[
					"school_public_id"] = check_school_booking.school_public_id
				return_school_details[
					"school_name"] = check_school_booking.school_name
				return_school_details[
					"school_level"] = check_school_booking.school_level
				return_school_details[
					"school_type"] = check_school_booking.school_type
				return_school_details[
					"school_gender"] = check_school_booking.school_gender
				return_school_details[
					"school_code"] = check_school_booking.school_code
				return_school_details[
					"closest_city_town"] = check_school_booking.closest_city_town
				return_school_details[
					"primary_contact"] = check_school_booking.primary_contact
				return_school_details[
					"primary_contact_email"] = check_school_booking.primary_contact_email
				return_school_details[
					"primary_contact_phone"] = check_school_booking.primary_contact_phone
				return_school_details[
					"secondary_contact"] = check_school_booking.secondary_contact
				return_school_details[
					"secondary_contact_email"] = check_school_booking.secondary_contact_email
				return_school_details[
					"secondary_contact_phone"] = check_school_booking.secondary_contact_phone

				school_details.append(return_school_details)

				return_data["school_booking_details"] = school_details
			else:
				return_data["school_booking"] = False

			check_org_booking = db.session.query(Group)\
			   .filter(Group.deletion_marker == None)\
			   .filter(Group.booking_id == single.booking_public_id)\
			   .first()

			if check_org_booking:
				return_data["corporate_booking"] = True

				org_details = []
				return_org_details = {}
				return_org_details[
					"organisation_name"] = check_org_booking.organisation_name
				return_org_details[
					"organisation_email"] = check_org_booking.organisation_email

				org_details.append(return_org_details)

				return_data["corporate_booking_details"] = org_details
			else:
				return_data["corporate_booking"] = False

			get_details = db.session.query(CheckInVehicle)\
			   .filter(CheckInVehicle.deletion_marker == None)\
			   .filter(CheckInVehicle.booking_id == single.booking_public_id)\
			   .all()

			vehicle_details = []
			for single_detail in get_details:
				vehicle_details.append(single_detail.return_json())

			return_data["vehicle_details"] = vehicle_details

			try:

				if get_member_booking:
					return_data["member_booking"] = True

					query_member_details = get_details_member(
						get_member_booking.member_id)
					return_data["member_details"] = query_member_details

				else:
					return_data["member_booking"] = False
					return_data["member_details"] = {}

			except Exception:
				pass

			data.append(return_data)

		return jsonify({"data": data}), 200


@app.route("/bookings/ticket/<booking_ref>")
# @bookings_logger.logWrapper()
def view_booking_by_ref(booking_ref):
	"""
	The sole purpose of this endpoint is to return data for ticket printing.
	"""
	booking_ref = (booking_ref.lower()).strip()
	return_bookings = db.session.query(Booking)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .join(Detail, Booking.booking_public_id == Detail.booking_id)\
	 .join(Gatepass, Booking.booking_public_id == Gatepass.booking_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.booking_ref_code, Booking.session_id,\
	  Booking.created_at, Booking.updated_at,Booking.currency_buying_rate_at_time, Booking.currency_selling_rate_at_time, Booking.status, Booking.payment_status,\
	  Booking.currency, Booking.deletion_marker, Booking.ticket,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name,\
	  Detail.first_name, Detail.last_name, Detail.email_address, Detail.phone_number,\
	  Detail.address, Detail.additional_note, Detail.city,\
	  Detail.country,Detail.kra_pin_number,\
	  Gatepass.destination)\
	 .filter(Booking.booking_ref_code == booking_ref) \
	 .filter(Detail.status != get_booking_status_id("Updated")) \
	 .options(FromCache(db_cache))\
	 .all()

	if not return_bookings:
		message = []
		message.append(
			"The selected booking does not appear to exist in the system.")
		return jsonify({"message": message}), 200

	else:
		data = []
		id_array = []
		inventory_total_cost_array = []
		total_cost_array = []

		asyncRequests = AsyncRequests()

		for single in return_bookings:
			return_data = {}

			## Basic booking details
			return_data[
				"booking_check_in_date"] = single.booking_check_in_date.strftime(
					"%a %d %b %Y")
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date.strftime(
					"%a %d %b %Y")
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code
			return_data["created_at"] = single.created_at

			get_booking_ticket = db.session.query(Booking)\
			  .filter(Booking.deletion_marker == None)\
			 .filter(Booking.booking_ref_code == booking_ref)\
			 .first()

			ticket_no = get_booking_ticket.ticket
			if not ticket_no:
				get_last_ticket = db.session.query(Ticket)\
				 .filter(Ticket.deletion_marker == None)\
				 .filter(Ticket.ticket_date == datetime.now().strftime("%Y-%m-%d"))\
				 .first()

				if not get_last_ticket:
					booking_ticket = ticketGenerator(None)

					ticket = Ticket(
						booking_tickets_public_id=str(uuid.uuid4()),
						ticket_date=datetime.now().strftime("%Y-%m-%d"),
						first_ticket=booking_ticket,
						last_ticket=booking_ticket,
						session_id="TicketPrinter",
						created_at=datetime.now(),
						updated_at=datetime.now())

					db.session.add(ticket)

					# single.ticket = booking_ticket

				else:
					booking_ticket = ticketGenerator(
						get_last_ticket.last_ticket)

					get_last_ticket.last_ticket = booking_ticket
					get_last_ticket.updated_at = datetime.now()

				get_booking_ticket.ticket = booking_ticket

			else:
				booking_ticket = ticket_no

			return_data["booking_ticket"] = booking_ticket

			## Booking currency
			currency = requests.get(get_currency.format(single.currency))
			# currency = asyncRequests.launchGetRequest(
			# 	url=get_currency, request_id=single.currency)

			try:
				return_data["currency"] = currency.json(
				)["data"][0]["currency_name"]
			except Exception:
				return_data["currency"] = ""
			return_data["currency_id"] = single.currency

			guest_kra_pin = single.kra_pin_number

			## Booking destination
			try:
				return_data["destination_id"] = single.destination
				return_data["destination"], = db.session.query(Destination.gatepass_destination_name)\
				 .filter(Destination.gatepass_destination_public_id == single.destination)\
				 .options(FromCache(db_cache))\
				 .first()
				return_data["destination_set"] = True
			except TypeError:
				return_data["destination_id"] = None
				return_data["destination"] = "N/A"
				return_data["destination_set"] = False
			except Exception:
				return_data["destination"] = "N/A"

			get_partner_booking = db.session.query(Partner) \
				.filter(Partner.deletion_marker == None) \
				.filter(Partner.booking_id == single.booking_public_id) \
				.options(FromCache(db_cache)) \
				.first()
			partner_kra_pin = None
			if get_partner_booking:
				partner_details = requests.get(
					get_partner_details.format(get_partner_booking.partner_id))
				try:
					partner_details = partner_details.json()
					try:
						partner_kra_pin = partner_details["kra_pin_number"]
						if partner_kra_pin:
							partner_kra_pin = partner_details["kra_pin_number"]
						else:
							partner_kra_pin = None
					except Exception:
						partner_kra_pin = None
				except Exception:
					partner_kra_pin = None

			kra_pin_number = guest_kra_pin or partner_kra_pin

			## Booking details such as a user's first name, last name etc
			detail_data = {}
			if kra_pin_number:
				detail_data["first_name"] = single.first_name + ".  KRA PIN: " + kra_pin_number
			else:
				detail_data["first_name"] = single.first_name
			detail_data["last_name"] = single.last_name
			detail_data["email_address"] = single.email_address
			detail_data["phone_number"] = single.phone_number
			detail_data["city"] = single.city
			detail_data["country"] = single.country
			detail_data["additional_note"] = single.additional_note

			return_data["booking_details"] = detail_data

			# try:
			# 	return_user = requests.post(get_user_from_aumra,\
			# 								json = {"users_ids": id_array})
			# except (requests.exceptions.ConnectionError, requests.exceptions.Timeout, requests.exceptions.ConnectTimeout) as connection_error:
			# 	pass

			## Querying booking notes
			get_notes = db.session.query(Note)\
			 .filter(Note.deletion_marker == None)\
			 .filter(Note.booking_id == single.booking_public_id)\
			 .options(FromCache(db_cache))\
			 .all()

			if not get_notes:
				pass
			else:
				for one_note in get_notes:
					## Append booking note session IDs to id_array
					id_array.append(one_note.session_id)

			bookingTotal(return_data, single.booking_public_id)


			#modify code
			temp_inventory_data = return_data["inventory_bookings"]
			return_data["inventory_bookings"] = []

			#modify our dat
			if return_data["guest_total"] > 0:
				guest_data = return_data["guests"]
				for guest  in guest_data:
					if guest["payment_guests"]>0:
						guest_obj = {}
						guest_obj["inventory_name"] =guest["payment_person"]
						guest_obj["inventory_ranger_marker"] =False
						guest_obj["agent_discount"] = 0.0
						guest_obj["agent_discount_amount"] =0
						guest_obj["inventory_id"] ="5bfa622d-1d4f-495b-bc64-d0146d14a7a6"
						guest_obj["inventory_booking_public_id"] = "57d60300-46e1-4e41-a939-087702ede756"
						guest_obj["inventory_booking_date"]=single.booking_check_out_date.strftime("%a %d %b %Y")
						guest_obj["inventory_booking_guests"] = guest["payment_guests"]
						guest_obj["inventory_booking_adults"]= 2
						guest_obj["inventory_booking_children"]= 0
						guest_obj["inventory_booking_extra_adults"]= 0
						guest_obj["inventory_booking_extra_children"]= 0
						guest_obj["inventory_booking_adult_cost"]= 14536.0
						# guest_obj["inventory_booking_total_cost"] = (guest["payment_person_amount"] * guest["payment_guests"])
						guest_obj["inventory_booking_total_cost"] = guest["payment_person_cost_after_discount"]
						guest_obj["inventory_booking_adult_cost_before_discounts"]= 14536.0
						guest_obj["inventory_booking_adult_cost_before_discounts"]= 14536.0
						guest_obj["inventory_booking_adult_cost_after_discounts"]= 14536.0
						guest_obj["inventory_booking_child_cost"]= 0.0
						guest_obj["inventory_booking_cost_per_child"]= 3634.0
						guest_obj["inventory_booking_child_cost_before_discounts"]= 0.0
						guest_obj["inventory_booking_child_cost_after_discounts"]= 0.0
						guest_obj["inventory_booking_total_cost_before_discounts"]= 14536.0
						guest_obj["inventory_booking_total_discount"]= 0.0
						guest_obj["inventory_booking_discount_percentage"]= 0.0
						guest_obj["inventory_booking_commission_percentage"]= 0.0
						guest_obj["adult_with_commission"]= 14536.0
						guest_obj["child_with_commission"]= 0.0
						guest_obj["discount_amount"]= 0.0
						guest_obj["time_frame"] = ""
						guest_obj["pick_up_location"]= None
						guest_obj["inventory_booking_currency"]= "KES"

						return_data["inventory_bookings"].append(guest_obj)

			if return_data["vehicle_total"] > 0:
				vehicle_data = return_data["vehicles"]
				for vehicle  in vehicle_data:
					if vehicle["vehicles"] > 0:
						vehicle_obj = {}
						vehicle_obj["inventory_name"] =vehicle["vehicle_charge_category"]
						vehicle_obj["inventory_ranger_marker"] =False
						vehicle_obj["agent_discount"] = 0.0
						vehicle_obj["agent_discount_amount"] =0
						vehicle_obj["inventory_id"] ="5bfa622d-1d4f-495b-bc64-d0146d14a7a6"
						vehicle_obj["inventory_booking_public_id"] = "57d60300-46e1-4e41-a939-087702ede756"
						vehicle_obj["inventory_booking_date"]=single.booking_check_out_date.strftime("%a %d %b %Y")
						vehicle_obj["inventory_booking_guests"] = vehicle["vehicles"]
						vehicle_obj["inventory_booking_adults"]= 2
						vehicle_obj["inventory_booking_children"]= 0
						vehicle_obj["inventory_booking_extra_adults"]= 0
						vehicle_obj["inventory_booking_extra_children"]= 0
						vehicle_obj["inventory_booking_adult_cost"]= 14536.0
						# vehicle_obj["inventory_booking_total_cost"] = vehicle["vehicle_charge_category_cost"] * vehicle["vehicles"]
						vehicle_obj["inventory_booking_total_cost"] = vehicle["vehicle_cost_after_discount"]
						vehicle_obj["inventory_booking_adult_cost_before_discounts"]= 14536.0
						vehicle_obj["inventory_booking_adult_cost_before_discounts"]= 14536.0
						vehicle_obj["inventory_booking_adult_cost_after_discounts"]= 14536.0
						vehicle_obj["inventory_booking_child_cost"]= 0.0
						vehicle_obj["inventory_booking_cost_per_child"]= 3634.0
						vehicle_obj["inventory_booking_child_cost_before_discounts"]= 0.0
						vehicle_obj["inventory_booking_child_cost_after_discounts"]= 0.0
						vehicle_obj["inventory_booking_total_cost_before_discounts"]= 14536.0
						vehicle_obj["inventory_booking_total_discount"]= 0.0
						vehicle_obj["inventory_booking_discount_percentage"]= 0.0
						vehicle_obj["inventory_booking_commission_percentage"]= 0.0
						vehicle_obj["adult_with_commission"]= 14536.0
						vehicle_obj["child_with_commission"]= 0.0
						vehicle_obj["discount_amount"]= 0.0
						vehicle_obj["time_frame"] = ""
						vehicle_obj["pick_up_location"]= None
						vehicle_obj["inventory_booking_currency"]= "KES"
						return_data["inventory_bookings"].append(vehicle_obj)

			if return_data["facility_bookings_total"] > 0:
				facility_data = return_data["facility_bookings"]
				for facility  in facility_data:
					if facility["facility_booking_guests"]>0:
						facility_obj = {}
						facility_obj["inventory_name"] =facility["facility_name"]
						facility_obj["inventory_booking_guests"] = facility["facility_booking_guests"]


						facility_obj["inventory_ranger_marker"] =False
						facility_obj["agent_discount"] = 0.0
						facility_obj["agent_discount_amount"] =0
						facility_obj["inventory_id"] ="5bfa622d-1d4f-495b-bc64-d0146d14a7a6"
						facility_obj["inventory_booking_public_id"] = "57d60300-46e1-4e41-a939-087702ede756"
						facility_obj["inventory_booking_date"]=single.booking_check_out_date.strftime("%a %d %b %Y")
						facility_obj["inventory_booking_guests"] = facility["facility_booking_guests"]
						facility_obj["inventory_booking_adults"]= 2
						facility_obj["inventory_booking_children"]= 0
						facility_obj["inventory_booking_extra_adults"]= 0
						facility_obj["inventory_booking_extra_children"]= 0
						facility_obj["inventory_booking_adult_cost"]= 14536.0
						facility_obj["inventory_booking_total_cost"] =facility["facility_booking_total_cost"]
						facility_obj["inventory_booking_adult_cost_before_discounts"]= 14536.0
						facility_obj["inventory_booking_adult_cost_before_discounts"]= 14536.0
						facility_obj["inventory_booking_adult_cost_after_discounts"]= 14536.0
						facility_obj["inventory_booking_child_cost"]= 0.0
						facility_obj["inventory_booking_cost_per_child"]= 3634.0
						facility_obj["inventory_booking_child_cost_before_discounts"]= 0.0
						facility_obj["inventory_booking_child_cost_after_discounts"]= 0.0
						facility_obj["inventory_booking_total_cost_before_discounts"]= 14536.0
						facility_obj["inventory_booking_total_discount"]= 0.0
						facility_obj["inventory_booking_discount_percentage"]= 0.0
						facility_obj["inventory_booking_commission_percentage"]= 0.0
						facility_obj["adult_with_commission"]= 14536.0
						facility_obj["child_with_commission"]= 0.0
						facility_obj["discount_amount"]= 0.0
						facility_obj["time_frame"] = ""
						facility_obj["pick_up_location"]= None
						facility_obj["inventory_booking_currency"]= "KES"

						return_data["inventory_bookings"].append(facility_obj)

			if len(temp_inventory_data) > 0:
				for inventory in temp_inventory_data:
					return_data["inventory_bookings"].append(inventory)
			return_data["inventory_bookings_total"] = len(return_data["inventory_bookings"])
			return_data["guest_total"] = 0
			return_data["vehicle_total"] = 0
			return_data["facility_bookings_total"] = 0



			selling_rate = round(float( single.currency_selling_rate_at_time), 2)
			destination = return_data["destination"]
			return_data["destination"] = destination+". Rate: " + str(selling_rate)

			get_partner_booking = db.session.query(Partner)\
			  .filter(Partner.deletion_marker == None)\
			  .filter(Partner.booking_id == single.booking_public_id)\
			  .options(FromCache(db_cache))\
			  .first()
			if get_partner_booking:
				return_data[
					"partner_booking_ref"] = get_partner_booking.partner_booking_ref
				return_data["partner_id"] = get_partner_booking.partner_id

				partner_details = requests.get(
					get_partner_details.format(get_partner_booking.partner_id))
				try:
					return_data["partner_name"] = partner_details.json(
					)["name"]

					partner_details = partner_details.json()
					try:
						partner_kra_pin = partner_details["kra_pin_number"]
						if partner_kra_pin:
							partner_kra_pin = partner_details["kra_pin_number"]
						else:
							partner_kra_pin = None
					except Exception:
						partner_kra_pin = None
				except Exception:
					return_data["partner_name"] = None
			else:
				return_data["partner_booking_ref"] = None
				return_data["partner_id"] = None
				return_data["partner_name"] = None

			# kra_pin_number = guest_kra_pin or partner_kra_pin
			# if kra_pin_number:
			# 	booking_currency_name = return_data["booking_currency_name"]
			# 	return_data["booking_currency_name"] = booking_currency_name + ".  KRA PIN: " + kra_pin_number


			check_school_booking = db.session.query(SchoolBooking)\
			   .join(School, SchoolBooking.school_id == School.school_public_id)\
			   .add_columns(School.school_name, School.school_level, School.school_type,\
			  School.school_gender, School.school_code, School.closest_city_town,\
			 School.school_public_id, School.primary_contact, School.primary_contact_email,\
			 School.primary_contact_phone, School.secondary_contact, School.secondary_contact_email,\
			 School.secondary_contact_phone)\
			   .filter(SchoolBooking.deletion_marker == None)\
			   .filter(SchoolBooking.booking_id == single.booking_public_id)\
			   .first()

			if check_school_booking:
				return_data["school_booking"] = True

				school_details = []
				return_school_details = {}
				return_school_details[
					"school_public_id"] = check_school_booking.school_public_id
				return_school_details[
					"school_name"] = check_school_booking.school_name
				return_school_details[
					"school_level"] = check_school_booking.school_level
				return_school_details[
					"school_type"] = check_school_booking.school_type
				return_school_details[
					"school_gender"] = check_school_booking.school_gender
				return_school_details[
					"school_code"] = check_school_booking.school_code
				return_school_details[
					"closest_city_town"] = check_school_booking.closest_city_town
				return_school_details[
					"primary_contact"] = check_school_booking.primary_contact
				return_school_details[
					"primary_contact_email"] = check_school_booking.primary_contact_email
				return_school_details[
					"primary_contact_phone"] = check_school_booking.primary_contact_phone
				return_school_details[
					"secondary_contact"] = check_school_booking.secondary_contact
				return_school_details[
					"secondary_contact_email"] = check_school_booking.secondary_contact_email
				return_school_details[
					"secondary_contact_phone"] = check_school_booking.secondary_contact_phone

				school_details.append(return_school_details)

				return_data["school_booking_details"] = school_details
			else:
				return_data["school_booking"] = False

			check_org_booking = db.session.query(Group)\
			   .filter(Group.deletion_marker == None)\
			   .filter(Group.booking_id == single.booking_public_id)\
			   .first()

			if check_org_booking:
				return_data["corporate_booking"] = True

				org_details = []
				return_org_details = {}
				return_org_details[
					"organisation_name"] = check_org_booking.organisation_name
				return_org_details[
					"organisation_email"] = check_org_booking.organisation_email

				org_details.append(return_org_details)

				return_data["corporate_booking_details"] = org_details
			else:
				return_data["corporate_booking"] = False

			get_details = db.session.query(CheckInVehicle)\
			   .filter(CheckInVehicle.deletion_marker == None)\
			   .filter(CheckInVehicle.booking_id == single.booking_public_id)\
			   .all()

			vehicle_details = []
			for single_detail in get_details:
				vehicle_details.append(single_detail.return_json())

			return_data["vehicle_details"] = vehicle_details

			get_all_booking_payments = db.session.query(Transaction)\
			 .join(PaymentMethod, Transaction.transaction_payment_method == PaymentMethod.payment_method_public_id)\
			 .add_columns(Transaction.transaction_original_cost, Transaction.transaction_total, Transaction.transaction_balance,\
			   Transaction.transaction_date, Transaction.transaction_payment_currency, Transaction.transaction_total_currency,\
			  Transaction.session_id, Transaction.payment_currency_buying_rate_at_time, Transaction.payment_currency_selling_rate_at_time,\
			  PaymentMethod.payment_method_name)\
			 .filter(Transaction.deletion_marker == None)\
			 .filter(Transaction.booking_id == single.booking_public_id)\
			 .order_by(Transaction.transaction_booking_id.desc())\
			 .options(FromCache(db_cache))\
			 .all()

			booking_payments_list = []

			for each_payment in get_all_booking_payments:
				booking_payments = {}
				booking_payments["transaction_original_cost"] = float(
					each_payment.transaction_original_cost)
				booking_payments["transaction_total"] = float(
					each_payment.transaction_total)
				booking_payments["transaction_balance"] = float(
					each_payment.transaction_balance)
				booking_payments[
					"transaction_date"] = each_payment.transaction_date
				booking_payments[
					"payment_method"] = each_payment.payment_method_name

				transaction_payment_currency = requests.get(
					get_currency.format(
						each_payment.transaction_payment_currency))
				transaction_total_currency = requests.get(
					get_currency.format(
						each_payment.transaction_total_currency))

				try:
					booking_payments[
						"transaction_payment_currency"] = transaction_payment_currency.json(
						)["data"][0]["currency_name"]
				except Exception:
					booking_payments[
						"transaction_payment_currency"] = transaction_total_currency.json(
						)["data"][0]["currency_name"]

				booking_payments[
					"transaction_total_currency"] = transaction_total_currency.json(
					)["data"][0]["currency_name"]

				booking_payments["currency"] = transaction_total_currency.json(
				)["data"][0]["currency_name"]

				booking_payments_list.append(booking_payments)

			return_data["booking_payments"] = booking_payments_list

			get_check_in = db.session.query(BookingActivity)\
			 .filter(BookingActivity.deletion_marker == None)\
			 .filter(BookingActivity.booking_id == single.booking_public_id)\
			 .filter(BookingActivity.booking_activity_description == "Booking checked in")\
			 .first()

			if get_check_in:
				user_details = get_details_user(get_check_in.session_id)

				return_data["checked_in"] = True
				return_data["checked_in_by"] = user_details.json(
				)["first_name"] + " " + user_details.json()["last_name"]

			else:
				return_data["checked_in"] = False
				return_data["checked_in_by"] = None

			data.append(return_data)

		db.session.close()
		db.session.commit()

		return jsonify({"data": data}), 200


@app.route("/bookings/view/checked_in", methods=["POST"])
# @bookings_logger.logWrapper()
def view_all_checked_in_bookings():
	messages = []
	try:
		request.json["start_date"].strip()
		if not request.json["start_date"]:
			messages.append("Start date is empty.")
	except KeyError as e:
		messages.append("Start date is missing.")

	try:
		request.json["end_date"].strip()
		if not request.json["end_date"]:
			messages.append("End date is empty.")
	except KeyError as e:
		messages.append("End date is missing.")

	if messages:
		message = []
		message.append("You appear to be missing some data. Please try again.")
		return jsonify({"messages": messages}), 422

	if request.json["end_date"] < request.json["start_date"]:
		output = []
		output.append("The start date cannot come after the end date.")
		return jsonify({"message": output}), 422
	return_bookings = db.session.query(Booking)\
	   .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	   .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	   .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	   .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	 Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	 Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	 Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
	 Booking.currency,\
	 BookingType.booking_type_name,\
	 BookingStatus.booking_status_name)\
	   .filter(Booking.deletion_marker == None)\
	   .filter(Booking.checked_in == 1)\
	   .filter(Booking.checked_out == None)\
	   .filter(Booking.booking_check_in_date >= request.json["start_date"])\
	   .filter(Booking.booking_check_in_date <= request.json["end_date"])\
	   .order_by(Booking.booking_id.desc())\
	   .all()

	if not return_bookings:
		output = []
		output.append(
			"There are currently no checked in bookings in the system.")
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		try:
			return_user = requests.post(get_user_from_aumra,\
			 json = {"users_ids": id_array})
		except (requests.exceptions.ConnectionError,
				requests.exceptions.Timeout,
				requests.exceptions.ConnectTimeout) as connection_error:
			pass

		for single in return_bookings:
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code

			guest_array = []
			guest_sum = []

			get_all_guests = db.session.query(GatepassGuest)\
			   .join(Mandatory, GatepassGuest.gatepass_guest_type == Mandatory.payment_public_id)\
			   .join(Gatepass, GatepassGuest.gatepass_id == Gatepass.gatepass_public_id)\
			   .add_columns(Mandatory.payment_person, Mandatory.payment_public_id,\
			 GatepassGuest.gatepass_guest_count, GatepassGuest.gatepass_discount_rate, GatepassGuest.gatepass_cost_per_pp,\
			 GatepassGuest.gatepass_no_of_nights)\
			   .filter(GatepassGuest.deletion_marker == None)\
			   .filter(Gatepass.booking_id == single.booking_public_id)\
			   .all()

			for each_guest in get_all_guests:
				guest_data = {}
				guest_data["guest_type"] = each_guest.payment_person
				guest_data["no_of_guests"] = each_guest.gatepass_guest_count

				guest_array.append(guest_data)
				guest_sum.append(int(each_guest.gatepass_guest_count))

			return_data["guests"] = guest_array
			return_data["guest_total"] = sum(guest_sum)

			return_data["booking_status"] = single.booking_status_name
			return_data["booking_status_id"] = single.status

			return_data[
				"booking_color"] = "background-color: #2196f3; color: #fff"

			try:
				for user in return_user.json()["data"]:
					if user["public_id"] == single.session_id:
						# return_data["session_user"] = user["first_name"] + " " + user["last_name"]
						return_data["session_user"] = user["full_name"]
						return_data["session_id"] = single.session_id

			except (IndexError, KeyError) as user_error:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			except (AttributeError,
					UnboundLocalError) as network_related_errors:
				return_data["session_user"] = "Network Error"
				return_data["session_id"] = single.session_id

			return_data["session_id"] = single.session_id
			return_data["created_at"] = single.created_at
			return_data["updated_at"] = single.updated_at

			output.append(return_data)

		return jsonify({"data": output}), 200


@app.route("/bookings/view/checked_out", methods=["POST"])
# @bookings_logger.logWrapper()
def view_all_checked_out_bookings():
	messages = []
	try:
		request.json["start_date"].strip()
		if not request.json["start_date"]:
			messages.append("Start date is empty.")
	except KeyError as e:
		messages.append("Start date is missing.")

	try:
		request.json["end_date"].strip()
		if not request.json["end_date"]:
			messages.append("End date is empty.")
	except KeyError as e:
		messages.append("End date is missing.")

	if messages:
		message = []
		message.append("You appear to be missing some data. Please try again.")
		return jsonify({"messages": messages}), 422

	if request.json["end_date"] < request.json["start_date"]:
		output = []
		output.append("The start date cannot come after the end date.")
		return jsonify({"message": output}), 422
	return_bookings = db.session.query(Booking)\
	   .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	   .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	   .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	   .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	 Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	 Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	 Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
	 Booking.currency,\
	 BookingType.booking_type_name,\
	 BookingStatus.booking_status_name)\
	   .filter(Booking.deletion_marker == None)\
	   .filter(Booking.checked_in == 1)\
	   .filter(Booking.checked_out == 1)\
	   .filter(Booking.booking_check_in_date >= request.json["start_date"])\
	   .filter(Booking.booking_check_in_date <= request.json["end_date"])\
	   .order_by(Booking.booking_id.desc())\
	   .all()

	if not return_bookings:
		output = []
		output.append(
			"There are currently no checked out bookings in the system.")
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		try:
			return_user = requests.post(get_user_from_aumra,\
			 json = {"users_ids": id_array})
		except (requests.exceptions.ConnectionError,
				requests.exceptions.Timeout,
				requests.exceptions.ConnectTimeout) as connection_error:
			pass

		for single in return_bookings:
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code

			guest_array = []
			guest_sum = []

			get_all_guests = db.session.query(GatepassGuest)\
			   .join(Mandatory, GatepassGuest.gatepass_guest_type == Mandatory.payment_public_id)\
			   .join(Gatepass, GatepassGuest.gatepass_id == Gatepass.gatepass_public_id)\
			   .add_columns(Mandatory.payment_person, Mandatory.payment_public_id,\
			 GatepassGuest.gatepass_guest_count, GatepassGuest.gatepass_discount_rate, GatepassGuest.gatepass_cost_per_pp,\
			 GatepassGuest.gatepass_no_of_nights)\
			   .filter(GatepassGuest.deletion_marker == None)\
			   .filter(Gatepass.booking_id == single.booking_public_id)\
			   .all()

			for each_guest in get_all_guests:
				guest_data = {}
				guest_data["guest_type"] = each_guest.payment_person
				guest_data["no_of_guests"] = each_guest.gatepass_guest_count

				guest_array.append(guest_data)
				guest_sum.append(int(each_guest.gatepass_guest_count))

			return_data["guests"] = guest_array
			return_data["guest_total"] = sum(guest_sum)

			return_data["booking_status"] = single.booking_status_name
			return_data["booking_status_id"] = single.status

			return_data[
				"booking_color"] = "background-color: #73a533; color: #fff"

			try:
				for user in return_user.json()["data"]:
					if user["public_id"] == single.session_id:
						# return_data["session_user"] = user["first_name"] + " " + user["last_name"]
						return_data["session_user"] = user["full_name"]
						return_data["session_id"] = single.session_id

			except (IndexError, KeyError) as user_error:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			except (AttributeError,
					UnboundLocalError) as network_related_errors:
				return_data["session_user"] = "Network Error"
				return_data["session_id"] = single.session_id

			return_data["session_id"] = single.session_id
			return_data["created_at"] = single.created_at
			return_data["updated_at"] = single.updated_at

			output.append(return_data)

		return jsonify({"data": output}), 200


@app.route("/bookings/view/confirmed", methods=["POST"])
# @bookings_logger.logWrapper()
def view_all_confirmed_bookings():

	messages = []
	try:
		request.json["start_date"].strip()
		if not request.json["start_date"]:
			messages.append("Start date is empty.")
	except KeyError as e:
		messages.append("Start date is missing.")

	try:
		request.json["end_date"].strip()
		if not request.json["end_date"]:
			messages.append("End date is empty.")
	except KeyError as e:
		messages.append("End date is missing.")

	if messages:
		message = []
		message.append("You appear to be missing some data. Please try again.")
		return jsonify({"messages": messages}), 422

	if request.json["end_date"] < request.json["start_date"]:
		output = []
		output.append("The start date cannot come after the end date.")
		return jsonify({"message": output}), 422


	return_bookings = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
	   Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(BookingStatus.booking_status_name=="Confirmed")\
	 .filter(Booking.booking_check_in_date >= request.json["start_date"])\
	 .filter(Booking.booking_check_in_date <= request.json["end_date"])\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	if not return_bookings:
		output = []
		output.append(
			"There are currently no confirmed bookings in the system.")
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		try:
			return_user = requests.post(get_user_from_aumra,\
			 json = {"users_ids": id_array})
		except (requests.exceptions.ConnectionError,
				requests.exceptions.Timeout,
				requests.exceptions.ConnectTimeout) as connection_error:
			pass

		for single in return_bookings:
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code

			guest_array = []
			guest_sum = []

			get_all_guests = db.session.query(BookingGuest)\
			   .join(GuestType, BookingGuest.guest_type == GuestType.booking_guest_type_public_id)\
			   .add_columns(GuestType.booking_guest_type_name,\
			 BookingGuest.guest_count)\
			   .filter(BookingGuest.deletion_marker == None)\
			   .filter(BookingGuest.booking_id == single.booking_public_id)\
			   .all()

			for each_guest in get_all_guests:
				guest_data = {}
				guest_data["guest_type"] = each_guest.booking_guest_type_name
				guest_data["no_of_guests"] = each_guest.guest_count

				guest_array.append(guest_data)
				guest_sum.append(int(each_guest.guest_count))

			return_data["guests"] = guest_array
			return_data["guest_total"] = sum(guest_sum)

			return_data["booking_status"] = single.booking_status_name
			return_data["booking_status_id"] = single.status

			return_data[
				"booking_color"] = "background-color: #fff; color: #000000"

			try:
				for user in return_user.json()["data"]:
					if user["public_id"] == single.session_id:
						# return_data["session_user"] = user["first_name"] + " " + user["last_name"]
						return_data["session_user"] = user["full_name"]
						return_data["session_id"] = single.session_id

			except (IndexError, KeyError) as user_error:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			except (AttributeError,
					UnboundLocalError) as network_related_errors:
				return_data["session_user"] = "Network Error"
				return_data["session_id"] = single.session_id

			return_data["session_id"] = single.session_id
			return_data["created_at"] = single.created_at
			return_data["updated_at"] = single.updated_at

			output.append(return_data)

		return jsonify({"data": output}), 200


# @app.route("/bookings/view/confirmed")
# # @bookings_logger.logWrapper()
# def view_all_confirmed_bookings():
# 	if db.session.query(BookingStatus)\
# 	 .filter(BookingStatus.deletion_marker==None)\
# 	 .filter(BookingStatus.booking_status_public_id == "3b5376e0-a4dc-476e-aebc-6280b44b756a")\
# 	 .count() == 0:
# 		BookingStatusSeed.seed_default_booking_status()

# 	return_bookings = db.session.query(Booking)\
# 	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
# 	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
# 	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
# 	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
# 	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
# 	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
# 	  Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
# 	   Booking.currency,\
# 	  BookingType.booking_type_name,\
# 	  BookingStatus.booking_status_name)\
# 	 .filter(Booking.deletion_marker == None)\
# 	 .filter(BookingStatus.booking_status_name=="Confirmed")\
# 	 .order_by(Booking.booking_id.desc())\
# 	 .all()

# 	if not return_bookings:
# 		output = []
# 		output.append(
# 			"There are currently no confirmed bookings in the system.")
# 		return jsonify({"message": output}), 200
# 	else:
# 		output = []
# 		id_array = []

# 		for each_id in return_bookings:
# 			id_array.append(each_id.session_id)

# 		try:
# 			return_user = requests.post(get_user_from_aumra,\
# 			 json = {"users_ids": id_array})
# 		except (requests.exceptions.ConnectionError,
# 				requests.exceptions.Timeout,
# 				requests.exceptions.ConnectTimeout) as connection_error:
# 			pass

# 		for single in return_bookings:
# 			return_data = {}
# 			return_data["booking_public_id"] = single.booking_public_id
# 			return_data["booking_type"] = single.booking_type_name
# 			return_data["booking_type_id"] = single.booking_type
# 			return_data["booking_check_in_date"] = single.booking_check_in_date
# 			return_data[
# 				"booking_check_out_date"] = single.booking_check_out_date
# 			return_data["booking_done_by"] = single.booking_done_by
# 			return_data["booking_ref_code"] = single.booking_ref_code

# 			guest_array = []
# 			guest_sum = []

# 			get_all_guests = db.session.query(BookingGuest)\
# 			   .join(GuestType, BookingGuest.guest_type == GuestType.booking_guest_type_public_id)\
# 			   .add_columns(GuestType.booking_guest_type_name,\
# 			 BookingGuest.guest_count)\
# 			   .filter(BookingGuest.deletion_marker == None)\
# 			   .filter(BookingGuest.booking_id == single.booking_public_id)\
# 			   .all()

# 			for each_guest in get_all_guests:
# 				guest_data = {}
# 				guest_data["guest_type"] = each_guest.booking_guest_type_name
# 				guest_data["no_of_guests"] = each_guest.guest_count

# 				guest_array.append(guest_data)
# 				guest_sum.append(int(each_guest.guest_count))

# 			return_data["guests"] = guest_array
# 			return_data["guest_total"] = sum(guest_sum)

# 			return_data["booking_status"] = single.booking_status_name
# 			return_data["booking_status_id"] = single.status

# 			return_data[
# 				"booking_color"] = "background-color: #fff; color: #000000"

# 			try:
# 				for user in return_user.json()["data"]:
# 					if user["public_id"] == single.session_id:
# 						# return_data["session_user"] = user["first_name"] + " " + user["last_name"]
# 						return_data["session_user"] = user["full_name"]
# 						return_data["session_id"] = single.session_id

# 			except (IndexError, KeyError) as user_error:
# 				return_data["session_user"] = "N/A"
# 				return_data["session_id"] = single.session_id

# 			except (AttributeError,
# 					UnboundLocalError) as network_related_errors:
# 				return_data["session_user"] = "Network Error"
# 				return_data["session_id"] = single.session_id

# 			return_data["session_id"] = single.session_id
# 			return_data["created_at"] = single.created_at
# 			return_data["updated_at"] = single.updated_at

# 			output.append(return_data)

# 		return jsonify({"data": output}), 200


@app.route("/bookings/view/unconfirmed", methods=["POST"])
# @bookings_logger.logWrapper()
def view_all_unconfirmed_bookings():
	messages = []
	try:
		request.json["start_date"].strip()
		if not request.json["start_date"]:
			messages.append("Start date is empty.")
	except KeyError as e:
		messages.append("Start date is missing.")

	try:
		request.json["end_date"].strip()
		if not request.json["end_date"]:
			messages.append("End date is empty.")
	except KeyError as e:
		messages.append("End date is missing.")

	if messages:
		message = []
		message.append("You appear to be missing some data. Please try again.")
		return jsonify({"messages": messages}), 422

	if request.json["end_date"] < request.json["start_date"]:
		output = []
		output.append("The start date cannot come after the end date.")
		return jsonify({"message": output}), 422
	return_bookings = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
	   Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(BookingStatus.booking_status_name=="Unconfirmed")\
	 .filter(Booking.booking_check_in_date >= request.json["start_date"])\
	 .filter(Booking.booking_check_in_date <= request.json["end_date"])\
	 .order_by(Booking.booking_id.desc())\
	 .all()
	if not return_bookings:
		output = []
		output.append(
			"There are currently no unconfirmed bookings between the given dates in the system."
		)
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		try:
			return_user = requests.post(get_user_from_aumra,\
			 json = {"users_ids": id_array})
		except (requests.exceptions.ConnectionError,
				requests.exceptions.Timeout,
				requests.exceptions.ConnectTimeout) as connection_error:
			pass

		for single in return_bookings:
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code

			guest_array = []
			guest_sum = []

			get_all_guests = db.session.query(BookingGuest)\
			   .join(GuestType, BookingGuest.guest_type == GuestType.booking_guest_type_public_id)\
			   .add_columns(GuestType.booking_guest_type_name,\
			 BookingGuest.guest_count)\
			   .filter(BookingGuest.deletion_marker == None)\
			   .filter(BookingGuest.booking_id == single.booking_public_id)\
			   .all()

			for each_guest in get_all_guests:
				guest_data = {}
				guest_data["guest_type"] = each_guest.booking_guest_type_name
				guest_data["no_of_guests"] = each_guest.guest_count

				guest_array.append(guest_data)
				guest_sum.append(int(each_guest.guest_count))

			return_data["guests"] = guest_array
			return_data["guest_total"] = sum(guest_sum)

			return_data["booking_status"] = single.booking_status_name
			return_data["booking_status_id"] = single.status

			return_data[
				"booking_color"] = "background-color: #fff; color: #000000"

			try:
				for user in return_user.json()["data"]:
					if user["public_id"] == single.session_id:
						# return_data["session_user"] = user["first_name"] + " " + user["last_name"]
						return_data["session_user"] = user["full_name"]
						return_data["session_id"] = single.session_id

			except (IndexError, KeyError) as user_error:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			except (AttributeError,
					UnboundLocalError) as network_related_errors:
				return_data["session_user"] = "Network Error"
				return_data["session_id"] = single.session_id

			return_data["session_id"] = single.session_id
			return_data["created_at"] = single.created_at
			return_data["updated_at"] = single.updated_at

			output.append(return_data)

		return jsonify({"data": output}), 200


@app.route("/bookings/view/check_in/today")
# @bookings_logger.logWrapper()
def view_all_bookings_to_check_in_today():
	now = datetime.now()
	today = now.strftime("%Y-%m-%d")
	yesterday_datetime = datetime.today() - timedelta(days=1)
	yesterday = yesterday_datetime.strftime("%Y-%m-%d")

	return_bookings = db.session.query(Booking)\
	 .outerjoin(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.payment_status, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
	   Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(Booking.booking_check_in_date == today)\
	 .filter(Booking.checked_out == None)\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	return_yesterday_bookings = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.payment_status, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
	   Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(Booking.booking_check_in_date == yesterday)\
	 .filter(Booking.checked_in == None)\
	 .filter(Booking.status != '3216010b-7c03-48b4-b82e-6c8ea5e3096b')\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	if len(return_yesterday_bookings) > 0:
		for return_yesterday_booking in return_yesterday_bookings:
			return_bookings.append(return_yesterday_booking)

	if not return_bookings:
		output = []
		output.append(
			"There are currently no bookings to be checked in today.")
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		try:
			return_user = requests.post(get_user_from_aumra,\
			 json = {"users_ids": id_array})
		except (requests.exceptions.ConnectionError,
				requests.exceptions.Timeout,
				requests.exceptions.ConnectTimeout) as connection_error:
			pass

		for single in return_bookings:
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["booking_ref_code"] = single.booking_ref_code
			if single.payment_status == 1:
				return_data["booking_payment_status"] = "Paid"
			if single.payment_status == 2:
				return_data["booking_payment_status"] = "Incomplete Payment"
			if single.payment_status == 3:
				return_data["booking_payment_status"] = "Complimentary"
			if single.payment_status == 4:
				return_data["booking_payment_status"] = "To Invoice"
			elif not single.payment_status:
				return_data["booking_payment_status"] = "Not Paid"
			check_school_booking = db.session.query(SchoolBooking)\
			   .join(School, SchoolBooking.school_id == School.school_public_id)\
			   .add_columns(School.school_name)\
			   .filter(SchoolBooking.deletion_marker == None)\
			   .filter(SchoolBooking.booking_id == single.booking_public_id)\
			   .first()

			check_org_booking = db.session.query(Group)\
			   .filter(Group.deletion_marker == None)\
			   .filter(Group.booking_id == single.booking_public_id)\
			   .first()

			try:
				if check_school_booking:
					return_data[
						"booking_done_by"] = check_school_booking.school_name
				elif check_org_booking:
					return_data[
						"booking_done_by"] = check_org_booking.organisation_name
				else:
					return_data["booking_done_by"] = single.booking_done_by

			except Exception:
				return_data["booking_done_by"] = single.booking_done_by

			if single.checked_in == None:
				return_data["booking_check_in_status"] = "Checking In"
				return_data[
					"booking_color"] = "background-color: #0084ff; color: #fff"
			elif single.checked_in == 1:
				return_data["booking_check_in_status"] = "Checked In"
				return_data[
					"booking_color"] = "background-color: #2ecc71; color: #fff"

			return_data["booking_check_out_status"] = "Not Checked Out"

			guest_array = []
			guest_sum = []

			get_all_guests = db.session.query(GatepassGuest)\
			   .join(Mandatory, GatepassGuest.gatepass_guest_type == Mandatory.payment_public_id)\
			   .join(Gatepass, GatepassGuest.gatepass_id == Gatepass.gatepass_public_id)\
			   .add_columns(Mandatory.payment_person, Mandatory.payment_public_id,\
			 GatepassGuest.gatepass_guest_count, GatepassGuest.gatepass_discount_rate, GatepassGuest.gatepass_cost_per_pp,\
			 GatepassGuest.gatepass_no_of_nights)\
			   .filter(GatepassGuest.deletion_marker == None)\
			   .filter(GatepassGuest.status != get_booking_status_id("Updated"))\
			   .filter(Gatepass.booking_id == single.booking_public_id)\
			   .options(FromCache(db_cache))\
			   .all()

			for each_guest in get_all_guests:
				guest_data = {}
				guest_data["guest_type"] = each_guest.payment_person
				guest_data["no_of_guests"] = each_guest.gatepass_guest_count

				guest_array.append(guest_data)
				guest_sum.append(int(each_guest.gatepass_guest_count))

			return_data["guests"] = guest_array
			return_data["guest_total"] = sum(guest_sum)

			return_data["booking_status"] = single.booking_status_name
			return_data["booking_status_id"] = single.status

			try:
				for user in return_user.json()["data"]:
					if user["public_id"] == single.session_id:
						# return_data["session_user"] = user["first_name"] + " " + user["last_name"]
						return_data["session_user"] = user["full_name"]
						return_data["session_id"] = single.session_id

			except (IndexError, KeyError) as user_error:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			except (AttributeError,
					UnboundLocalError) as network_related_errors:
				return_data["session_user"] = "Network Error"
				return_data["session_id"] = single.session_id

			return_data["session_id"] = single.session_id
			return_data["created_at"] = single.created_at
			return_data["updated_at"] = single.updated_at

			check_in_vehicle = db.session.query(CheckInVehicle)\
			 .add_columns(CheckInVehicle.booking_id, CheckInVehicle.check_vehicle_driver, CheckInVehicle.check_vehicle_reg)\
			 .filter(CheckInVehicle.booking_id == single.booking_public_id)\
			 .all()

			if len(check_in_vehicle) == 0:
				return_data["vehicle_registration"] = ''
			else:
				vehicle_str = ''
				for vehicle in check_in_vehicle:
					vehicle_reg = vehicle.check_vehicle_reg
					vehicle_str += vehicle_reg + ','
				return_data["vehicle_registration"] = vehicle_str

			output.append(return_data)

		return jsonify({"data": output}), 200


@app.route("/bookings/view/inspection")
# @bookings_logger.logWrapper()
def view_all_bookings_inspection():

	now = datetime.now()
	today = now.strftime("%Y-%m-%d")


	return_bookings = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
	   Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(Booking.booking_check_in_date == today)\
	 .filter(Booking.checked_out == None)\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	if not return_bookings:
		output = []
		output.append("There are currently no bookings to be inspected today.")
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		for single in return_bookings:
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["created_at"] = single.created_at

			if single.checked_in == None:
				return_data["booking_check_in_status"] = "Checking In"
				return_data[
					"booking_color"] = "background-color: #0084ff; color: #fff"
			elif single.checked_in == 1:
				return_data["booking_check_in_status"] = "Checked In"
				return_data[
					"booking_color"] = "background-color: #2ecc71; color: #fff"

			return_data["booking_ref_code"] = single.booking_ref_code

			if return_data["booking_type_id"] == '8D7E6504':
				check_school_booking = db.session.query(SchoolBooking)\
				 .join(School, SchoolBooking.school_id == School.school_public_id)\
				 .add_columns(School.school_name)\
				 .filter(SchoolBooking.booking_id == single.booking_public_id)\
				 .first()
				return_data[
					"booking_done_by"] = check_school_booking.school_name
			elif return_data["booking_type_id"] == 'C3237489':
				check_org_booking = db.session.query(Group)\
				 .filter(Group.booking_id == single.booking_public_id)\
				 .first()
				return_data[
					"booking_done_by"] = check_org_booking.organisation_name
			else:
				return_data["booking_done_by"] = single.booking_done_by

			guest_array = []
			guest_sum = []

			get_all_guests = db.session.query(GatepassGuest)\
			   .join(Mandatory, GatepassGuest.gatepass_guest_type == Mandatory.payment_public_id)\
			   .join(Gatepass, GatepassGuest.gatepass_id == Gatepass.gatepass_public_id)\
			   .add_columns(Mandatory.payment_person, Mandatory.payment_public_id,\
			 GatepassGuest.gatepass_guest_count, GatepassGuest.gatepass_discount_rate, GatepassGuest.gatepass_cost_per_pp,\
			 GatepassGuest.gatepass_no_of_nights)\
			   .filter(GatepassGuest.deletion_marker == None)\
			   .filter(GatepassGuest.status != get_booking_status_id("Updated"))\
			   .filter(Gatepass.booking_id == single.booking_public_id)\
			   .options(FromCache(db_cache))\
			   .all()

			check_in_vehicle = db.session.query(CheckInVehicle)\
			 .add_columns(CheckInVehicle.booking_id, CheckInVehicle.check_vehicle_driver, CheckInVehicle.check_vehicle_reg)\
			 .filter(CheckInVehicle.booking_id == return_data["booking_public_id"])\
			 .all()

			if len(check_in_vehicle) == 0:
				return_data["vehicle_registration"] = ''
				return_data["driver_name"] = ''
			else:
				vehicle_str = ''
				driver_str = ''
				for vehicle in check_in_vehicle:
					vehicle_reg = vehicle.check_vehicle_reg
					driver_name = vehicle.check_vehicle_driver
					vehicle_str += vehicle_reg + ','
					driver_str += driver_name + ','

				return_data["vehicle_registration"] = vehicle_str
				return_data["driver_name"] = driver_str

			for each_guest in get_all_guests:
				guest_data = {}
				# guest_data["guest_type"] = each_guest.payment_person
				guest_data["no_of_guests"] = each_guest.gatepass_guest_count

				guest_array.append(guest_data)
				guest_sum.append(int(each_guest.gatepass_guest_count))

			return_data["guests"] = guest_array
			return_data["guest_total"] = sum(guest_sum)

			return_data["booking_status"] = single.booking_status_name
			get_ranger_notes = db.session.query(Note)\
			 .filter(Note.deletion_marker == None)\
			 .filter(Note.ranger_note == 1)\
			 .filter(Note.booking_id == single.booking_public_id)\
			 .options(FromCache(db_cache))\
			 .all()

			alert_arr = []
			if not get_ranger_notes:
				return_data["inspect_alert_status"] = 'Not Inspected'
				return_data[
					"booking_color"] = "background-color: #f0932b; color: #fff"

			else:
				for single_note in get_ranger_notes:
					alert = single_note.alert
					if alert:
						alert_arr.append(1)

				if 1 in alert_arr:
					return_data["inspect_alert_status"] = 'Alert'
					return_data[
						"booking_color"] = "background-color: #e74c3c; color: #fff"

				else:
					return_data["inspect_alert_status"] = 'Okay'
					return_data[
						"booking_color"] = "background-color: #73a533; color: #fff"

			output.append(return_data)
		return jsonify({"data": output}), 200


@app.route("/bookings/view/inpected-alerted")
# @bookings_logger.logWrapper()
def view_all_bookings_alert():
	try:
		page = int(request.args["page"])
	except Exception:
		page = 1

	try:
		items = int(request.args["items"])
	except Exception:
		items = 50

	if page == 0:
		get_ranger_notes = db.session.query(Note)\
		 .add_columns(Note.session_id,Note.alert,Note.booking_id,Note.note,Note.update_note,Note.booking_notes_public_id,Note.created_at)\
		 .filter(Note.deletion_marker == None)\
		 .filter(Note.ranger_note == 1)\
		 .filter(Note.update_note == None)\
		 .order_by(Note.created_at.desc())\
		 .options(FromCache(db_cache))\
		 .all()
	else:
		get_ranger_notes = db.session.query(Note)\
		 .add_columns(Note.session_id,Note.alert,Note.booking_id,Note.note,Note.update_note,Note.booking_notes_public_id,Note.created_at)\
		 .filter(Note.deletion_marker == None)\
		 .filter(Note.ranger_note == 1)\
		 .filter(Note.update_note == None)\
		 .order_by(Note.created_at.desc())\
		 .options(FromCache(db_cache))\
		 .paginate(page, items, False)\
		 .items
	output = []
	if not set(get_ranger_notes):
		message = []
		message.append("The search did not return any results.")
		return jsonify({"message": message}), 412
	else:
		for note in get_ranger_notes:
			return_booking = db.session.query(Booking)\
			  .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
			  .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
			  .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
			  .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
			  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
			  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
			  Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
			  Booking.currency,\
			  BookingType.booking_type_name,\
			  BookingStatus.booking_status_name)\
			  .filter(Booking.booking_public_id == note.booking_id)\
			  .order_by(Booking.created_at.desc())\
			  .first()

			if not return_booking:
				output = []
				output.append("There are currently no bookings.")
				return jsonify({"message": output}), 200
			else:

				return_data = {}
				user_info = {}
				try:
					getBookingSessionUser(note.session_id, user_info)
					return_data["session_user"] = user_info["session_user"]
					return_data["session_id"] = user_info["session_id"]
				except Exception as e:
					return_data["session_user"] = ''
					return_data["session_id"] = ''

				return_data["note_public_id"] = note.booking_notes_public_id
				return_data["note"] = note.note
				return_data["created_at"] = note.created_at

				get_ranger_note_updates = db.session.query(Note)\
				 .add_columns(Note.session_id,Note.alert,Note.booking_id,Note.note,Note.update_note,Note.booking_notes_public_id,Note.created_at)\
				 .filter(Note.deletion_marker == None)\
				 .filter(Note.ranger_note == 1)\
				 .filter(Note.update_note == note.booking_notes_public_id)\
				 .order_by(Note.created_at.desc())\
				 .options(FromCache(db_cache))\
				 .all()

				if len(get_ranger_note_updates) > 0:
					return_data["action_taken"] = 'Yes'
					update_ranger_notes = []
					for update_note in get_ranger_note_updates:
						update_ranger_note_ob = {}
						update_ranger_note_ob["note"] = note.note
						update_ranger_note_ob[
							"alert_update"] = update_note.note
						update_ranger_note_ob[
							"created_at"] = update_note.created_at
						update_ranger_note_ob[
							"update_note"] = update_note.update_note
						user_info_update = {}
						try:
							getBookingSessionUser(update_note.session_id,
												  user_info_update)
							update_ranger_note_ob[
								"session_user"] = user_info_update[
									"session_user"]
							update_ranger_note_ob[
								"session_id"] = user_info_update["session_id"]
						except Exception as e:
							update_ranger_note_ob["session_user"] = ''
							update_ranger_note_ob["session_id"] = ''
						update_ranger_notes.append(update_ranger_note_ob)

					return_data["update_notes"] = update_ranger_notes
				else:
					return_data["update_notes"] = ''
					return_data["action_taken"] = 'No'

				alert = note.alert
				return_data["alert"] = alert
				if alert:
					return_data[
						"booking_color"] = "background-color: #e74c3c; color: #fff"
				else:
					return_data[
						"booking_color"] = "background-color: #73a533; color: #fff"

				return_data[
					"booking_public_id"] = return_booking.booking_public_id
				return_data["booking_type"] = return_booking.booking_type_name
				return_data["booking_type_id"] = return_booking.booking_type
				return_data[
					"booking_check_in_date"] = return_booking.booking_check_in_date
				return_data[
					"booking_check_out_date"] = return_booking.booking_check_out_date
				return_data[
					"booking_ref_code"] = return_booking.booking_ref_code

				if return_data["booking_type_id"] == '8D7E6504':
					check_school_booking = db.session.query(SchoolBooking)\
					.join(School, SchoolBooking.school_id == School.school_public_id)\
					.add_columns(School.school_name)\
					.filter(SchoolBooking.booking_id == return_booking.booking_public_id)\
					.first()
					return_data[
						"booking_done_by"] = check_school_booking.school_name
				elif return_data["booking_type_id"] == 'C3237489':
					check_org_booking = db.session.query(Group)\
					.filter(Group.booking_id == return_booking.booking_public_id)\
					.first()
					return_data[
						"booking_done_by"] = check_org_booking.organisation_name
				else:
					return_data[
						"booking_done_by"] = return_booking.booking_done_by

				guest_array = []
				guest_sum = []

				get_all_guests = db.session.query(GatepassGuest)\
				.join(Mandatory, GatepassGuest.gatepass_guest_type == Mandatory.payment_public_id)\
				.join(Gatepass, GatepassGuest.gatepass_id == Gatepass.gatepass_public_id)\
				.add_columns(Mandatory.payment_person, Mandatory.payment_public_id,\
				GatepassGuest.gatepass_guest_count, GatepassGuest.gatepass_discount_rate, GatepassGuest.gatepass_cost_per_pp,\
				GatepassGuest.gatepass_no_of_nights)\
				.filter(GatepassGuest.deletion_marker == None)\
				.filter(GatepassGuest.status != get_booking_status_id("Updated"))\
				.filter(Gatepass.booking_id == return_booking.booking_public_id)\
				.options(FromCache(db_cache))\
				.all()

				check_in_vehicle = db.session.query(CheckInVehicle)\
				.add_columns(CheckInVehicle.booking_id, CheckInVehicle.check_vehicle_driver, CheckInVehicle.check_vehicle_reg)\
				.filter(CheckInVehicle.booking_id == return_data["booking_public_id"])\
				.all()

				if len(check_in_vehicle) == 0:
					return_data["vehicle_registration"] = ''
					return_data["driver_name"] = ''
				else:
					vehicle_str = ''
					driver_str = ''
					for vehicle in check_in_vehicle:
						vehicle_reg = vehicle.check_vehicle_reg
						driver_name = vehicle.check_vehicle_driver
						vehicle_str += vehicle_reg + ','
						driver_str += driver_name + ','

					return_data["vehicle_registration"] = vehicle_str
					return_data["driver_name"] = driver_str

				for each_guest in get_all_guests:
					guest_data = {}
					guest_data[
						"no_of_guests"] = each_guest.gatepass_guest_count
					guest_array.append(guest_data)
					guest_sum.append(int(each_guest.gatepass_guest_count))

				return_data["guests"] = guest_array
				return_data["guest_total"] = sum(guest_sum)
				return_data[
					"booking_status"] = return_booking.booking_status_name
				output.append(return_data)

		return jsonify({"data": output}), 200


@app.route("/bookings/view/inpected-unticketed-alerted")
# @bookings_logger.logWrapper()
def view_all_bookings_unticketed_alert():
    try:
        page = int(request.args["page"])
    except Exception:
        page = 1

    try:
        items = int(request.args["items"])
    except Exception:
        items = 50

    if page == 0:
        get_ranger_notes = db.session.query(Note)\
         .add_columns(Note.session_id, Note.alert, Note.note, Note.booking_id, 
                     Note.vehicle_reg, Note.destination, Note.update_note, 
                     Note.booking_notes_public_id, Note.created_at, Note.adult, 
                     Note.children, Note.infants, Note.guide, Note.gate, 
                     Note.name, Note.vehicle_type)\
         .filter(Note.deletion_marker == None)\
         .filter(Note.ranger_note == 2)\
         .filter(Note.update_note == None)\
         .filter(Note.booking_id == None)\
         .order_by(Note.created_at.desc())\
         .options(FromCache(db_cache))\
         .all()
    else:
        get_ranger_notes = db.session.query(Note)\
         .add_columns(Note.session_id, Note.alert, Note.booking_id, Note.vehicle_reg, 
                     Note.destination, Note.note, Note.update_note, 
                     Note.booking_notes_public_id, Note.created_at, Note.adult, 
                     Note.children, Note.infants, Note.guide, Note.gate,
                     Note.name, Note.vehicle_type)\
         .filter(Note.deletion_marker == None)\
         .filter(Note.ranger_note == 2)\
         .filter(Note.update_note == None)\
         .filter(Note.booking_id == None)\
         .order_by(Note.created_at.desc())\
         .options(FromCache(db_cache))\
         .paginate(page, items, False)\
         .items
    
    output = []
    if not get_ranger_notes:
        message = []
        message.append("The search did not return any results.")
        return jsonify({"message": message}), 412
    else:
        for result in get_ranger_notes:
            # Extract the Note object from the result tuple
            note = result[0]  # The first element is the Note object
            return_data = {}
            user_info = {}
            try:
                getBookingSessionUser(result.session_id, user_info)
                return_data["session_user"] = user_info["session_user"]
                return_data["session_id"] = user_info["session_id"]
            except Exception as e:
                return_data["session_user"] = ''
                return_data["session_id"] = ''

            return_data["note_public_id"] = note.booking_notes_public_id
            return_data["note"] = note.note
            return_data["created_at"] = note.created_at
            
            try:
                destination_db = db.session.query(Destination)\
                   .filter(Destination.gatepass_destination_public_id == note.destination)\
                   .options(FromCache(db_cache))\
                   .first()

                destination_name = destination_db.gatepass_destination_name
                return_data["destination"] = destination_name
            except Exception as e:
                return_data["destination"] = ''
            
            try:
                gate_db = db.session.query(Gate)\
                   .filter(Gate.gate_public_id == note.gate)\
                   .options(FromCache(db_cache))\
                   .first()

                gate_name = gate_db.gate_name
                return_data["gate"] = gate_name
            except Exception as e:
                return_data["gate"] = ''
                
            # Get vehicle type name from Vehicle table using vehicle_charge_public_id
            try:
                if note.vehicle_type:
                    vehicle_db = db.session.query(Vehicle)\
                       .filter(Vehicle.vehicle_charge_public_id == note.vehicle_type)\
                       .options(FromCache(db_cache))\
                       .first()
                    
                    if vehicle_db:
                        vehicle_type_name = vehicle_db.vehicle_charge_category
                    else:
                        vehicle_type_name = ''
                else:
                    vehicle_type_name = ''
            except Exception as e:
                vehicle_type_name = ''

            alert = note.alert
            
            if note.infants is None:
                infants = 0
            else:
                infants = note.infants

            if note.guide is None:
                guide = 0
            else:
                guide = note.guide

            return_data["alert"] = alert
            return_data["infants"] = infants
            return_data["guide"] = guide
            
            return_data["vehicle_registration"] = note.vehicle_reg
            return_data["name"] = note.name or ''
            return_data["vehicle_type"] = vehicle_type_name  # Use the resolved vehicle type name
            
            if note.adult is None:
                adult_number = 0
            else:
                adult_number = note.adult
                
            if note.children is None:
                children_number = 0
            else:
                children_number = note.children

            return_data["adult"] = adult_number
            return_data["children"] = children_number

            get_ranger_update_notes = db.session.query(Note)\
            .add_columns(Note.session_id, Note.alert, Note.booking_id, Note.vehicle_reg, 
                        Note.destination, Note.note, Note.update_note, 
                        Note.booking_notes_public_id, Note.created_at, Note.adult, Note.children)\
            .filter(Note.deletion_marker == None)\
            .filter(Note.ranger_note == 1)\
            .filter(Note.update_note == return_data["note_public_id"])\
            .filter(Note.booking_id != None)\
            .all()
            
            if len(get_ranger_update_notes) > 0:
                return_data["action_taken"] = 'Yes'
                return_data["booking_color"] = "background-color: #73a533; color: #fff"
                update_ranger_notes = []
                update_bookings = []
                
                for update_result in get_ranger_update_notes:
                    update_note = update_result[0]  # Extract Note object from result
                    update_ranger_note_ob = {}
                    update_ranger_note_ob["note"] = update_note.note
                    update_ranger_note_ob["alert_update"] = update_note.note
                    update_ranger_note_ob["created_at"] = update_note.created_at
                    update_ranger_note_ob["update_note"] = update_note.update_note

                    user_info_update = {}
                    try:
                        getBookingSessionUser(update_result.session_id, user_info_update)
                        update_ranger_note_ob["session_user"] = user_info_update["session_user"]
                        update_ranger_note_ob["session_id"] = user_info_update["session_id"]
                    except Exception as e:
                        update_ranger_note_ob["session_user"] = ''
                        update_ranger_note_ob["session_id"] = ''
                    
                    try:
                        return_booking = db.session.query(Booking)\
                        .filter(Booking.booking_public_id == update_note.booking_id)\
                        .first()

                        booking_ref_code = return_booking.booking_ref_code
                        booking_public_id = return_booking.booking_public_id

                        update_ranger_note_ob["booking_ref_code"] = booking_ref_code
                        update_ranger_note_ob["booking_public_id"] = booking_public_id
                    except Exception as e:
                        update_ranger_note_ob["booking_ref_code"] = ''
                        update_ranger_note_ob["booking_public_id"] = ''

                    update_ranger_notes.append(update_ranger_note_ob)
                    booking_data = {
                        "booking_ref_code": booking_ref_code,
                        "booking_public_id": booking_public_id
                    }
                    update_bookings.append(booking_data)

                return_data["update_bookings"] = update_bookings
                return_data["update_notes"] = update_ranger_notes
            else:
                return_data["update_notes"] = ''
                return_data["action_taken"] = 'No'
                return_data["booking_color"] = "background-color: #e74c3c; color: #fff"

            output.append(return_data)

        return jsonify({"data": output}), 200


@app.route("/bookings/view/check_out/today")
# @bookings_logger.logWrapper()
def view_all_bookings_to_check_out_today():
	now = datetime.now()
	today = now.strftime("%Y-%m-%d")
	yesterday_datetime = datetime.today() - timedelta(days=1)
	yesterday = yesterday_datetime.strftime("%Y-%m-%d")

	return_bookings = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status,Booking.payment_status, Booking.booking_ref_code,\
	   Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(Booking.booking_check_out_date == today)\
	 .filter(Booking.checked_in == 1)\
	 .filter(Booking.checked_out == None)\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	return_yesterday_bookings = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.payment_status, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status,Booking.payment_status, Booking.booking_ref_code,\
	   Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(Booking.booking_check_out_date == yesterday)\
	 .filter(Booking.checked_out == None)\
	 .filter(Booking.status != '3216010b-7c03-48b4-b82e-6c8ea5e3096b')\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	if len(return_yesterday_bookings) > 0:
		for return_yesterday_booking in return_yesterday_bookings:
			return_bookings.append(return_yesterday_booking)

	if not return_bookings:
		output = []
		output.append(
			"There are currently no bookings to be checked out today.")
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		try:
			return_user = requests.post(get_user_from_aumra,\
			 json = {"users_ids": id_array})
		except (requests.exceptions.ConnectionError,
				requests.exceptions.Timeout,
				requests.exceptions.ConnectTimeout) as connection_error:
			pass

		for single in return_bookings:
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["booking_ref_code"] = single.booking_ref_code
			if single.payment_status == 1:
				return_data["booking_payment_status"] = "Paid"
			if single.payment_status == 2:
				return_data["booking_payment_status"] = "Incomplete Payment"
			if single.payment_status == 3:
				return_data["booking_payment_status"] = "Complimentary"
			if single.payment_status == 4:
				return_data["booking_payment_status"] = "To Invoice"
			elif not single.payment_status:
				return_data["booking_payment_status"] = "Not Paid"
			check_school_booking = db.session.query(SchoolBooking)\
			   .join(School, SchoolBooking.school_id == School.school_public_id)\
			   .add_columns(School.school_name)\
			   .filter(SchoolBooking.deletion_marker == None)\
			   .filter(SchoolBooking.booking_id == single.booking_public_id)\
			   .first()

			check_org_booking = db.session.query(Group)\
			   .filter(Group.deletion_marker == None)\
			   .filter(Group.booking_id == single.booking_public_id)\
			   .first()

			try:
				if check_school_booking:
					return_data[
						"booking_done_by"] = check_school_booking.school_name
				elif check_org_booking:
					return_data[
						"booking_done_by"] = check_org_booking.organisation_name
				else:
					return_data["booking_done_by"] = single.booking_done_by

			except Exception:
				return_data["booking_done_by"] = single.booking_done_by

			if single.checked_out == None:
				return_data["booking_check_out_status"] = "Checking Out"
				return_data[
					"booking_color"] = "background-color: #9b59b6; color: #fff"
			elif single.checked_out == 1:
				return_data["booking_check_out_status"] = "Checked Out"
				return_data[
					"booking_color"] = "background-color: #e74c3c; color: #fff"

			guest_array = []
			guest_sum = []

			get_all_guests = db.session.query(GatepassGuest)\
			   .join(Mandatory, GatepassGuest.gatepass_guest_type == Mandatory.payment_public_id)\
			   .join(Gatepass, GatepassGuest.gatepass_id == Gatepass.gatepass_public_id)\
			   .add_columns(Mandatory.payment_person, Mandatory.payment_public_id,\
			 GatepassGuest.gatepass_guest_count, GatepassGuest.gatepass_discount_rate, GatepassGuest.gatepass_cost_per_pp,\
			 GatepassGuest.gatepass_no_of_nights)\
			   .filter(GatepassGuest.deletion_marker == None)\
			   .filter(GatepassGuest.status != get_booking_status_id("Updated"))\
			   .filter(Gatepass.booking_id == single.booking_public_id)\
			   .options(FromCache(db_cache))\
			   .all()

			for each_guest in get_all_guests:
				guest_data = {}
				guest_data["guest_type"] = each_guest.payment_person
				guest_data["no_of_guests"] = each_guest.gatepass_guest_count

				guest_array.append(guest_data)
				guest_sum.append(int(each_guest.gatepass_guest_count))

			return_data["guests"] = guest_array
			return_data["guest_total"] = sum(guest_sum)

			return_data["booking_status"] = single.booking_status_name
			return_data["booking_status_id"] = single.status
			payment_status = single.payment_status
			if payment_status == 1:
				return_data["payment_status"] = 'PAID'
			elif payment_status == 2:
				return_data["payment_status"] = 'DEPOSIT'

			elif payment_status == 3:
				return_data["payment_status"] = 'COMPLIMENTARY'
			elif payment_status == 4:
				return_data["payment_status"] = 'TO INVOICE'

			else:
				return_data["payment_status"] = 'NOT PAID'

			try:
				for user in return_user.json()["data"]:
					if user["public_id"] == single.session_id:
						# return_data["session_user"] = user["first_name"] + " " + user["last_name"]
						return_data["session_user"] = user["full_name"]
						return_data["session_id"] = single.session_id

			except (IndexError, KeyError) as user_error:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			except (AttributeError,
					UnboundLocalError) as network_related_errors:
				return_data["session_user"] = "Network Error"
				return_data["session_id"] = single.session_id

			return_data["session_id"] = single.session_id
			return_data["created_at"] = single.created_at
			return_data["updated_at"] = single.updated_at
			check_in_vehicle = db.session.query(CheckInVehicle)\
			 .add_columns(CheckInVehicle.booking_id, CheckInVehicle.check_vehicle_driver, CheckInVehicle.check_vehicle_reg)\
			 .filter(CheckInVehicle.booking_id == single.booking_public_id)\
			 .all()

			if len(check_in_vehicle) == 0:
				return_data["vehicle_registration"] = ''
			else:
				vehicle_str = ''
				for vehicle in check_in_vehicle:
					vehicle_reg = vehicle.check_vehicle_reg
					vehicle_str += vehicle_reg + ','
				return_data["vehicle_registration"] = vehicle_str

			output.append(return_data)

		return jsonify({"data": output}), 200

@app.route("/bookings/view/overstays")
# @bookings_logger.logWrapper()
def view_all_overstays_this_month():
	now = datetime.now()
	today = now.strftime("%Y-%m-%d")
	yesterday_datetime = datetime.today() - timedelta(days=1)
	yesterday = yesterday_datetime.strftime("%Y-%m-%d")
	this_month = now.strftime("%Y-%m")  # Gets current month in "YYYY-MM" format
	first_day_of_month = now.replace(day=1).date()  # e.g., 2024-04-01
	last_day_of_month = (now.replace(day=28) + timedelta(days=4)).replace(day=1) - timedelta(days=1)  # Last day of current month
	last_day_of_month = last_day_of_month.date()  # Ensure it's a date object (not datetime)
	
	return_bookings = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status,Booking.payment_status, Booking.booking_ref_code,\
	   Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(Booking.booking_check_out_date == today)\
	 .filter(Booking.checked_in == 1)\
	 .filter(Booking.checked_out == None)\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	return_overstays_this_month = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.payment_status, Booking.status,Booking.payment_status, Booking.booking_ref_code,\
	  Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(Booking.booking_check_out_date >= first_day_of_month)\
     .filter(Booking.booking_check_out_date < yesterday)\
	 .filter(Booking.checked_in == 1)\
	 .filter(Booking.checked_out == None)\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	return_yesterday_bookings = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status,Booking.payment_status, Booking.booking_ref_code,\
	  Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(Booking.booking_check_out_date == yesterday)\
	 .filter(Booking.checked_out == None)\
	 .filter(Booking.status != '3216010b-7c03-48b4-b82e-6c8ea5e3096b')\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	if len(return_yesterday_bookings) > 0:
		for return_yesterday_booking in return_yesterday_bookings:
			return_bookings.append(return_yesterday_booking)

	if not return_bookings:
		output = []
		output.append(
			"There are currently no bookings to be checked out today.")
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		try:
			return_user = requests.post(get_user_from_aumra,\
			 json = {"users_ids": id_array})
		except (requests.exceptions.ConnectionError,
				requests.exceptions.Timeout,
				requests.exceptions.ConnectTimeout) as connection_error:
			pass

		for single in return_overstays_this_month:
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["booking_ref_code"] = single.booking_ref_code

			check_school_booking = db.session.query(SchoolBooking)\
			   .join(School, SchoolBooking.school_id == School.school_public_id)\
			   .add_columns(School.school_name)\
			   .filter(SchoolBooking.deletion_marker == None)\
			   .filter(SchoolBooking.booking_id == single.booking_public_id)\
			   .first()

			check_org_booking = db.session.query(Group)\
			   .filter(Group.deletion_marker == None)\
			   .filter(Group.booking_id == single.booking_public_id)\
			   .first()

			try:
				if check_school_booking:
					return_data[
						"booking_done_by"] = check_school_booking.school_name
				elif check_org_booking:
					return_data[
						"booking_done_by"] = check_org_booking.organisation_name
				else:
					return_data["booking_done_by"] = single.booking_done_by

			except Exception:
				return_data["booking_done_by"] = single.booking_done_by

			if single.checked_out == None:
				return_data["booking_check_out_status"] = "Checking Out"
				return_data[
					"booking_color"] = "background-color: #9b59b6; color: #fff"
			elif single.checked_out == 1:
				return_data["booking_check_out_status"] = "Checked Out"
				return_data[
					"booking_color"] = "background-color: #e74c3c; color: #fff"

			guest_array = []
			guest_sum = []

			get_all_guests = db.session.query(GatepassGuest)\
			   .join(Mandatory, GatepassGuest.gatepass_guest_type == Mandatory.payment_public_id)\
			   .join(Gatepass, GatepassGuest.gatepass_id == Gatepass.gatepass_public_id)\
			   .add_columns(Mandatory.payment_person, Mandatory.payment_public_id,\
			 GatepassGuest.gatepass_guest_count, GatepassGuest.gatepass_discount_rate, GatepassGuest.gatepass_cost_per_pp,\
			 GatepassGuest.gatepass_no_of_nights)\
			   .filter(GatepassGuest.deletion_marker == None)\
			   .filter(GatepassGuest.status != get_booking_status_id("Updated"))\
			   .filter(Gatepass.booking_id == single.booking_public_id)\
			   .options(FromCache(db_cache))\
			   .all()

			for each_guest in get_all_guests:
				guest_data = {}
				guest_data["guest_type"] = each_guest.payment_person
				guest_data["no_of_guests"] = each_guest.gatepass_guest_count

				guest_array.append(guest_data)
				guest_sum.append(int(each_guest.gatepass_guest_count))

			return_data["guests"] = guest_array
			return_data["guest_total"] = sum(guest_sum)

			return_data["booking_status"] = single.booking_status_name
			return_data["booking_status_id"] = single.status
			payment_status = single.payment_status
			if payment_status == 1:
				return_data["payment_status"] = 'PAID'
			elif payment_status == 2:
				return_data["payment_status"] = 'DEPOSIT'

			elif payment_status == 3:
				return_data["payment_status"] = 'COMPLIMENTARY'
			elif payment_status == 4:
				return_data["payment_status"] = 'TO INVOICE'

			else:
				return_data["payment_status"] = 'NOT PAID'

			try:
				for user in return_user.json()["data"]:
					if user["public_id"] == single.session_id:
						# return_data["session_user"] = user["first_name"] + " " + user["last_name"]
						return_data["session_user"] = user["full_name"]
						return_data["session_id"] = single.session_id

			except (IndexError, KeyError) as user_error:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			except (AttributeError,
					UnboundLocalError) as network_related_errors:
				return_data["session_user"] = "Network Error"
				return_data["session_id"] = single.session_id

			return_data["session_id"] = single.session_id
			return_data["created_at"] = single.created_at
			return_data["updated_at"] = single.updated_at
			check_in_vehicle = db.session.query(CheckInVehicle)\
			 .add_columns(CheckInVehicle.booking_id, CheckInVehicle.check_vehicle_driver, CheckInVehicle.check_vehicle_reg)\
			 .filter(CheckInVehicle.booking_id == single.booking_public_id)\
			 .all()

			if len(check_in_vehicle) == 0:
				return_data["vehicle_registration"] = ''
			else:
				vehicle_str = ''
				for vehicle in check_in_vehicle:
					vehicle_reg = vehicle.check_vehicle_reg
					vehicle_str += vehicle_reg + ','
				return_data["vehicle_registration"] = vehicle_str
			if payment_status == 1:
				return_data["booking_payment_status"] = 'PAID'
			elif payment_status == 2:
				return_data["booking_payment_status"] = 'DEPOSIT'

			elif payment_status == 3:
				return_data["booking_payment_status"] = 'COMPLIMENTARY'
			elif payment_status == 4:
				return_data["booking_payment_status"] = 'TO INVOICE'

			else:
				return_data["booking_payment_status"] = 'NOT PAID'



			output.append(return_data)

		return jsonify({"data": output}), 200

@app.route("/bookings/view/today")
# @bookings_logger.logWrapper()
def view_all_bookings_today():
	now = datetime.now()
	today = now.strftime("%Y-%m-%d")

	return_bookings = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
	   Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter((Booking.booking_check_in_date == today) | (Booking.booking_check_out_date == today))\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	if not return_bookings:
		output = []
		output.append(
			"There are currently no bookings to be checked in or out today.")
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		try:
			return_user = requests.post(get_user_from_aumra,\
			 json = {"users_ids": id_array})
		except (requests.exceptions.ConnectionError,
				requests.exceptions.Timeout,
				requests.exceptions.ConnectTimeout) as connection_error:
			pass

		for single in return_bookings:
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code

			guest_array = []
			guest_sum = []

			get_all_guests = db.session.query(GatepassGuest)\
			   .join(Mandatory, GatepassGuest.gatepass_guest_type == Mandatory.payment_public_id)\
			   .join(Gatepass, GatepassGuest.gatepass_id == Gatepass.gatepass_public_id)\
			   .add_columns(Mandatory.payment_person, Mandatory.payment_public_id,\
			 GatepassGuest.gatepass_guest_count, GatepassGuest.gatepass_discount_rate, GatepassGuest.gatepass_cost_per_pp,\
			 GatepassGuest.gatepass_no_of_nights)\
			   .filter(GatepassGuest.deletion_marker == None)\
			   .filter(GatepassGuest.status != get_booking_status_id("Updated"))\
			   .filter(Gatepass.booking_id == single.booking_public_id)\
			   .options(FromCache(db_cache))\
			   .all()

			for each_guest in get_all_guests:
				guest_data = {}
				guest_data["guest_type"] = each_guest.payment_person
				guest_data["no_of_guests"] = each_guest.gatepass_guest_count

				guest_array.append(guest_data)
				guest_sum.append(int(each_guest.gatepass_guest_count))

			return_data["guests"] = guest_array
			return_data["guest_total"] = sum(guest_sum)

			return_data["booking_status"] = single.booking_status_name
			return_data["booking_status_id"] = single.status

			try:
				for user in return_user.json()["data"]:
					if user["public_id"] == single.session_id:
						# return_data["session_user"] = user["first_name"] + " " + user["last_name"]
						return_data["session_user"] = user["full_name"]
						return_data["session_id"] = single.session_id

			except (IndexError) as user_error:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			except (AttributeError,
					UnboundLocalError) as network_related_errors:
				return_data["session_user"] = "Network Error"
				return_data["session_id"] = single.session_id

			return_data["session_id"] = single.session_id
			return_data["created_at"] = single.created_at
			return_data["updated_at"] = single.updated_at

			output.append(return_data)

		return jsonify({"data": output}), 200


@app.route("/bookings/view/abandoned")
# @bookings_logger.logWrapper()
def view_all_abandoned_bookings():
	if db.session.query(BookingStatus)\
	 .filter(BookingStatus.deletion_marker==None)\
	 .filter(BookingStatus.booking_status_public_id == "3b5376e0-a4dc-476e-aebc-6280b44b756a")\
	 .count() == 0:
		BookingStatusSeed.seed_default_booking_status()

	return_bookings = db.session.query(Booking)\
	 .join(BookingGuest, Booking.booking_public_id == BookingGuest.booking_id)\
	 .join(BookingType, Booking.booking_type == BookingType.booking_type_public_id)\
	 .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
	   Booking.currency,\
	  BookingType.booking_type_name,\
	  BookingStatus.booking_status_name)\
	 .filter(Booking.deletion_marker == None)\
	 .filter(BookingStatus.booking_status_name=="Abandoned")\
	 .order_by(Booking.booking_id.desc())\
	 .all()

	if not return_bookings:
		output = []
		output.append(
			"There are currently no abandoned bookings in the system.")
		return jsonify({"message": output}), 200
	else:
		output = []
		id_array = []

		for each_id in return_bookings:
			id_array.append(each_id.session_id)

		try:
			return_user = requests.post(get_user_from_aumra,\
			 json = {"users_ids": id_array})
		except (requests.exceptions.ConnectionError,
				requests.exceptions.Timeout,
				requests.exceptions.ConnectTimeout) as connection_error:
			pass

		for single in return_bookings:
			return_data = {}
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_type"] = single.booking_type_name
			return_data["booking_type_id"] = single.booking_type
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code

			guest_array = []
			guest_sum = []

			get_all_guests = db.session.query(BookingGuest)\
			   .join(GuestType, BookingGuest.guest_type == GuestType.booking_guest_type_public_id)\
			   .add_columns(GuestType.booking_guest_type_name,\
			 BookingGuest.guest_count)\
			   .filter(BookingGuest.deletion_marker == None)\
			   .filter(BookingGuest.booking_id == single.booking_public_id)\
			   .all()

			for each_guest in get_all_guests:
				guest_data = {}
				guest_data["guest_type"] = each_guest.booking_guest_type_name
				guest_data["no_of_guests"] = each_guest.guest_count

				guest_array.append(guest_data)
				guest_sum.append(int(each_guest.guest_count))

			return_data["guests"] = guest_array
			return_data["guest_total"] = sum(guest_sum)

			return_data["booking_status"] = single.booking_status_name
			return_data["booking_status_id"] = single.status

			try:
				for user in return_user.json()["data"]:
					if user["public_id"] == single.session_id:
						# return_data["session_user"] = user["first_name"] + " " + user["last_name"]
						return_data["session_user"] = user["full_name"]
						return_data["session_id"] = single.session_id

			except (IndexError) as user_error:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			except (AttributeError,
					UnboundLocalError) as network_related_errors:
				return_data["session_user"] = "Network Error"
				return_data["session_id"] = single.session_id

			return_data["session_id"] = single.session_id
			return_data["created_at"] = single.created_at
			return_data["updated_at"] = single.updated_at

			output.append(return_data)

		return jsonify({"data": output}), 200


@app.route("/bookings/confirm", methods=["PATCH"])
# @bookings_logger.logWrapper()
def confirm_single_booking():
	messages = []

	if db.session.query(BookingStatus)\
	 .filter(BookingStatus.deletion_marker==None)\
	 .filter(BookingStatus.booking_status_public_id == "3b5376e0-a4dc-476e-aebc-6280b44b756a")\
	 .count() == 0:
		BookingStatusSeed.seed_default_booking_status()

	try:
		request.json["booking_id"].strip()
		if not request.json["booking_id"]:
			messages.append("Booking ID is empty.")
	except KeyError as e:
		messages.append("Booking ID is missing.")

	try:
		request.json["session_id"].strip()
		if not request.json["session_id"]:
			messages.append("Session ID is empty.")
	except KeyError as e:
		messages.append("Session ID is missing.")

	if messages:
		output = []
		output.append("You appear to be missing some data. Please try again.")
		return jsonify({"message": output, "messages": messages}), 422

	return_booking = db.session.query(Booking)\
	   .join(BookingStatus, Booking.status == BookingStatus.booking_status_public_id)\
	   .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	 Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	 Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.session_id,\
	 Booking.created_at, Booking.updated_at, Booking.status, Booking.booking_ref_code,\
	 Booking.currency,\
	 BookingType.booking_type_name,\
	 BookingStatus.booking_status_name)\
	   .filter(Booking.booking_public_id==request.json["booking_id"])\
	   .filter(Booking.deletion_marker==None)\
	   .filter(BookingStatus.booking_status_name=="Unconfirmed")\
	   .first()

	if not return_booking:
		output = []
		output.append("That booking does not appear to exist.")
		return jsonify({"message": output}), 200
	else:
		return_booking.status = get_booking_status_id("Confirmed")

		## Commented out in order to stop updating the user.
		# return_booking.session_id = request.json["session_id"]

		return_booking.updated_at = datetime.now()

	try:
		db.session.commit()
		close(db)

		output = []
		output.append("Booking confirmed successfully. Please proceed.")
		return jsonify({"message": output}), 200
	except Exception as e:
		print(e)
		db.session.rollback()
		close(db)

		output = []
		output.append(
			"There was a slight issue confirming that order. :-( Please try again later."
		)
		return jsonify({"message": output}), 422


@app.route("/bookings/view-checkin/<booking_id>")
# @bookings_logger.logWrapper()
def view_single_checkin_booking(booking_id):

	return_bookings = db.session.query(Booking)\
	 .add_columns(Booking.booking_public_id, Booking.booking_type, Booking.booking_check_in_date,\
	  Booking.booking_check_out_date, Booking.actual_booking_check_in_date, Booking.actual_booking_check_out_date,\
	  Booking.booking_done_by, Booking.checked_in, Booking.checked_out, Booking.booking_ref_code, Booking.session_id,\
	  Booking.created_at, Booking.updated_at, Booking.status, Booking.payment_status,\
	  Booking.currency, Booking.deletion_marker, Booking.currency_buying_rate_at_time,\
	  Booking.currency_selling_rate_at_time)\
	 .filter(Booking.booking_public_id == booking_id)\
	 .options(FromCache(db_cache))\
	 .all()

	if not return_bookings:
		message = []
		message.append(
			"The selected booking does not appear to exist in the system.")
		return jsonify({"message": message}), 200

	else:
		data = []
		for single in return_bookings:
			return_data = {}

			## Basic booking details
			return_data["booking_public_id"] = single.booking_public_id
			return_data["booking_check_in_date"] = single.booking_check_in_date
			return_data[
				"booking_check_out_date"] = single.booking_check_out_date
			return_data[
				"actual_booking_check_in_date"] = single.actual_booking_check_in_date
			return_data[
				"check_in_date"] = single.booking_check_in_date.strftime(
					"%A, %d %b %Y")

			return_data[
				"check_out_date"] = single.booking_check_out_date.strftime(
					"%A, %d %b %Y")

			return_data[
				"actual_booking_check_out_date"] = single.actual_booking_check_out_date
			if single.payment_status == 1:
				return_data["booking_payment_status"] = "Paid"
			if single.payment_status == 2:
				return_data["booking_payment_status"] = "Incomplete Payment"
			if single.payment_status == 3:
				return_data["booking_payment_status"] = "Complimentary"
			if single.payment_status == 4:
				return_data["booking_payment_status"] = "To Invoice"
			elif not single.payment_status:
				return_data["booking_payment_status"] = "Not Paid"
			return_data["booking_done_by"] = single.booking_done_by
			return_data["booking_ref_code"] = single.booking_ref_code
			return_data["created_at"] = single.created_at

			if not single.payment_status and single.booking_type == 'PB001A20':
				return_data["is_partner"] = True
				get_partner_booking = db.session.query(Partner)\
				.filter(Partner.deletion_marker == None)\
				.filter(Partner.booking_id == single.booking_public_id)\
				.options(FromCache(db_cache))\
				.first()

				if get_partner_booking:
					partner_details = requests.get(
						get_partner_details.format(
							get_partner_booking.partner_id))
					try:
						return_data["partner_name"] = partner_details.json(
						)["name"]
					except Exception:
						return_data["partner_name"] = None
					paid_by = get_partner_booking.paid_by
					if paid_by == 1:
						return_data["paid_by"] = return_data[
							"partner_name"] + ' To Pay'
					elif paid_by == 0:
						return_data["paid_by"] = 'Guest To Pay'
					else:
						return_data["paid_by"] = 'Not Specified'

			else:
				return_data["is_partner"] = False

			get_booking_details = db.session.query(Detail)\
			 .filter(Detail.booking_id == single.booking_public_id)\
			 .filter(Detail.status != get_booking_status_id("Updated"))\
			 .first()
			entry_mode = get_booking_details.entry_mode
			if entry_mode:
				return_data["entry_mode"] = True
				get_entry_mode = db.session.query(EntryMode)\
				 .filter(EntryMode.deletion_marker == None)\
				 .filter(EntryMode.entry_mode_public_id == get_booking_details.entry_mode)\
				 .first()
				try:
					return_data[
						"entry_mode_name"] = get_entry_mode.entry_mode_name
					return_data[
						"entry_mode_public_id"] = get_entry_mode.entry_mode_public_id
				except Exception as e:
					return_data["entry_mode_name"] = ''
					return_data["entry_mode_public_id"] = ''

				get_entry_point = db.session.query(Gate)\
				 .filter(Gate.deletion_marker == None)\
				 .filter(Gate.gate_public_id == get_booking_details.entry_point)\
				 .first()
				try:
					return_data["gate_name"] = get_entry_point.gate_name
					return_data[
						"gate_public_id"] = get_entry_point.gate_public_id
				except Exception as e:
					return_data["gate_name"] = ''
					return_data["gate_public_id"] = ''

				return_data[
					"mode_registration"] = get_booking_details.mode_registration
			else:
				return_data["entry_mode"] = False
			get_gatepass = db.session.query(Gatepass)\
			 .filter(Gatepass.booking_id == single.booking_public_id)\
			 .filter(Gatepass.status != get_booking_status_id("Updated"))\
			 .first()
			
			get_gatepass_guests = db.session.query(GatepassGuest)\
			 .filter(GatepassGuest.gatepass_id == get_gatepass.gatepass_public_id)\
			 .filter(GatepassGuest.gatepass_guest_count > 0)\
			 .first()

			if get_gatepass:
				## Booking destination
				try:
					return_data["destination_id"] = get_gatepass.destination
					return_data["destination"], = db.session.query(Destination.gatepass_destination_name)\
					 .filter(Destination.gatepass_destination_public_id == get_gatepass.destination)\
					 .options(FromCache(db_cache))\
					 .first()
					return_data["destination_set"] = True
				except TypeError:
					return_data["destination_id"] = None
					return_data["destination"] = None
					return_data["destination_set"] = False
			else:
				return_data["destination_id"] = None
				return_data["destination"] = None
				return_data["destination_set"] = False
			if get_gatepass_guests:
				try:
					return_data["gatepass_guest_count"] = get_gatepass_guests.gatepass_guest_count
					
				except TypeError:
					return_data["gatepass_guest_count"] = 0
			else:
				return_data["gatepass_guest_count"] = 0

			residency_db= db.session.query(ResidencyProof)\
			  .filter(ResidencyProof.booking_id == single.booking_public_id)\
			  .filter(ResidencyProof.deletion_marker == None)\
			  .options(FromCache(db_cache))\
			  .all()
			residency_proof = []
			if not residency_db:
				residency_proof = []
			else:
				for residency in residency_db:
					residency_obj = {}
					residency_obj["first_name"] = residency.first_name
					residency_obj["last_name"] = residency.last_name
					residency_obj["document_id"] = residency.document_id
					residency_obj[
						"residency_proof_public_id"] = residency.residency_proof_public_id
					residency_obj[
						"residency_booking_id"] = single.booking_public_id
					residency_id = residency.residency_id


					get_residence_name = db.session.query(Mandatory)\
					 .add_columns(Mandatory.payment_person,Mandatory.payment_public_id )\
					 .filter(Mandatory.payment_public_id == residency_id)\
					 .options(FromCache(db_cache))\
					 .first()
					residency_obj[
						"payment_person"] = get_residence_name.payment_person
					residency_obj[
						"payment_public_id"] = get_residence_name.payment_public_id
					residency_obj["proof_point"] = residency.proof_point
					verify = residency.verified
					if verify == 1:
						residency_obj["verified"] = True
					else:
						residency_obj["verified"] = False
					residency_proof.append(residency_obj)

			# Getting the guest types and conservancy fee totals
			get_all_gatepass_guests = db.session.query(GatepassGuest)\
			.join(Mandatory, GatepassGuest.gatepass_guest_type == Mandatory.payment_public_id)\
			.join(Gatepass, GatepassGuest.gatepass_id == Gatepass.gatepass_public_id)\
			.add_columns(Mandatory.payment_person,Mandatory.residency_proof,  Mandatory.payment_public_id, Mandatory.payment_person_income_code,\
			GatepassGuest.gatepass_guest_count, GatepassGuest.gatepass_guest_public_id,\
			Gatepass.destination)\
			.filter(GatepassGuest.status != get_booking_status_id("Updated"))\
			.filter(GatepassGuest.deletion_marker == None)\
			.filter(Gatepass.booking_id == booking_id)\
			.filter(GatepassGuest.gatepass_guest_count >0)\
			.filter(Gatepass.status != get_booking_status_id("Updated"))\
			.filter(Mandatory.residency_proof == 1)\
			.options(FromCache(db_cache))\
			.all()

			guest_array = []

			for each_guest in get_all_gatepass_guests:
				guest_data = {}
				guest_data["residency_proof"] = True
				guest_data["payment_public_id"] = each_guest.payment_public_id
				guest_data["payment_person"] = each_guest.payment_person
				guest_data["payment_guests"] = each_guest.gatepass_guest_count
				guest_data["proof_point"] = "Residency"
				guest_array.append(guest_data)
			inventory_array = []
			inventory_bookings = db.session.query(Inventory)\
			 .filter(Inventory.deletion_marker == None)\
			 .filter(Inventory.status != get_booking_status_id("Updated"))\
			 .filter(Inventory.booking_id == booking_id)\
			 .options(FromCache(db_cache))\
			 .all()

			for single_inventory in inventory_bookings:
				return_inventory = requests.get(
					get_inventory_details.format(
						single_inventory.inventory_id))
				try:
					inventory_name = return_inventory.json()["data"][0]["name"]
				except Exception as e:
					inventory_name = ''
				if single_inventory.inventory_booking_children_residency:
					inventory_data = {}
					get_residency_name = db.session.query(Mandatory)\
					.filter(Mandatory.deletion_marker == None)\
					.filter(Mandatory.payment_public_id ==  single_inventory.inventory_booking_children_residency)\
					.first()
					proof = get_residency_name.residency_proof
					if proof == 1:
						inventory_data["residency_proof"] = True
						inventory_data[
							"payment_public_id"] = get_residency_name.payment_public_id
						inventory_data[
							"payment_person"] = get_residency_name.payment_person
						inventory_data[
							"payment_guests"] = single_inventory.inventory_booking_children
						inventory_data["proof_point"] = inventory_name
						inventory_array.append(inventory_data)

				if single_inventory.inventory_booking_adults_residency:
					inventory_data = {}
					get_residency_name = db.session.query(Mandatory)\
					.filter(Mandatory.deletion_marker == None)\
					.filter(Mandatory.payment_public_id ==  single_inventory.inventory_booking_adults_residency)\
					.first()

					proof = get_residency_name.residency_proof
					if proof == 1:
						inventory_data["residency_proof"] = True
						inventory_data[
							"payment_public_id"] = get_residency_name.payment_public_id
						inventory_data[
							"payment_person"] = get_residency_name.payment_person
						inventory_data[
							"payment_guests"] = single_inventory.inventory_booking_adults
						inventory_data["proof_point"] = inventory_name
						inventory_array.append(inventory_data)

				if single_inventory.inventory_booking_extra_adults_residency:
					inventory_data = {}
					get_residency_name = db.session.query(Mandatory)\
					.filter(Mandatory.deletion_marker == None)\
					.filter(Mandatory.payment_public_id ==  single_inventory.inventory_booking_extra_adults_residency)\
					.first()
					proof = get_residency_name.residency_proof
					if proof == 1:
						inventory_data["residency_proof"] = True
						inventory_data[
							"payment_public_id"] = get_residency_name.payment_public_id
						inventory_data[
							"payment_person"] = get_residency_name.payment_person
						inventory_data[
							"payment_guests"] = single_inventory.inventory_booking_extra_adults
						inventory_data["proof_point"] = inventory_name
						inventory_array.append(inventory_data)

				if single_inventory.inventory_booking_extra_children_residency:
					inventory_data = {}
					get_residency_name = db.session.query(Mandatory)\
					.filter(Mandatory.deletion_marker == None)\
					.filter(Mandatory.payment_public_id ==  single_inventory.inventory_booking_extra_children_residency)\
					.first()
					proof = get_residency_name.residency_proof
					if proof == 1:
						inventory_data["residency_proof"] = True
						inventory_data[
							"payment_public_id"] = get_residency_name.payment_public_id
						inventory_data[
							"payment_person"] = get_residency_name.payment_person
						inventory_data[
							"payment_guests"] = single_inventory.inventory_booking_extra_children
						inventory_data["proof_point"] = inventory_name
						inventory_array.append(inventory_data)

			if len(guest_array) > 0:
				for single_guest in guest_array:
					guest_count = single_guest["payment_guests"]
					guest_id = single_guest["payment_public_id"]
					proof_point = single_guest["proof_point"]
					guest_proofed_number = 0
					if len(residency_proof) > 0:

						for residency in residency_proof:
							residency_proof_point = residency["proof_point"]
							residency_guest_id = residency["payment_public_id"]
							if residency_guest_id == guest_id and residency_proof_point == proof_point:
								guest_proofed_number += 1
					to_proof_number = guest_count - guest_proofed_number
					if to_proof_number > 0:
						for i in range(to_proof_number):
							proof_obj = {}
							proof_obj["first_name"] = ""
							proof_obj["last_name"] = ""
							proof_obj["document_id"] = ""
							proof_obj["residency_proof_public_id"] = ""
							proof_obj[
								"residency_booking_id"] = single.booking_public_id
							proof_obj["payment_person"] = single_guest[
								"payment_person"]
							proof_obj["payment_public_id"] = single_guest[
								"payment_public_id"]
							proof_obj["proof_point"] = proof_point
							proof_obj["verified"] = False
							residency_proof.append(proof_obj)
			if len(inventory_array) > 0:

				for single_inventory in inventory_array:
					guest_count = single_inventory["payment_guests"]
					guest_id = single_inventory["payment_public_id"]
					proof_point = single_inventory["proof_point"]
					guest_proofed_number = 0
					if len(residency_proof) > 0:

						for residency in residency_proof:
							residency_proof_point = residency["proof_point"]
							residency_guest_id = residency["payment_public_id"]
							if residency_guest_id == guest_id and residency_proof_point == proof_point:
								guest_proofed_number += 1
					to_proof_number = guest_count - guest_proofed_number
					if to_proof_number > 0:
						for i in range(to_proof_number):
							proof_obj = {}
							proof_obj["first_name"] = ""
							proof_obj["last_name"] = ""
							proof_obj["document_id"] = ""
							proof_obj["residency_proof_public_id"] = ""
							proof_obj[
								"residency_booking_id"] = single.booking_public_id
							proof_obj["payment_person"] = single_guest[
								"payment_person"]
							proof_obj["payment_public_id"] = single_guest[
								"payment_public_id"]
							proof_obj["proof_point"] = proof_point
							proof_obj["verified"] = False
							residency_proof.append(proof_obj)
			return_data["residency_proof"] = residency_proof
			data.append(return_data)
		return jsonify({"data": data}), 200


@app.route("/bookings/check_in", methods=["PATCH"])
# @bookings_logger.logWrapper()
def check_in_single_booking():

    try:
        activity_check_in = request.json["activity_check_in"]
    except Exception:
        activity_check_in = None

    try:
        destination = request.json["destination"]
    except Exception:
        destination = None

    if not activity_check_in:
        messages = []

        try:
            request.json["booking_id"].strip()
            if not request.json["booking_id"]:
                messages.append("Booking ID is empty.")
        except KeyError as e:
            messages.append("Booking ID is missing.")

        try:
            request.json["source"].strip()
            if not request.json["source"]:
                messages.append("Source is empty.")
        except KeyError as e:
            messages.append("Source is missing.")

        try:
            request.json["session_id"].strip()
            if not request.json["session_id"]:
                messages.append("Session ID is empty.")
        except KeyError as e:
            messages.append("Session ID is missing.")

        if request.json["vehicles"]:
            for each_vehicle in request.json["vehicles"]:
                try:
                    each_vehicle["driver_name"].strip()
                    if not each_vehicle["driver_name"]:
                        messages.append("Driver name is empty.")
                except KeyError as e:
                    messages.append("Driver name is missing.")

                try:
                    each_vehicle["reg_plate"].strip()
                    if not each_vehicle["reg_plate"]:
                        messages.append("Vehicle registration is empty.")
                except KeyError as e:
                    messages.append("Vehicle registration is missing.")

                try:
                    each_vehicle["disk"].strip()
                    if not each_vehicle["disk"]:
                        messages.append("Disk is empty.")
                except KeyError as e:
                    messages.append("Disk is missing.")

                try:
                    each_vehicle["phone_number"].strip()
                    if not each_vehicle["phone_number"]:
                        messages.append("Phone number is empty.")
                except KeyError as e:
                    messages.append("Phone number is missing.")

                phone_validation = validatePhoneNumber(
                    each_vehicle["phone_number"])

                if not phone_validation[0]:
                    messages.append(each_vehicle["phone_number"] +
                                    " is invalid.")

        if messages:
            return jsonify({"messages": messages}), 422

    yesterday_datetime = datetime.today() - timedelta(days=1)
    yesterday = yesterday_datetime.strftime("%Y-%m-%d")

    get_gatepass = db.session.query(Gatepass)\
     .filter(Gatepass.deletion_marker == None)\
     .filter(Gatepass.booking_id == request.json["booking_id"])\
     .first()

    if not get_gatepass.destination:
        if not destination:
            message = []
            message.append("Destination must be set.")
            return jsonify({"message": message}), 422


    # return_booking = db.session.query(Booking)\
    #    .filter(Booking.booking_public_id == request.json["booking_id"])\
    #    .filter(Booking.deletion_marker == None)\
    #    .filter(Booking.booking_check_in_date >= yesterday)\
    #    .filter(Booking.checked_in == None)\
    #    .filter(Booking.checked_out == None)\
    #    .first()
    return_booking = db.session.query(Booking)\
       .filter(Booking.booking_public_id == request.json["booking_id"])\
       .filter(Booking.deletion_marker == None)\
       .filter(Booking.checked_in == None)\
       .filter(Booking.checked_out == None)\
       .first()
    if not return_booking:
        output = []
        output.append(
            "The selected booking either does not exist or has already been checked in."
        )
        return jsonify({"message": output}), 422
    else:
        if datetime.now() < return_booking.booking_check_in_date:
            message = []
            message.append(
                "The selected booking cannot be checked in as the check-in date is in the future."
            )
            return jsonify({"message": message}), 412

        #residency proof

        try:
            residency_proof = request.json["residency_proof"]

        except Exception as e:
            residency_proof = []
        if len(residency_proof) > 0:
            try:
                for single_residency_proof in residency_proof:
                    messages = []
                    try:
                        if not single_residency_proof["first_name"]:
                            messages.append("First name is empty.")
                    except KeyError as e:
                        messages.append("First name is missing.")
                    try:
                        if not single_residency_proof["last_name"]:
                            messages.append("Last name is empty.")
                    except KeyError as e:
                        messages.append("Last name is missing.")

                    try:
                        if not single_residency_proof["document_id"]:
                            messages.append("Document id is empty.")
                    except KeyError as e:
                        messages.append("Document is missing.")
                    try:
                        if not single_residency_proof["verified"]:
                            messages.append("Please verify all residencies.")
                    except KeyError as e:
                        messages.append("Please verify all residencies.")
                    if messages:
                        return jsonify({"messages": messages}), 422

            except KeyError as e:
                message = []
                message.append("Error occurred while prooving residency.")
                return jsonify({"message": message}), 412

            #fetch already saved proofs
            residecy_proof_db = db.session.query(ResidencyProof)\
            .filter(ResidencyProof.deletion_marker == None)\
            .filter(ResidencyProof.booking_id == return_booking.booking_public_id)\
            .options(FromCache(db_cache))\
            .all()

            for single_proof in residecy_proof_db:
                single_proof.deletion_marker = 1
                single_proof.updated_at = datetime.now()
            try:
                newResidencyProof(residency_proof, request.json["booking_id"],
                                  request.json["session_id"])
            except Exception as e:
                trace = traceback.format_exc()
                return jsonify({"message": str(e), "trace": trace}), 422

        if not return_booking.ticket:
            get_last_ticket = db.session.query(Ticket)\
            .filter(Ticket.deletion_marker == None)\
            .filter(Ticket.ticket_date == datetime.now().strftime("%Y-%m-%d"))\
            .first()

            if not get_last_ticket:
                booking_ticket = ticketGenerator(None)

                ticket = Ticket(
                    booking_tickets_public_id=str(uuid.uuid4()),
                    ticket_date=datetime.now().strftime("%Y-%m-%d"),
                    first_ticket=booking_ticket,
                    last_ticket=booking_ticket,
                    session_id=request.json["session_id"],
                    created_at=datetime.now(),
                    updated_at=datetime.now())

                db.session.add(ticket)

            else:
                booking_ticket = ticketGenerator(get_last_ticket.last_ticket)

                get_last_ticket.last_ticket = booking_ticket
                get_last_ticket.updated_at = datetime.now()

            return_booking.ticket = booking_ticket

        else:
            booking_ticket = return_booking.ticket

        return_booking.checked_in = 1
        return_booking.actual_booking_check_in_date = datetime.now()

        ## Commented out in order to stop updating the user.
        # return_booking.session_id = request.json["session_id"]

        return_booking.updated_at = datetime.now()

        get_gatepass = db.session.query(Gatepass)\
        .filter(Gatepass.deletion_marker == None)\
        .filter(Gatepass.booking_id == request.json["booking_id"])\
        .first()

        if not get_gatepass.destination:
            if destination:
                get_gatepass.destination = destination

        get_gatepass.gatepass_source = request.json["source"]
        get_gatepass.updated_at = datetime.now()

        # Update booking notes - find notes with matching vehicle registration and update booking_id
        if request.json["vehicles"]:
            for vehicle in request.json["vehicles"]:
                reg_plate = vehicle["reg_plate"].upper()
                
                # Find notes with matching vehicle registration and no booking_id
                notes_to_update = db.session.query(Note)\
                    .filter(Note.deletion_marker == None)\
                    .filter(Note.vehicle_reg.ilike(reg_plate))\
                    .filter(Note.booking_id == None)\
                    .all()
                
                # Update the booking_id for matching notes
                for note in notes_to_update:
                    note.booking_id = return_booking.booking_public_id
                    note.updated_at = datetime.now()

        booking_activity = BookingActivity(
            booking_activity_public_id=str(uuid.uuid4()),
            booking_id=request.json["booking_id"],
            booking_activity_description="Booking checked in",
            session_id=request.json["session_id"],
            created_at=datetime.now())

        db.session.add(booking_activity)

        if not activity_check_in:
            for vehicle in request.json["vehicles"]:
                check_in_vehicle = CheckInVehicle(
                    check_vehicle_public_id=str(uuid.uuid4()),
                    booking_id=return_booking.booking_public_id,
                    check_vehicle_driver=vehicle["driver_name"].title(),
                    check_vehicle_phone_number=vehicle["phone_number"],
                    check_vehicle_reg=vehicle["reg_plate"].upper(),
                    check_vehicle_disc=vehicle["disk"],
                    session_id=request.json["session_id"],
                    created_at=datetime.now(),
                    updated_at=datetime.now())

                db.session.add(check_in_vehicle)

        try:
            db.session.commit()
            close(db)

            output = []
            output.append("Check in successful. Please proceed.")
            # return jsonify({"message": output, "url": 'https://' + app.config['SERVER'] + '/docs/tickets/receipt-' + get_booking_details.gatepass_ref_code + '.pdf'}), 200
            return jsonify({
                "message":
                output,
                "url":
                "https://bookings.olpejetaconservancy.org/booking/{}".format(
                    request.json["booking_id"])
            }), 200
        except Exception as e:
            print(e)
            db.session.rollback()
            close(db)

            output = []
            output.append(
                "There was a slight issue checking in. Please try again later."
            )
            return jsonify({"message": output}), 422


# def check_in_single_booking():
# 	## TODO: Remove the exception handling after v1.3.1
# 	try:
# 		activity_check_in = request.json["activity_check_in"]
# 	except Exception:
# 		activity_check_in = None

# 	try:
# 		destination = request.json["destination"]
# 	except Exception:
# 		destination = None

# 	if not activity_check_in:
# 		messages = []

# 		try:
# 			request.json["booking_id"].strip()
# 			if not request.json["booking_id"]:
# 				messages.append("Booking ID is empty.")
# 		except KeyError as e:
# 			messages.append("Booking ID is missing.")

# 		try:
# 			request.json["source"].strip()
# 			if not request.json["source"]:
# 				messages.append("Source is empty.")
# 		except KeyError as e:
# 			messages.append("Source is missing.")

# 		try:
# 			request.json["session_id"].strip()
# 			if not request.json["session_id"]:
# 				messages.append("Session ID is empty.")
# 		except KeyError as e:
# 			messages.append("Session ID is missing.")

# 		if request.json["vehicles"]:
# 			for each_vehicle in request.json["vehicles"]:
# 				try:
# 					each_vehicle["driver_name"].strip()
# 					if not each_vehicle["driver_name"]:
# 						messages.append("Driver name is empty.")
# 				except KeyError as e:
# 					messages.append("Driver name is missing.")

# 				try:
# 					each_vehicle["reg_plate"].strip()
# 					if not each_vehicle["reg_plate"]:
# 						messages.append("Vehicle registration is empty.")
# 				except KeyError as e:
# 					messages.append("Vehicle registration is missing.")

# 				try:
# 					each_vehicle["disk"].strip()
# 					if not each_vehicle["disk"]:
# 						messages.append("Disk is empty.")
# 				except KeyError as e:
# 					messages.append("Disk is missing.")

# 				try:
# 					each_vehicle["phone_number"].strip()
# 					if not each_vehicle["phone_number"]:
# 						messages.append("Phone number is empty.")
# 				except KeyError as e:
# 					messages.append("Phone number is missing.")

# 				phone_validation = validatePhoneNumber(
# 					each_vehicle["phone_number"])

# 				if not phone_validation[0]:
# 					messages.append(each_vehicle["phone_number"] +
# 									" is invalid.")

# 		if messages:
# 			return jsonify({"messages": messages}), 422

# 	today = datetime.now().strftime("%Y-%m-%d")
# 	yesterday_datetime = datetime.today() - timedelta(days=1)
# 	yesterday = yesterday_datetime.strftime("%Y-%m-%d")

# 	get_gatepass = db.session.query(Gatepass)\
# 	 .filter(Gatepass.deletion_marker == None)\
# 	 .filter(Gatepass.booking_id == request.json["booking_id"])\
# 	 .first()

# 	if not get_gatepass.destination:
# 		if not destination:
# 			message = []
# 			message.append("Destination must be set.")
# 			return jsonify({"message": message}), 422

# 	return_booking = db.session.query(Booking)\
# 	   .filter(Booking.booking_public_id == request.json["booking_id"])\
# 	   .filter(Booking.deletion_marker == None)\
# 	   .filter(Booking.booking_check_in_date >= yesterday)\
# 	   .filter(Booking.checked_in == None)\
# 	   .filter(Booking.checked_out == None)\
# 	   .first()

# 	if not return_booking:
# 		output = []
# 		output.append(
# 			"The selected booking either does not exist or has already been checked in."
# 		)
# 		return jsonify({"message": output}), 200
# 	else:
# 		if datetime.now() < return_booking.booking_check_in_date:
# 			message = []
# 			message.append(
# 				"The selected booking cannot be checked in as the check-in date is in the future."
# 			)
# 			return jsonify({"message": message}), 412

# 			message = []
# 			message.append("Error occurred while prooving residency.")
# 			return jsonify({"message": message}), 412
# 		try:
# 			residency_proof = request.json["residency_proof"]

# 		except Exception as e:
# 			residency_proof = []
# 		if len(residency_proof) > 0:
# 			try:
# 				for single_residency_proof in residency_proof:
# 					messages = []
# 					try:
# 						if not single_residency_proof["first_name"]:
# 							messages.append("First name is empty.")
# 					except KeyError as e:
# 						messages.append("First name is missing.")
# 					try:
# 						if not single_residency_proof["last_name"]:
# 							messages.append("Last name is empty.")
# 					except KeyError as e:
# 						messages.append("Last name is missing.")

# 					try:
# 						if not single_residency_proof["document_id"]:
# 							messages.append("Document id is empty.")
# 					except KeyError as e:
# 						messages.append("Document is missing.")
# 					try:
# 						if not single_residency_proof["verified"]:
# 							messages.append("Please verify all residencies.")
# 					except KeyError as e:
# 						messages.append("Please verify all residencies.")
# 					if messages:
# 						return jsonify({"messages": messages}), 422

# 			except KeyError as e:
# 				message = []
# 				message.append("Error occurred while prooving residency.")
# 				return jsonify({"message": message}), 412

# 			#fetch already saved proofs
# 			residecy_proof_db = db.session.query(ResidencyProof)\
# 			.filter(ResidencyProof.deletion_marker == None)\
# 			.filter(ResidencyProof.booking_id == return_booking.booking_public_id)\
# 			.options(FromCache(db_cache))\
# 			.all()

# 			for single_proof in residecy_proof_db:
# 				single_proof.deletion_marker = 1
# 				single_proof.updated_at = datetime.now()
# 			try:
# 				newResidencyProof(residency_proof, request.json["booking_id"],
# 								  request.json["session_id"])
# 			except Exception as e:
# 				trace = traceback.format_exc()
# 				return jsonify({"message": str(e), "trace": trace}), 422

# 		if not return_booking.ticket:
# 			get_last_ticket = db.session.query(Ticket)\
# 			 .filter(Ticket.deletion_marker == None)\
# 			 .filter(Ticket.ticket_date == datetime.now().strftime("%Y-%m-%d"))\
# 			 .first()

# 			if not get_last_ticket:
# 				booking_ticket = ticketGenerator(None)

# 				ticket = Ticket(
# 					booking_tickets_public_id=str(uuid.uuid4()),
# 					ticket_date=datetime.now().strftime("%Y-%m-%d"),
# 					first_ticket=booking_ticket,
# 					last_ticket=booking_ticket,
# 					session_id=request.json["session_id"],
# 					created_at=datetime.now(),
# 					updated_at=datetime.now())

# 				db.session.add(ticket)

# 			else:
# 				booking_ticket = ticketGenerator(get_last_ticket.last_ticket)

# 				get_last_ticket.last_ticket = booking_ticket
# 				get_last_ticket.updated_at = datetime.now()

# 			return_booking.ticket = booking_ticket

# 		else:
# 			booking_ticket = return_booking.ticket

# 		return_booking.checked_in = 1
# 		return_booking.actual_booking_check_in_date = datetime.now()

# 		## Commented out in order to stop updating the user.
# 		# return_booking.session_id = request.json["session_id"]

# 		return_booking.updated_at = datetime.now()

# 		get_gatepass = db.session.query(Gatepass)\
# 		 .filter(Gatepass.deletion_marker == None)\
# 		 .filter(Gatepass.booking_id == request.json["booking_id"])\
# 		 .first()

# 		if not get_gatepass.destination:
# 			if destination:
# 				get_gatepass.destination = destination

# 		get_gatepass.gatepass_source = request.json["source"]
# 		get_gatepass.updated_at = datetime.now()

# 		booking_activity = BookingActivity(
# 			booking_activity_public_id=str(uuid.uuid4()),
# 			booking_id=request.json["booking_id"],
# 			booking_activity_description="Booking checked in",
# 			session_id=request.json["session_id"],
# 			created_at=datetime.now())

# 		db.session.add(booking_activity)

# 		if not activity_check_in:
# 			for vehicle in request.json["vehicles"]:
# 				check_in_vehicle = CheckInVehicle(
# 					check_vehicle_public_id=str(uuid.uuid4()),
# 					booking_id=return_booking.booking_public_id,
# 					check_vehicle_driver=vehicle["driver_name"].title(),
# 					check_vehicle_phone_number=vehicle["phone_number"],
# 					check_vehicle_reg=vehicle["reg_plate"].upper(),
# 					check_vehicle_disc=vehicle["disk"],
# 					session_id=request.json["session_id"],
# 					created_at=datetime.now(),
# 					updated_at=datetime.now())

# 				db.session.add(check_in_vehicle)

# 		try:
# 			db.session.commit()
# 			close(db)

# 			output = []
# 			output.append("Check in successful. Please proceed.")
# 			# return jsonify({"message": output, "url": 'https://' + app.config['SERVER'] + '/docs/tickets/receipt-' + get_booking_details.gatepass_ref_code + '.pdf'}), 200
# 			return jsonify({
# 				"message":
# 				output,
# 				"url":
# 				"https://bookings.olpejetaconservancy.org/booking/{}".format(
# 					request.json["booking_id"])
# 			}), 200
# 		except Exception as e:
# 			print(e)
# 			db.session.rollback()
# 			close(db)

# 			output = []
# 			output.append(
# 				"There was a slight issue checking in. Please try again later."
# 			)
# 			return jsonify({"message": output}), 422


@app.route("/bookings/check_out", methods=["PATCH"])
# @bookings_logger.logWrapper()
def check_out_single_booking():
	messages = []

	try:
		request.json["booking_id"].strip()
		if not request.json["booking_id"]:
			messages.append("Booking ID is empty.")
	except KeyError as e:
		messages.append("Booking ID is missing.")

	try:
		request.json["session_id"].strip()
		if not request.json["session_id"]:
			messages.append("Session ID is empty.")
	except KeyError as e:
		messages.append("Session ID is missing.")

	if messages:
		output = []
		output.append("You appear to be missing some data. Please try again.")
		return jsonify({"message": output, "messages": messages}), 422

	today = datetime.now().strftime("%Y-%m-%d")

	return_booking = db.session.query(Booking)\
	   .filter(Booking.booking_public_id==request.json["booking_id"])\
	   .filter(Booking.deletion_marker==None)\
	   .filter(Booking.checked_in == 1)\
	   .filter(Booking.checked_out == None)\
	   .first()

	if not return_booking:
		output = []
		output.append(
			"That booking either does not exist or has already been checked out."
		)
		return jsonify({"message": output}), 200
	else:
		if datetime.now() < return_booking.booking_check_out_date:
			message = []
			message.append(
				"You cannot check-out the selected booking as the check-out date is in the future."
			)
			return jsonify({"message": message}), 412

		return_booking.checked_out = 1
		return_booking.actual_booking_check_out_date = datetime.now()

		## Commented out in order to stop updating the user.
		# return_booking.session_id = request.json["session_id"]

		return_booking.updated_at = datetime.now()

		booking_activity = BookingActivity(
			booking_activity_public_id=str(uuid.uuid4()),
			booking_id=request.json["booking_id"],
			booking_activity_description="Booking checked out",
			session_id=request.json["session_id"],
			created_at=datetime.now())

		db.session.add(booking_activity)

		try:
			db.session.commit()
			close(db)

			output = []
			output.append("Check out successful. Please proceed.")
			return jsonify({"message": output}), 200
		except Exception as e:
			print(e)
			db.session.rollback()
			close(db)

			output = []
			output.append(
				"There was a slight issue checking out. :-( Please try again later."
			)
			return jsonify({"message": output}), 422


## TODO: Update payment
@app.route("/bookings/modify", methods=["PATCH"])
def change_single_booking_date():

	validation_list = [{
		"field": "booking_id",
		"alias": "Booking ID"
	}, {
		"field": "check_in",
		"alias": "Check-in date"
	}, {
		"field": "check_out",
		"alias": "Check-out date"
	}, {
		"field": "currency"
	}, {
		"field": "session_id",
		"alias": "session ID"
	}]

	messages = fieldValidation(request.json, validation_list)

	try:
		first_name = request.json["member"]["first_name"].title()
		last_name = request.json["member"]["surname"].title()
		email = request.json["member"]["email"].lower()
		phone = request.json["member"]["tel_number"]

		booking_type = "7769748C"
		member_visit = 1

		member_details_list = [{
			"field": "first_name",
			"alias": "Member first name"
		}, {
			"field": "surname",
			"alias": "Member last name"
		}, {
			"field": "email",
			"alias": "Member email address"
		}, {
			"field": "tel_number",
			"alias": "Member phone number"
		}]

		messages = messages + fieldValidation(request.json["member"],
											  member_details_list)

	except Exception:
		first_name = request.json["first_name"].title()
		last_name = request.json["last_name"].title()
		email = request.json["email"].lower()
		phone = request.json["phone"]

		booking_type = request.json["type"]
		member_visit = None

		details_list = [{
			"field": "first_name",
			"alias": "First name"
		}, {
			"field": "last_name",
			"alias": "Last name"
		}, {
			"field": "email",
			"alias": "Email address"
		}, {
			"field": "phone",
			"alias": "Phone number"
		}]

		messages = messages + fieldValidation(request.json, details_list)

	# details_list = [
	# 	{"field": "first_name", "alias": "First name"},
	# 	{"field": "last_name", "alias": "Last name"},
	# 	{"field": "email", "alias": "Email address"},
	# 	{"field": "phone", "alias": "Phone number"}
	# ]

	# messages = messages + fieldValidation(request.json, details_list)

	if messages:
		return jsonify({"messages": messages}), 422

	today = datetime.now().strftime("%Y-%m-%d")
	check_in_date = GenerateDateFromString.generateDate(
		request.json["check_in"])
	check_out_date = GenerateDateFromString.generateDate(
		request.json["check_out"])

	temp_date_diff = DateOperations.returnDateDifferenceInDays(
		check_out_date, check_in_date)

	if temp_date_diff == 0:
		date_diff = 1
	elif temp_date_diff > 0:
		date_diff = temp_date_diff

	exchange_rate_data = requests.get(get_latest_exchange_rate)

	return_booking = db.session.query(Booking)\
	   .filter(Booking.booking_public_id == request.json["booking_id"])\
	   .first()

	if not return_booking:
		message = []
		message.append("The selected booking is not in the system.")
		return jsonify({"message": message}), 412

	if return_booking.currency != request.json["currency_id"]:
		message = []
		message.append(
			"The updated booking currency does not match the original booking currency."
		)
		return jsonify({"message": message}), 422

	# From return_booking query
	return_booking.booking_check_in_date = request.json["check_in"],
	return_booking.booking_check_out_date = request.json["check_out"],
	return_booking.status = get_booking_status_id("Updated")
	return_booking.updated_at = datetime.now()

	booking_id = return_booking.booking_public_id
	booking_ref = return_booking.booking_ref_code
	booking_done_by = return_booking.booking_done_by

	# From JSON sent
	# first_name = request.json["first_name"]
	# last_name = request.json["last_name"]
	# email = request.json["email"].lower()
	# phone = request.json["phone"]

	recipient_email = email

	try:
		send_email = request.json["send_mail"]
	except Exception:
		send_email = None

	phone_validation = validatePhoneNumber(phone)

	if phone_validation[0]:
		phone = phone_validation[1]

	else:
		message = []
		message.append(phone_validation[1])
		return jsonify({"message": message}), 422

	valid_email = validateEmail(email)

	if not valid_email:
		message = []
		message.append("The email address provided is invalid.")
		return jsonify({"message": message}), 422
	# try:
	# 	check_booking_ban(email, phone)
	# except Exception as e:
	# 	trace = traceback.format_exc()
	# 	return jsonify({"message": str(e), "trace": trace}), 422
	try:
		promo_code_json = request.json["promo_code"]

	except Exception:
		promo_code_json = None

	if promo_code_json:
		try:
			check_promo_validity = requests.post(
				promo_code_search, json={"promo_code": promo_code_json})

			if check_promo_validity.status_code != 200:
				return jsonify(
					{"message": check_promo_validity.json()["message"]}), 422

			elif check_promo_validity.status_code == 200:
				promo_code = promo_code_json
				promo_discount = int(
					check_promo_validity.json()["data"][0]["percentage_off"])
				promo_code_public_id = check_promo_validity.json(
				)["data"][0]["public_id"]

		except Exception:
			message = []
			message.append(
				"There was an issue getting the promo code details. Please try again or leave the promo code field blank."
			)
			return jsonify({"message": message}), 422

	else:
		promo_code = None
		promo_discount = None
		promo_code_public_id = None

	get_gatepass = db.session.query(Gatepass)\
	 .filter(Gatepass.status != get_booking_status_id("Updated"))\
	 .filter(Gatepass.booking_id == booking_id)\
	 .first()

	try:
		# From get_gatepass query
		old_gatepass_id = get_gatepass.gatepass_public_id


		get_gatepass_vehicles = db.session.query(GatepassVehicle)\
		  .filter(GatepassVehicle.gatepass_id == old_gatepass_id)\
		  .filter(GatepassVehicle.status != get_booking_status_id("Updated"))\
		  .all()

		for single_vehicle in get_gatepass_vehicles:
			single_vehicle.status = get_booking_status_id("Updated")
			single_vehicle.updated_at = datetime.now()

		get_gatepass_guests = db.session.query(GatepassGuest)\
		  .filter(GatepassGuest.gatepass_id == old_gatepass_id)\
		  .filter(GatepassGuest.status != get_booking_status_id("Updated"))\
		  .all()

		for single_guest in get_gatepass_guests:
			single_guest.status = get_booking_status_id("Updated")
			single_guest.updated_at = datetime.now()

		get_gatepass_details = db.session.query(GatepassDetail)\
		  .filter(GatepassDetail.gatepass_id == old_gatepass_id)\
		  .filter(GatepassDetail.status != get_booking_status_id("Updated"))\
		  .all()

		for single_gate_detail in get_gatepass_details:
			single_gate_detail.status = get_booking_status_id("Updated")
			single_gate_detail.updated_at = datetime.now()
	except Exception:
		pass
	get_latest_booking_detail = db.session.query(Detail) \
		.filter(Detail.booking_id == booking_id) \
		.order_by(Detail.created_at.desc()) \
		.first()
	print("@#@@@@get_latest_booking_detail", get_latest_booking_detail)

	get_booking_details = db.session.query(Detail)\
	  .filter(Detail.booking_id == booking_id)\
	  .filter(Detail.status != get_booking_status_id("Updated"))\
	  .all()

	for single_book_detail in get_booking_details:
		single_book_detail.status = get_booking_status_id("Updated")
		single_book_detail.updated_at = datetime.now()

	get_booking_guests = db.session.query(BookingGuest)\
	 .filter(BookingGuest.booking_id == booking_id)\
	 .filter(BookingGuest.status != get_booking_status_id("Updated"))\
	 .all()

	for single_book_guest in get_booking_guests:
		single_book_guest.status = get_booking_status_id("Updated")
		single_book_guest.updated_at = datetime.now()

	old_facility_list_ui = []
	old_facility_list_db = []

	for facility_old_single in request.json["old_facilities"]:
		old_facility_list_ui.append(
			facility_old_single["facility_booking_public_id"])

	get_booking_accommodation = db.session.query(Facility)\
	  .filter(Facility.booking_id == booking_id)\
	  .filter(Facility.deletion_marker == None)\
	  .filter(Facility.external_facility == None)\
	  .filter(Facility.status != get_booking_status_id("Updated"))\
	  .filter(Facility.status != get_booking_status_id("Cancelled"))\
	  .all()

	for facility_old_db_single in get_booking_accommodation:
		old_facility_list_db.append(
			facility_old_db_single.facility_booking_public_id)

	for single_old_facility in old_facility_list_db:
		if single_old_facility in old_facility_list_ui:
			pass
		else:
			get_accommodation = db.session.query(Facility)\
			   .filter(Facility.booking_id == booking_id)\
			   .first()

			get_accommodation.status = get_booking_status_id("Updated")
			get_accommodation.updated_at = datetime.now()

	old_external_facility_list_ui = []
	old_external_facility_list_db = []
	try:
		for external_facility_old_single in request.json[
				"old_external_facilities"]:
			old_external_facility_list_ui.append(
				external_facility_old_single["facility_booking_public_id"])

		get_booking_external_accommodation = db.session.query(Facility)\
		.filter(Facility.booking_id == booking_id)\
		.filter(Facility.deletion_marker == None)\
		.filter(Facility.external_facility == 1)\
		.filter(Facility.status != get_booking_status_id("Updated"))\
		.filter(Facility.status != get_booking_status_id("Cancelled"))\
		.all()

		for external_facility_old_db_single in get_booking_external_accommodation:
			old_external_facility_list_db.append(
				external_facility_old_db_single.facility_booking_public_id)

		for single_old_external_facility in old_external_facility_list_db:
			if single_old_external_facility in old_external_facility_list_ui:
				pass
			else:
				get_external_accommodation = db.session.query(Facility)\
				.filter(Facility.facility_booking_public_id == single_old_external_facility)\
				.first()

				get_external_accommodation.status = get_booking_status_id(
					"Updated")
				get_external_accommodation.updated_at = datetime.now()
	except Exception as e:
		pass
	old_inventory_list_ui = []
	old_inventory_list_db = []

	for inventory_old_single in request.json["old_inventory"]:
		old_inventory_list_ui.append(
			inventory_old_single["inventory_booking_public_id"])

	get_booking_activity = db.session.query(Inventory)\
	   .filter(Inventory.booking_id == booking_id)\
	   .filter(Inventory.deletion_marker == None)\
	   .filter(Inventory.status != get_booking_status_id("Updated"))\
	   .filter(Inventory.status != get_booking_status_id("Cancelled"))\
	   .all()

	for inventory_old_db_single in get_booking_activity:
		old_inventory_list_db.append(
			inventory_old_db_single.inventory_booking_public_id)

	for single_old_inventory in old_inventory_list_db:
		if single_old_inventory in old_inventory_list_ui:
			pass
		else:
			get_activity = db.session.query(Inventory)\
			 .filter(Inventory.inventory_booking_public_id == single_old_inventory)\
			 .first()

			get_activity.status = get_booking_status_id("Updated")
			get_activity.updated_at = datetime.now()

	# From get_gatepass query
	get_gatepass.status = get_booking_status_id("Updated")
	get_gatepass.updated_at = datetime.now()

	for gatepass_guest in request.json["guests"]:
		get_guest_type = db.session.query(Mandatory)\
		 .filter(Mandatory.payment_public_id == gatepass_guest["payment_public_id"])\
		 .first()

		try:
			guest_count = int(gatepass_guest["payment_guests"])
		except Exception:
			guest_count = 0

		guest = BookingGuest(booking_guest_public_id=str(uuid.uuid4()),
							 booking_id=booking_id,
							 guest_type=get_booking_guest_type_id(
								 get_guest_type.payment_person.lower()),
							 guest_count=guest_count,
							 session_id=request.json["session_id"],
							 created_at=datetime.now())

		db.session.add(guest)
	try:
		entry_mode = request.json["entry_mode"]
	except KeyError as entry_mode_error:
		entry_mode = None
	try:
		entry_point = request.json["entry_point"]
	except KeyError as entry_point_error:
		entry_point = None

	try:
		kra_pin_number = request.json["kra_pin_number"]
	except KeyError as kra_pin_number_error:
		kra_pin_number = None

	print("kra pin is herre", kra_pin_number)

	try:
		country_code = request.json["code"]
	except KeyError as country_code_key_error:
		country_code = None

	try:
		country = request.json["country_details"]['name']
	except KeyError as country_key_error:
		country = None
	try:
		city = request.json["city"]
	except KeyError as city_key_error:
		city = None
	try:
		mode_registration = request.json["mode_registration"]
	except KeyError as mode_registration_error:
		mode_registration = None
	try:
		address = request.json["address"]
	except KeyError as address_key_error:
		address = None

	if not country_code:
		country_code = get_latest_booking_detail.country_code

	if not country:
		country = get_latest_booking_detail.country

	if not city:
		city = get_latest_booking_detail.city

	if not kra_pin_number:
		kra_pin_number = get_latest_booking_detail.kra_pin_number

	if not entry_mode:
		entry_mode = get_latest_booking_detail.entry_mode

	if not entry_point:
		entry_point = get_latest_booking_detail.entry_point

	if not mode_registration:
		mode_registration = get_latest_booking_detail.mode_registration

	if not address:
		address = get_latest_booking_detail.address
	detail = Detail(booking_details_public_id=str(uuid.uuid4()),
					booking_id=booking_id,
					first_name=first_name,
					last_name=last_name,
					email_address=email,
					phone_number=phone,
					country=country,
					country_code=country_code,
					city=city,
					address=address,
					entry_mode=entry_mode,
					entry_point=entry_point,
					mode_registration=mode_registration,
					kra_pin_number=kra_pin_number,
					session_id=request.json["session_id"],
					created_at=datetime.now())
	# detail = Detail(booking_details_public_id=str(uuid.uuid4()),
	# 				booking_id=booking_id,
	# 				first_name=first_name,
	# 				last_name=last_name,
	# 				email_address=email,
	# 				phone_number=phone,
	# 				entry_mode=entry_mode,
	# 				entry_point=entry_point,
	# 				mode_registration=mode_registration,
	# 				kra_pin_number=kra_pin_number,
	# 				session_id=request.json["session_id"],
	# 				created_at=datetime.now())

	db.session.add(detail)

	try:
		destination = request.json["destination"]
	except (KeyError) as destination_error:
		destination = None

	# New gatepass ID
	gatepass_id = str(uuid.uuid4())

	gatepass = Gatepass(gatepass_public_id=gatepass_id,
						gatepass_date=today,
						gatepass_done_by=first_name + " " + last_name,
						destination=destination,
						gatepass_phone_number=phone,
						gatepass_ref_code=str(uuid.uuid4())[:10],
						booking_id=booking_id,
						booking=1,
						start_date=request.json["check_in"],
						end_date=request.json["check_out"],
						gatepass_currency=request.json["currency_id"],
						gatepass_payment_status=1,
						session_id=request.json["session_id"],
						created_at=datetime.now())

	db.session.add(gatepass)

	for each_gatepass_guest in request.json["guests"]:
		get_gatepass_fee = db.session.query(MandatoryPaymentPrices)\
		  .join(Mandatory, MandatoryPaymentPrices.payment_category == Mandatory.payment_public_id)\
		  .add_columns(MandatoryPaymentPrices.price_public_id, MandatoryPaymentPrices.payment_schedule, MandatoryPaymentPrices.payment_category,\
		   MandatoryPaymentPrices.payment_currency, MandatoryPaymentPrices.payment_price,\
		   Mandatory.payment_person)\
		  .filter(MandatoryPaymentPrices.payment_schedule == each_gatepass_guest["gatepass_payment_schedule"])\
		  .filter(MandatoryPaymentPrices.payment_category == each_gatepass_guest["payment_public_id"])\
		  .first()

		# try:
		# if get_gatepass_fee:
		# 	gatepass = get_gatepass_fee.payment_price
		# 	else:
		# 		gatepass = 0

		# except (ValueError, TypeError) as no_value:
		# 	gatepass = 0

		gatepass = get_gatepass_fee.payment_price
		gatepass_currency = get_gatepass_fee.payment_currency

		gatepass_amount = currencyHandler(request.json["currency_id"],
										  get_gatepass_fee.payment_currency,
										  gatepass)

		get_ex_rate = requests.get(
			get_buy_sell_rate.format(get_gatepass_fee.payment_currency))

		try:
			buying = get_ex_rate.json()["data"][0]["currency_buy_amount"]
			selling = get_ex_rate.json()["data"][0]["currency_sell_amount"]

		except Exception:
			buying = 1
			selling = 1

		if promo_discount:
			person_discount = promo_discount
		else:
			try:
				person_discount = float(
					each_gatepass_guest["payment_person_discount"])
			except Exception:
				person_discount = 0

		if promo_discount:
			person_discount_reason = promo_code
		else:
			try:
				person_discount_reason = each_gatepass_guest["reason"]
			except Exception:
				person_discount_reason = None

		try:
			guests = int(each_gatepass_guest["payment_guests"])
		except Exception:
			guests = 0

		gatepass_guest = GatepassGuest(
			gatepass_guest_public_id=str(uuid.uuid4()),
			gatepass_id=gatepass_id,
			gatepass_guest_type=each_gatepass_guest["payment_public_id"],
			gatepass_guest_count=guests,
			gatepass_discount_rate=person_discount,
			gatepass_discount_reason=each_gatepass_guest[
				"payment_person_discount_reason"],
			gatepass_cost_per_pp=round(gatepass_amount, 2),
			gatepass_payment_schedule=each_gatepass_guest[
				"gatepass_payment_schedule"],
			gatepass_no_of_nights=date_diff,
			gatepass_currency=request.json["currency_id"],
			gatepass_guest_cost_at_time=round(gatepass),
			gatepass_guest_currency_at_time=get_gatepass_fee.payment_currency,
			# gatepass_guest_currency_at_time=gatepass_currency,
			gatepass_guest_rate_at_time=buying,
			session_id=request.json["session_id"],
			created_at=datetime.now())

		db.session.add(gatepass_guest)

	gatepass_detail = GatepassDetail(gatepass_details_public_id=str(
		uuid.uuid4()),
									 gatepass_id=gatepass_id,
									 first_name=first_name,
									 last_name=last_name,
									 email_address=email,
									 phone_number=phone,
									 session_id=request.json["session_id"],
									 created_at=datetime.now())

	db.session.add(gatepass_detail)

	for each_vehicle in request.json["vehicles"]:
		get_cost = db.session.query(Vehicle)\
		   .filter(Vehicle.deletion_marker == None)\
		   .filter(Vehicle.vehicle_charge_public_id == each_vehicle["vehicle_charge_public_id"])\
		   .first()

		try:
			vehicle = get_cost.vehicle_charge_category_cost
		except (ValueError, TypeError) as no_value:
			vehicle = 0

		vehicle_fee = currencyHandler(request.json["currency_id"],
									  get_cost.vehicle_charge_cost_currency,
									  vehicle)

		get_ex_rate = requests.get(
			get_buy_sell_rate.format(get_cost.vehicle_charge_cost_currency))

		try:
			buying = get_ex_rate.json()["data"][0]["currency_buy_amount"]
			selling = get_ex_rate.json()["data"][0]["currency_sell_amount"]

		except Exception:
			buying = 1
			selling = 1

		if promo_discount:
			vehicle_discount = promo_discount
		else:
			try:
				vehicle_discount = float(each_vehicle["discount"])
			except Exception:
				vehicle_discount = 0

		if promo_code:
			vehicle_discount_reason = promo_code
		else:
			try:
				vehicle_discount_reason = each_vehicle["discount_reason"]
			except Exception:
				vehicle_discount_reason = None

		try:
			vehicles = int(each_vehicle["vehicles"])
		except Exception:
			vehicles = 0

		gatepass_vehicle = GatepassVehicle(
			gatepass_vehicle_public_id=str(uuid.uuid4()),
			gatepass_id=gatepass_id,
			gatepass_vehicle_type=each_vehicle["vehicle_charge_public_id"],
			gatepass_vehicle_count=vehicles,
			gatepass_cost_per_vehicle=round(vehicle_fee),
			gatepass_vehicle_currency=request.json["currency_id"],
			gatepass_vehicle_no_of_nights=date_diff,
			gatepass_vehicle_discount_rate=vehicle_discount,
			gatepass_vehicle_discount_reason=vehicle_discount_reason,
			gatepass_vehicle_cost_at_time=round(vehicle),
			gatepass_vehicle_currency_at_time=get_cost.
			vehicle_charge_cost_currency,
			gatepass_vehicle_rate_at_time=buying,
			session_id=request.json["session_id"],
			created_at=datetime.now())

		db.session.add(gatepass_vehicle)

	booking_info = {}
	booking_info["booking_id"] = booking_id
	booking_info["booking_ref"] = booking_ref
	booking_info["first_name"] = first_name
	booking_info["last_name"] = last_name

	## Facility booking handler
	facility_email_data = []
	try:
		facilityBooking(request.json,
						booking_info,
						facility_email_data,
						currency_id=True)
	except Exception as e:
		error_tuple = sys.exc_info()
		trace = traceback.format_exc()
		return jsonify({"message": str(e), "trace": trace}), 422

	## Activity booking handler
	inventory_email_data = []

	try:
		inventoryBooking(request.json,
						 booking_info,
						 inventory_email_data,
						 currency_id=True)
	except Exception as e:
		error_tuple = sys.exc_info()
		trace = traceback.format_exc()
		return jsonify({"message": str(e), "trace": trace}), 422

	get_booking_exchange_rate = requests.get(
		get_buy_sell_rate.format(request.json["currency_id"]))
	booking_buying_rate = get_booking_exchange_rate.json(
	)["data"][0]["currency_buy_amount"]
	booking_selling_rate = get_booking_exchange_rate.json(
	)["data"][0]["currency_sell_amount"]

	return_booking.booking_done_by = first_name + " " + last_name
	return_booking.currency = request.json["currency_id"]
	return_booking.currency_buying_rate_at_time = booking_buying_rate
	return_booking.currency_selling_rate_at_time = booking_selling_rate
	return_booking.booking_check_in_date = request.json["check_in"]
	return_booking.booking_check_out_date = request.json["check_out"]
	return_booking.status = get_booking_status_id("Updated")
	return_booking.updated_at = datetime.now()

	booking_activity = BookingActivity(
		booking_activity_public_id=str(uuid.uuid4()),
		booking_id=booking_id,
		booking_activity_description="Booking updated",
		session_id=request.json["session_id"],
		created_at=datetime.now())

	db.session.add(booking_activity)
	try:
		if request.json["proof_of_residency"]:
			residecy_proof_db = db.session.query(ResidencyProof)\
			.filter(ResidencyProof.deletion_marker == None)\
			.filter(ResidencyProof.booking_id == booking_id)\
			.options(FromCache(db_cache))\
			.all()
			for single_proof in residecy_proof_db:
				single_proof.deletion_marker = 1
				single_proof.updated_at = datetime.now()
			newResidencyProof(request.json["proof_of_residency"], booking_id,
							  request.json["session_id"])

	except Exception as e:
		pass
		# trace = traceback.format_exc()
		# return jsonify({"message": str(e), "trace": trace}), 422
	if request.json["note"]:
		new_note = Note(booking_notes_public_id=str(uuid.uuid4()),
						booking_id=booking_id,
						note=request.json["note"],
						session_id=request.json["session_id"],
						created_at=datetime.now())

		db.session.add(new_note)

	try:
		db.session.commit()
		close(db)

		if booking_id == "c9f036b1-eaec-4c92-bbd1-9e84895aeed3":
			get_transactions = db.session.query(Transaction)\
			 .filter(Transaction.deletion_marker == None)\
			 .filter(Transaction.booking_id == booking_id)\
			 .all()

			if get_transactions:
				booking_data = {}
				bookingTotal(booking_data, booking_id)

				new_booking_total = booking_data["total_cost"]
				new_booking_currency = request.json["currency_id"]

				for single_transaction in get_transactions:
					single_transaction.transaction_original_cost = new_booking_total
					single_transaction.transaction_total_currency = new_booking_currency

					new_balance = currencyPostProcessor(new_booking_currency, single_transaction.transaction_payment_currency,\
					   single_transaction.transaction_balance, single_transaction.payment_currency_buying_rate_at_time,\
					   single_transaction.payment_currency_selling_rate_at_time)

					single_transaction.transaction_balance = new_balance
					single_transaction.updated_at = datetime.now()

				db.session.commit()
				close(db)

		if send_email:
			email_data = {}
			email_data["subject"] = "Booking ID #" + booking_ref + " Update"
			email_data["recipient"] = [recipient_email]
			email_data["sender"] = "reservations@olpejetaconservancy.org"
			email_data["booking_ref_code"] = booking_ref
			email_data["done_by"] = booking_done_by
			email_data["booking_id"] = booking_id

			send_booking_update_email(email_data)

		message = []
		message.append("Successfully updated the booking.")
		return jsonify({"message": message}), 200

	except Exception:
		db.session.rollback()
		close(db)

		trace = traceback.format_exc()

		message = []
		message.append(
			"There was an error updating the booking. Please try again later.")
		return jsonify({"message": message, "trace": trace}), 422


## TODO: Postpone booking
@app.route("/bookings/postpone", methods=["PATCH"])
def postpone_booking_date():

	validation_list = [{
		"field": "booking_id",
		"alias": "Booking ID"
	}, {
		"field": "check_in",
		"alias": "Check-in date"
	}, {
		"field": "check_out",
		"alias": "Check-out date"
	}, {
		"field": "currency"
	}, {
		"field": "session_id",
		"alias": "session ID"
	}]

	messages = fieldValidation(request.json, validation_list)

	try:
		first_name = request.json["member"]["first_name"].title()
		last_name = request.json["member"]["surname"].title()

		member_details_list = [{
			"field": "first_name",
			"alias": "Member first name"
		}, {
			"field": "surname",
			"alias": "Member last name"
		}, {
			"field": "email",
			"alias": "Member email address"
		}, {
			"field": "tel_number",
			"alias": "Member phone number"
		}]

		messages = messages + fieldValidation(request.json["member"],
											  member_details_list)

	except Exception:
		first_name = request.json["first_name"].title()
		last_name = request.json["last_name"].title()
		details_list = [{
			"field": "first_name",
			"alias": "First name"
		}, {
			"field": "last_name",
			"alias": "Last name"
		}, {
			"field": "email",
			"alias": "Email address"
		}, {
			"field": "phone",
			"alias": "Phone number"
		}]

		messages = messages + fieldValidation(request.json, details_list)

	if messages:
		return jsonify({"messages": messages}), 422

	try:
		session_id = request.json["session_id"]
	except Exception:
		session_id = None

	return_booking = db.session.query(Booking)\
	   .filter(Booking.booking_public_id == request.json["booking_id"])\
	   .first()

	if not return_booking:
		message = []
		message.append("The selected booking is not in the system.")
		return jsonify({"message": message}), 412

	# From return_booking query
	return_booking.before_postpone_booking_check_in_date = return_booking.booking_check_in_date,
	return_booking.before_postpone_booking_check_out_date = return_booking.booking_check_out_date,
	return_booking.booking_check_in_date = request.json["check_in"],
	return_booking.booking_check_out_date = request.json["check_out"],
	return_booking.status = get_booking_status_id("Postponed")
	return_booking.updated_at = datetime.now()
	return_booking.session_id = session_id
	booking_id = return_booking.booking_public_id
	booking_ref = return_booking.booking_ref_code


	get_gatepass = db.session.query(Gatepass)\
	 .filter(Gatepass.status != get_booking_status_id("Updated"))\
	 .filter(Gatepass.booking_id == booking_id)\
	 .first()

	try:
		# From get_gatepass query
		old_gatepass_id = get_gatepass.gatepass_public_id

		get_gatepass_vehicles = db.session.query(GatepassVehicle)\
		  .filter(GatepassVehicle.gatepass_id == old_gatepass_id)\
		  .filter(GatepassVehicle.status != get_booking_status_id("Updated"))\
		  .all()

		for single_vehicle in get_gatepass_vehicles:
			single_vehicle.status = get_booking_status_id("Postponed")
			single_vehicle.updated_at = datetime.now()
			single_vehicle.session_id = session_id

		get_gatepass_guests = db.session.query(GatepassGuest)\
		  .filter(GatepassGuest.gatepass_id == old_gatepass_id)\
		  .filter(GatepassGuest.status != get_booking_status_id("Updated"))\
		  .all()

		for single_guest in get_gatepass_guests:
			single_guest.status = get_booking_status_id("Postponed")
			single_guest.updated_at = datetime.now()
			single_guest.session_id = session_id

		get_gatepass_details = db.session.query(GatepassDetail)\
		  .filter(GatepassDetail.gatepass_id == old_gatepass_id)\
		  .filter(GatepassDetail.status != get_booking_status_id("Updated"))\
		  .all()

		for single_gate_detail in get_gatepass_details:
			single_gate_detail.status = get_booking_status_id("Postponed")
			single_gate_detail.updated_at = datetime.now()
			single_gate_detail.session_id = session_id

		get_booking_details = db.session.query(Detail)\
		.filter(Detail.booking_id == booking_id)\
		.filter(Detail.status != get_booking_status_id("Updated"))\
		.all()

		for single_book_detail in get_booking_details:
			single_book_detail.status = get_booking_status_id("Postponed")
			single_book_detail.updated_at = datetime.now()
			single_book_detail.session_id = session_id

		get_booking_guests = db.session.query(BookingGuest)\
		.filter(BookingGuest.booking_id == booking_id)\
		.filter(BookingGuest.status != get_booking_status_id("Updated"))\
		.all()

		for single_book_guest in get_booking_guests:
			single_book_guest.status = get_booking_status_id("Postponed")
			single_book_guest.updated_at = datetime.now()
			single_book_guest.session_id = session_id

		current_checkin_date = get_gatepass.start_date
		current_checkout_date = get_gatepass.end_date

		# From get_gatepass query
		get_gatepass.before_postpone_start_date = get_gatepass.start_date
		get_gatepass.before_postpone_end_date = get_gatepass.end_date
		get_gatepass.status = get_booking_status_id("Postponed")
		get_gatepass.updated_at = datetime.now()
		get_gatepass.gatepass_done_by = first_name + " " + last_name,
		get_gatepass.start_date = request.json["check_in"],
		get_gatepass.end_date = request.json["check_out"],
		get_gatepass.session_id = request.json["session_id"],
		get_gatepass.updated_at = datetime.now()

		# except Exception:
	except Exception as e:
		db.session.rollback()
		close(db)
		error_tuple = sys.exc_info()
		trace = traceback.format_exc()
		return jsonify({"message": str(e), "trace": trace}), 422

	booking_info = {}
	booking_info["booking_id"] = booking_id
	booking_info["booking_ref"] = booking_ref
	booking_info["first_name"] = first_name
	booking_info["last_name"] = last_name

	## Facility booking handler
	facility_email_data = []
	try:
		postponeFacilityBooking(request.json,
								booking_info,
								facility_email_data,
								currency_id=True)
	except Exception as e:
		db.session.rollback()
		close(db)
		error_tuple = sys.exc_info()
		trace = traceback.format_exc()
		return jsonify({"message": str(e), "trace": trace}), 422

	## Activity booking handler
	inventory_email_data = []
	try:
		postponeInventoryBooking(request.json,
								 booking_info,
								 inventory_email_data,
								 currency_id=True)
	except Exception as e:
		db.session.rollback()
		close(db)
		error_tuple = sys.exc_info()
		trace = traceback.format_exc()

		return jsonify({"message": str(e), "trace": trace}), 422

	bookingdets = "Booking postponed from checkin date " + str(
		current_checkin_date) + " and checkout date " + str(
			current_checkout_date) + " to checkin date " + str(
				request.json["check_in"]) + " and checkout date " + str(
					request.json["check_in"])

	booking_activity = BookingActivity(
		booking_activity_public_id=str(uuid.uuid4()),
		booking_id=booking_id,
		booking_activity_description=bookingdets,
		session_id=session_id,
		created_at=datetime.now())

	db.session.add(booking_activity)

	try:
		db.session.commit()
		close(db)
		message = []
		message.append("Successfully postponed the booking.")
		return jsonify({"message": message}), 200

	except Exception:
		db.session.rollback()
		close(db)

		trace = traceback.format_exc()

		message = []
		message.append(
			"There was an error postponing the booking. Please try again later."
		)
		return jsonify({"message": message, "trace": trace}), 422


## TODO: Cancel booking
@app.route("/bookings/cancel", methods=["PATCH"])
def cancel_single_booking():
	messages = []

	try:
		request.json["booking_id"].strip()
		if not request.json["booking_id"]:
			messages.append("Booking ID is empty.")
	except KeyError as e:
		messages.append("Booking ID is missing.")

	try:
		request.json["session_id"].strip()
		if not request.json["session_id"]:
			messages.append("Session ID is empty.")
	except KeyError as e:
		messages.append("Session ID is missing.")

	if messages:
		output = []
		output.append("You appear to be missing some data. Please try again.")
		return jsonify({"message": output, "messages": messages}), 422

	return_booking = db.session.query(Booking)\
	   .filter(Booking.booking_public_id==request.json["booking_id"])\
	   .filter(Booking.deletion_marker==None)\
	   .first()

	if not return_booking:
		output = []
		output.append("That booking does not exist.")
		return jsonify({"message": output}), 200
	else:
		return_booking.status = get_booking_status_id("Cancelled")
		return_booking.updated_at = datetime.now()

		get_booking_guests = db.session.query(BookingGuest)\
		 .filter(BookingGuest.deletion_marker == None)\
		 .filter(BookingGuest.booking_id == return_booking.booking_public_id)\
		 .all()

		for each_booking_guest in get_booking_guests:
			each_booking_guest.status = get_booking_status_id("Cancelled")
			each_booking_guest.updated_at = datetime.now()

		get_booking_details = db.session.query(Detail)\
		  .filter(Detail.deletion_marker == None)\
		  .filter(Detail.booking_id == return_booking.booking_public_id)\
		  .first()

		get_booking_details.status = get_booking_status_id("Cancelled")
		get_booking_details.updated_at = datetime.now()

		get_all_facilities = db.session.query(Facility)\
		 .filter(Facility.deletion_marker == None)\
		 .filter(Facility.booking_id ==  return_booking.booking_public_id)\
		 .all()

		for each_facility in get_all_facilities:
			each_facility.status = get_booking_status_id("Cancelled")
			each_facility.updated_at = datetime.now()


		get_all_inventory = db.session.query(Inventory)\
		   .filter(Inventory.deletion_marker == None)\
		   .filter(Inventory.booking_id == return_booking.booking_public_id)\
		   .all()

		for each_inventory in get_all_inventory:
			each_inventory.status = get_booking_status_id("Cancelled")
			each_inventory.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_inventory.session_id = request.json["session_id"]

		get_gatepass = db.session.query(Gatepass)\
		 .filter(Gatepass.deletion_marker == None)\
		 .filter(Gatepass.booking_id ==  return_booking.booking_public_id)\
		 .first()

		get_gatepass.status = get_booking_status_id("Cancelled")
		get_gatepass.updated_at = datetime.now()

		## Commented out in order to stop updating the user.
		# get_gatepass.session_id = request.json["session_id"]

		get_gatepass_guests = db.session.query(GatepassGuest)\
		  .filter(GatepassGuest.deletion_marker == None)\
		  .filter(GatepassGuest.gatepass_id == get_gatepass.gatepass_public_id)\
		  .all()

		for each_gatepass_guest in get_gatepass_guests:
			each_gatepass_guest.status = get_booking_status_id("Cancelled")
			each_gatepass_guest.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_gatepass_guest.session_id = request.json["session_id"]

		get_gatepass_details = db.session.query(GatepassDetail)\
		   .filter(GatepassDetail.deletion_marker == None)\
		   .filter(GatepassDetail.gatepass_id == get_gatepass.gatepass_public_id)\
		   .first()

		get_gatepass_details.status = get_booking_status_id("Cancelled")
		get_gatepass_details.updated_at = datetime.now()

		## Commented out in order to stop updating the user.
		# get_gatepass_details.session_id = request.json["session_id"]

		get_gatepass_vehicles = db.session.query(GatepassVehicle)\
		 .filter(GatepassVehicle.deletion_marker == None)\
		 .filter(GatepassVehicle.gatepass_id == get_gatepass.gatepass_public_id)\
		 .all()

		for each_gatepass_vehicle in get_gatepass_vehicles:
			each_gatepass_vehicle.status = get_booking_status_id("Cancelled")
			each_gatepass_vehicle.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_gatepass_vehicle.session_id = request.json["session_id"]

		try:
			db.session.commit()
			close(db)

			output = []
			output.append("The booking has been cancelled.")
			return jsonify({"message": output}), 200
		except Exception as e:
			print(e)
			db.session.rollback()
			close(db)

			output = []
			output.append(
				"There was a slight issue cancelling the booking. Please try again later."
			)
			return jsonify({"message": output}), 422


@app.route("/bookings/delete", methods=["PATCH"])
def delete_single_booking():
	messages = []

	try:
		request.json["booking_id"].strip()
		if not request.json["booking_id"]:
			messages.append("Booking ID is empty.")
	except KeyError as e:
		messages.append("Booking ID is missing.")

	try:
		request.json["session_id"].strip()
		if not request.json["session_id"]:
			messages.append("Session ID is empty.")
	except KeyError as e:
		messages.append("Session ID is missing.")

	if messages:
		output = []
		output.append("You appear to be missing some data. Please try again.")
		return jsonify({"messages": messages}), 422

	return_booking = db.session.query(Booking)\
	   .filter(Booking.booking_public_id == request.json["booking_id"])\
	   .filter(Booking.deletion_marker == None)\
	   .first()

	if not return_booking:
		output = []
		output.append(
			"The selected booking does not exist or has already been cancelled."
		)
		return jsonify({"message": output}), 200
	else:
		return_booking.status = get_booking_status_id("Cancelled")
		return_booking.deletion_marker = 1
		return_booking.updated_at = datetime.now()

		## Commented out in order to stop updating the user.
		# return_booking.session_id = request.json["session_id"]

		booking_ref_code = return_booking.booking_ref_code
		booking_done_by = return_booking.booking_done_by

		booking_activity = BookingActivity(
			booking_activity_public_id=str(uuid.uuid4()),
			booking_id=request.json["booking_id"],
			booking_activity_description="Booking cancelled",
			session_id=request.json["session_id"],
			created_at=datetime.now())

		db.session.add(booking_activity)

		get_booking_guests = db.session.query(BookingGuest)\
		 .filter(BookingGuest.deletion_marker == None)\
		 .filter(BookingGuest.booking_id == return_booking.booking_public_id)\
		 .all()

		for each_booking_guest in get_booking_guests:
			each_booking_guest.status = get_booking_status_id("Cancelled")
			each_booking_guest.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_booking_guest.session_id = request.json["session_id"]

		get_booking_details = db.session.query(Detail)\
		  .filter(Detail.deletion_marker == None)\
		  .filter(Detail.booking_id == return_booking.booking_public_id)\
		  .first()

		try:
			get_booking_details.status = get_booking_status_id("Cancelled")
			get_booking_details.updated_at = datetime.now()
		except Exception:
			pass

		## Commented out in order to stop updating the user.
		# get_booking_details.session_id = request.json["session_id"]

		try:
			recipient_email = get_booking_details.email_address
		except Exception:
			recipient_email = None

		get_all_facilities = db.session.query(Facility)\
		 .filter(Facility.deletion_marker == None)\
		 .filter(Facility.booking_id ==  return_booking.booking_public_id)\
		 .all()

		for each_facility in get_all_facilities:
			each_facility.status = get_booking_status_id("Cancelled")
			each_facility.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_facility.session_id = request.json["session_id"]

		get_all_inventory = db.session.query(Inventory)\
		   .filter(Inventory.deletion_marker == None)\
		   .filter(Inventory.booking_id == return_booking.booking_public_id)\
		   .all()

		for each_inventory in get_all_inventory:
			each_inventory.status = get_booking_status_id("Cancelled")
			each_inventory.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_inventory.session_id = request.json["session_id"]

		get_gatepass = db.session.query(Gatepass)\
		 .filter(Gatepass.deletion_marker == None)\
		 .filter(Gatepass.booking_id ==  return_booking.booking_public_id)\
		 .first()

		try:
			get_gatepass.status = get_booking_status_id("Cancelled")
			get_gatepass.updated_at = datetime.now()
		except Exception:
			pass

		## Commented out in order to stop updating the user.
		# get_gatepass.session_id = request.json["session_id"]

		try:
			get_gatepass_guests = db.session.query(GatepassGuest)\
			  .filter(GatepassGuest.deletion_marker == None)\
			  .filter(GatepassGuest.gatepass_id == get_gatepass.gatepass_public_id)\
			  .all()

			for each_gatepass_guest in get_gatepass_guests:
				each_gatepass_guest.status = get_booking_status_id("Cancelled")
				each_gatepass_guest.updated_at = datetime.now()
		except Exception:
			pass

			## Commented out in order to stop updating the user.
			# each_gatepass_guest.session_id = request.json["session_id"]

		try:
			get_gatepass_details = db.session.query(GatepassDetail)\
			  .filter(GatepassDetail.deletion_marker == None)\
			  .filter(GatepassDetail.gatepass_id == get_gatepass.gatepass_public_id)\
			  .first()

			get_gatepass_details.status = get_booking_status_id("Cancelled")
			get_gatepass_details.updated_at = datetime.now()
		except Exception:
			pass

		## Commented out in order to stop updating the user.
		# get_gatepass_details.session_id = request.json["session_id"]

		try:
			get_gatepass_vehicles = db.session.query(GatepassVehicle)\
			  .filter(GatepassVehicle.deletion_marker == None)\
			  .filter(GatepassVehicle.gatepass_id == get_gatepass.gatepass_public_id)\
			  .all()

			for each_gatepass_vehicle in get_gatepass_vehicles:
				each_gatepass_vehicle.status = get_booking_status_id(
					"Cancelled")
				each_gatepass_vehicle.updated_at = datetime.now()
		except Exception:
			pass

			## Commented out in order to stop updating the user.
			# each_gatepass_vehicle.session_id = request.json["session_id"]

		try:
			db.session.commit()
			close(db)

			if recipient_email:
				email_data = {}
				email_data[
					"subject"] = "Booking ID #" + booking_ref_code + " Cancellation"
				email_data["recipient"] = [recipient_email,"cancelledbookings@olpejetaconservancy.org"]
				email_data["sender"] = "reservations@olpejetaconservancy.org"
				email_data["booking_ref_code"] = booking_ref_code
				email_data["done_by"] = booking_done_by
				email_data["booking_id"] = request.json["booking_id"]

				send_booking_cancellation_email(email_data)

			message = []
			# message.append("The details of the booking have been deleted successfully.")
			message.append("The booking has been cancelled.")
			return jsonify({"message": message}), 200
		except Exception as e:
			print(e)
			db.session.rollback()
			close(db)

			message = []
			# message.append("There was a slight issue deleting the details of the booking. :-( Please try again later.")
			message.append(
				"There was a slight issue cancelling the booking. Please try again later."
			)
			return jsonify({"message": message, "error": str(e)}), 422


@app.route("/bookings/reinstate", methods=["PATCH"])
def reinstate_single_booking():
	messages = []

	try:
		request.json["booking_id"].strip()
		if not request.json["booking_id"]:
			messages.append("Booking ID is empty.")
	except KeyError as e:
		messages.append("Booking ID is missing.")

	try:
		request.json["session_id"].strip()
		if not request.json["session_id"]:
			messages.append("Session ID is empty.")
	except KeyError as e:
		messages.append("Session ID is missing.")

	if messages:
		output = []
		output.append("You appear to be missing some data. Please try again.")
		return jsonify({"messages": messages}), 422

	return_booking = db.session.query(Booking)\
	   .filter(Booking.booking_public_id == request.json["booking_id"])\
	   .filter(Booking.status == get_booking_status_id("Cancelled"))\
	   .first()

	if not return_booking:
		output = []
		output.append(
			"The selected booking does not exist or has already been reinstated."
		)
		return jsonify({"message": output}), 200
	else:
		return_booking.status = get_booking_status_id("Updated")
		return_booking.deletion_marker = None
		return_booking.updated_at = datetime.now()

		## Commented out in order to stop updating the user.
		# return_booking.session_id = request.json["session_id"]

		booking_activity = BookingActivity(
			booking_activity_public_id=str(uuid.uuid4()),
			booking_id=request.json["booking_id"],
			booking_activity_description="Booking reinstated",
			session_id=request.json["session_id"],
			created_at=datetime.now())

		db.session.add(booking_activity)

		get_booking_guests = db.session.query(BookingGuest)\
		 .filter(BookingGuest.deletion_marker == None)\
		 .filter(BookingGuest.status == get_booking_status_id("Cancelled"))\
		 .filter(BookingGuest.booking_id == return_booking.booking_public_id)\
		 .all()

		for each_booking_guest in get_booking_guests:
			each_booking_guest.status = "1"
			each_booking_guest.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_booking_guest.session_id = request.json["session_id"]

		## TODO: How is it that not all booking details are set to 'Cancelled?'
		## Case in point: Booking ID 4fef316f-aed3-4894-925a-993ae32e1f21
		get_booking_details = db.session.query(Detail)\
		  .filter(Detail.deletion_marker == None)\
		  .filter(Detail.booking_id == return_booking.booking_public_id)\
		  .first()

		get_booking_details.status = "1"
		get_booking_details.updated_at = datetime.now()

		## Commented out in order to stop updating the user.
		# get_booking_details.session_id = request.json["session_id"]

		get_all_facilities = db.session.query(Facility)\
		 .filter(Facility.deletion_marker == None)\
		 .filter(Facility.status == get_booking_status_id("Cancelled"))\
		 .filter(Facility.booking_id ==  return_booking.booking_public_id)\
		 .all()

		for each_facility in get_all_facilities:
			each_facility.status = "1"
			each_facility.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_facility.session_id = request.json["session_id"]

		get_all_inventory = db.session.query(Inventory)\
		   .filter(Inventory.deletion_marker == None)\
		   .filter(Inventory.status == get_booking_status_id("Cancelled"))\
		   .filter(Inventory.booking_id == return_booking.booking_public_id)\
		   .all()

		for each_inventory in get_all_inventory:
			each_inventory.status = "1"
			each_inventory.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_inventory.session_id = request.json["session_id"]

		get_gatepass = db.session.query(Gatepass)\
		 .filter(Gatepass.deletion_marker == None)\
		 .filter(Gatepass.status == get_booking_status_id("Cancelled"))\
		 .filter(Gatepass.booking_id ==  return_booking.booking_public_id)\
		 .first()

		get_gatepass.status = "1"
		get_gatepass.updated_at = datetime.now()

		## Commented out in order to stop updating the user.
		# get_gatepass.session_id = request.json["session_id"]

		get_gatepass_guests = db.session.query(GatepassGuest)\
		  .filter(GatepassGuest.deletion_marker == None)\
		  .filter(GatepassGuest.status == get_booking_status_id("Cancelled"))\
		  .filter(GatepassGuest.gatepass_id == get_gatepass.gatepass_public_id)\
		  .all()

		for each_gatepass_guest in get_gatepass_guests:
			each_gatepass_guest.status = "1"
			each_gatepass_guest.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_gatepass_guest.session_id = request.json["session_id"]

		get_gatepass_details = db.session.query(GatepassDetail)\
		   .filter(GatepassDetail.deletion_marker == None)\
		   .filter(GatepassDetail.status == get_booking_status_id("Cancelled"))\
		   .filter(GatepassDetail.gatepass_id == get_gatepass.gatepass_public_id)\
		   .first()

		get_gatepass_details.status = "1"
		get_gatepass_details.updated_at = datetime.now()

		## Commented out in order to stop updating the user.
		# get_gatepass_details.session_id = request.json["session_id"]

		get_gatepass_vehicles = db.session.query(GatepassVehicle)\
		 .filter(GatepassVehicle.deletion_marker == None)\
		 .filter(GatepassVehicle.status == get_booking_status_id("Cancelled"))\
		 .filter(GatepassVehicle.gatepass_id == get_gatepass.gatepass_public_id)\
		 .all()

		for each_gatepass_vehicle in get_gatepass_vehicles:
			each_gatepass_vehicle.status = "1"
			each_gatepass_vehicle.updated_at = datetime.now()

			## Commented out in order to stop updating the user.
			# each_gatepass_vehicle.session_id = request.json["session_id"]

		try:
			db.session.commit()
			close(db)

			message = []
			# message.append("The details of the booking have been deleted successfully.")
			message.append("The booking has been reinstated.")
			return jsonify({"message": message}), 200
		except Exception as e:
			print(e)
			db.session.rollback()
			close(db)

			message = []
			# message.append("There was a slight issue deleting the details of the booking. :-( Please try again later.")
			message.append(
				"There was a slight issue reinstating the booking. Please try again later."
			)
			return jsonify({"message": message}), 422


@app.route("/test", methods=["POST"])
def test_route():
	one_array = []
	two_array = []
	three_array = []
	four_array = []
	five_array = []
	six_array = []

	try:
		for gatepass_guest in request.json["guests"]:
			get_guest_type = db.session.query(Mandatory)\
			   .filter(Mandatory.deletion_marker == None)\
			   .filter(Mandatory.payment_public_id == gatepass_guest["payment_public_id"])\
			   .first()

			get_gatepass_fee = db.session.query(Mandatory)\
			  .filter(Mandatory.deletion_marker == None)\
			  .filter(Mandatory.payment_public_id == gatepass_guest["payment_public_id"])\
			  .first()

			try:
				gatepass = get_gatepass_fee.payment_person_amount
				# six_array.append(float(get_gatepass_fee.payment_person_amount))
			except (ValueError, TypeError) as no_value:
				gatepass = 0
				# six_array.append(no_value)

			gatepass_amount = currencyHandler(
				request.json["currency"],
				get_gatepass_fee.payment_person_currency, gatepass)

			one_array.append(gatepass_guest["payment_public_id"])
			two_array.append(
				get_booking_guest_type_id(
					get_guest_type.payment_person.lower()))
			three_array.append(get_guest_type.payment_person.lower())

			if type(gatepass_amount) == str:
				five_array.append(gatepass_amount)
			else:
				five_array.append(float(gatepass_amount))

		type_id = db.session.query(GuestType)\
		 .filter(GuestType.deletion_marker == None)\
		 .all()

		for each_type in type_id:
			four_array.append(each_type.booking_guest_type_name.lower())

		return jsonify({
			"one": one_array,
			"two": two_array,
			"three": three_array,
			"four": four_array,
			"five": five_array,
			"six": six_array
		}), 200

	except KeyError as guest_error:
		print("There was an error getting: " + str(guest_error))
		return "Pass"


@app.route("/test2")
@sessionTracking
def test_route2():
	output = []

	# output.append(str(request.data))
	# output.append(request.status_code)

	print(request.data)
	print(request.path)
	print(request.full_path)
	print(request.url)
	print(request.headers)
	print(request.method)

	headers = request.headers

	print(dict(headers))

	headers2 = dict(headers)

	print(headers2["User-Agent"])

	return jsonify({"data": "output"})


@app.route("/bookings/stream")
# @bookings_logger.logWrapper()
def stream_all_bookings():
	try:
		page = int(request.args["page"])
	except Exception:
		page = 1

	try:
		items = int(request.args["items"])
	except Exception:
		items = 50

	if page == 0:
		return_bookings = db.session.query(Booking)\
		 .order_by(Booking.booking_id.desc())\
		 .options(FromCache(db_cache))\
		 .all()

	else:
		return_bookings = db.session.query(Booking)\
		 .order_by(Booking.booking_id.desc())\
		 .options(FromCache(db_cache))\
		 .paginate(page, items, False)\
		 .items

	if not return_bookings:
		output = []
		output.append("There are currently no bookings in the system.")
		return jsonify({"message": output}), 200

	id_array = []

	for each_id in return_bookings:
		id_array.append(each_id.session_id)

	request_session = requests.Session()
	# adapter = requests.adapters.HTTPAdapter(pool_connections = 12)
	# request_session.mount("https://", adapter)

	try:
		return_user = request_session.post(get_user_from_aumra,\
		  json = {"users_ids": id_array})
	except (requests.exceptions.ConnectionError, requests.exceptions.Timeout,
			requests.exceptions.ConnectTimeout) as connection_error:
		pass

	data = []
	for single in return_bookings:
		return_data = {}
		return_data["booking_public_id"] = single.booking_public_id
		return_data["booking_type"] = single.b_type.booking_type_name
		return_data["booking_type_id"] = single.booking_type
		return_data["booking_check_in_date"] = single.booking_check_in_date
		return_data["booking_check_out_date"] = single.booking_check_out_date
		return_data["booking_done_by"] = single.booking_done_by
		return_data["booking_ref_code"] = single.booking_ref_code

		return_data["facility_bookings"] = single.return_facilities(
			request_session)
		return_data["inventory_bookings"] = single.return_inventory(
			request_session)

		guest_array = []
		guest_sum = []

		get_all_guests = db.session.query(GatepassGuest)\
		   .join(Mandatory, GatepassGuest.gatepass_guest_type == Mandatory.payment_public_id)\
		   .join(Gatepass, GatepassGuest.gatepass_id == Gatepass.gatepass_public_id)\
		   .add_columns(Mandatory.payment_person, Mandatory.payment_public_id,\
		 GatepassGuest.gatepass_guest_count, GatepassGuest.gatepass_discount_rate, GatepassGuest.gatepass_cost_per_pp,\
		 GatepassGuest.gatepass_no_of_nights)\
		   .filter(GatepassGuest.deletion_marker == None)\
		   .filter(GatepassGuest.status != get_booking_status_id("Updated"))\
		   .filter(Gatepass.booking_id == single.booking_public_id)\
		   .options(FromCache(db_cache))\
		   .all()

		for each_guest in get_all_guests:
			guest_data = {}
			guest_data["guest_type"] = each_guest.payment_person
			guest_data["no_of_guests"] = each_guest.gatepass_guest_count

			guest_array.append(guest_data)
			guest_sum.append(int(each_guest.gatepass_guest_count))

		return_data["guests"] = guest_array
		return_data["guest_total"] = sum(guest_sum)

		check_to_invoice = db.session.query(Invoice)\
		 .filter(Invoice.deletion_marker == None)\
		 .filter(Invoice.booking_id == single.booking_public_id)\
		 .first()

		if check_to_invoice:
			if single.deletion_marker == 1:
				return_data["booking_status"] = "Cancelled"
				return_data[
					"booking_color"] = "background-color: #e53935; color: #fff"
			else:
				return_data["booking_status"] = "To Invoice"

		else:
			if single.checked_out == 1:
				return_data["booking_status"] = "Checked Out"
				return_data[
					"booking_color"] = "background-color: #73a533; color: #fff"
			elif single.checked_in == 1:
				return_data["booking_status"] = "Checked In"
				return_data[
					"booking_color"] = "background-color: #2196f3; color: #fff"
			elif single.deletion_marker == 1:
				return_data["booking_status"] = "Cancelled"
				return_data[
					"booking_color"] = "background-color: #e53935; color: #fff"
			else:
				if single.b_status.booking_status_name == "Unconfirmed":
					return_data[
						"booking_color"] = "background-color: #e67e22; color: #fff"
				elif single.b_status.booking_status_name == "No-Show":
					return_data[
						"booking_color"] = "background-color: #9b59b6; color: #fff"
				else:
					return_data[
						"booking_color"] = "background-color: #fff; color: #000000"
				return_data[
					"booking_status"] = single.b_status.booking_status_name
		return_data["booking_status_id"] = single.status

		if single.session_id:
			try:
				for user in return_user.json()["data"]:
					if user["public_id"] == single.session_id:
						return_data["session_user"] = user["full_name"]
						return_data["session_id"] = single.session_id

			except (IndexError, KeyError) as user_error:
				return_data["session_user"] = "N/A"
				return_data["session_id"] = single.session_id

			except (AttributeError,
					UnboundLocalError) as network_related_errors:
				return_data["session_user"] = "Network Error"
				return_data["session_id"] = single.session_id
		else:
			return_data["session_user"] = "N/A"
			return_data["session_id"] = single.session_id

		return_data["created_at"] = single.created_at
		return_data["updated_at"] = single.updated_at

		get_partner_booking = db.session.query(Partner)\
		  .filter(Partner.deletion_marker == None)\
		  .filter(Partner.booking_id == single.booking_public_id)\
		  .options(FromCache(db_cache))\
		  .first()

		if get_partner_booking:
			return_data[
				"partner_booking_ref"] = get_partner_booking.partner_booking_ref
		else:
			return_data["partner_booking_ref"] = None

		data.append(return_data)

	return jsonify({"data": data}), 200


@app.route("/bookings/finally-delete", methods=["POST"])
def delete_bookings():
	""" With great power comes great responsibility.
		This function is used to delete bookings from the database and should, therefore, be used responsibly.
	"""

	if not request.json["bookings"]:
		return jsonify({"message": "Bookings is empty."})

	messages = []

	for single_booking in request.json["bookings"]:
		get_booking = db.session.query(Booking)\
		   .filter(Booking.booking_public_id == single_booking)\
		   .all()

		get_gatepass = db.session.query(Gatepass)\
		 .filter(Gatepass.booking_id == single_booking)\
		 .all()

		for single_gatepass in get_gatepass:
			get_gatepass_guests = db.session.query(GatepassGuest)\
			  .filter(GatepassGuest.gatepass_id == single_gatepass.gatepass_public_id)\
			  .all()

			if get_gatepass_guests:
				for _get_gatepass_guests in get_gatepass_guests:
					db.session.delete(_get_gatepass_guests)

			get_gatepass_vehicles = db.session.query(GatepassVehicle)\
			 .filter(GatepassVehicle.gatepass_id == single_gatepass.gatepass_public_id)\
			 .all()

			if get_gatepass_vehicles:
				for _get_gatepass_vehicles in get_gatepass_vehicles:
					db.session.delete(_get_gatepass_vehicles)

			get_gatepass_details = db.session.query(GatepassDetail)\
			   .filter(GatepassDetail.gatepass_id == single_gatepass.gatepass_public_id)\
			   .all()

			if get_gatepass_details:
				for _get_gatepass_details in get_gatepass_details:
					db.session.delete(_get_gatepass_details)

			db.session.delete(single_gatepass)

		for each_booking in get_booking:
			get_booking_details = db.session.query(Detail)\
			  .filter(Detail.booking_id == each_booking.booking_public_id)\
			  .all()

			if get_booking_details:
				for _get_booking_details in get_booking_details:
					db.session.delete(_get_booking_details)

			get_booking_inventory = db.session.query(Inventory)\
			 .filter(Inventory.booking_id == each_booking.booking_public_id)\
			 .all()

			if get_booking_inventory:
				for _get_booking_inventory in get_booking_inventory:
					db.session.delete(_get_booking_inventory)

			get_booking_facility = db.session.query(Facility)\
			   .filter(Facility.booking_id == each_booking.booking_public_id)\
			   .all()

			if get_booking_facility:
				for _get_booking_facility in get_booking_facility:
					db.session.delete(_get_booking_facility)

			get_booking_guests = db.session.query(BookingGuest)\
			 .filter(BookingGuest.booking_id == each_booking.booking_public_id)\
			 .all()

			if get_booking_guests:
				for _get_booking_guests in get_booking_guests:
					db.session.delete(_get_booking_guests)

			get_booking_to_invoice = db.session.query(Invoice)\
			  .filter(Invoice.booking_id == each_booking.booking_public_id)\
			  .all()

			if get_booking_to_invoice:
				for _get_booking_to_invoice in get_booking_to_invoice:
					db.session.delete(_get_booking_to_invoice)

			get_booking_activities = db.session.query(BookingActivity)\
			  .filter(BookingActivity.booking_id == each_booking.booking_public_id)\
			  .all()

			if get_booking_activities:
				for _get_booking_activities in get_booking_activities:
					db.session.delete(_get_booking_activities)

			get_booking_notes = db.session.query(Note)\
			   .filter(Note.booking_id == each_booking.booking_public_id)\
			   .all()

			if get_booking_notes:
				for _get_booking_notes in get_booking_notes:
					db.session.delete(_get_booking_notes)

			get_booking_payments = db.session.query(BookingPayment)\
			   .filter(BookingPayment.booking_id == each_booking.booking_public_id)\
			   .all()

			if get_booking_payments:
				for _get_booking_payments in get_booking_payments:
					db.session.delete(_get_booking_payments)

			get_check_in_vehicles = db.session.query(CheckInVehicle)\
			 .filter(CheckInVehicle.booking_id == each_booking.booking_public_id)\
			 .all()

			if get_check_in_vehicles:
				for _get_check_in_vehicles in get_check_in_vehicles:
					db.session.delete(_get_check_in_vehicles)

			get_group_bookings = db.session.query(Group)\
			 .filter(Group.booking_id == each_booking.booking_public_id)\
			 .all()

			if get_group_bookings:
				for _get_group_bookings in get_group_bookings:
					db.session.delete(_get_group_bookings)

			get_member_bookings = db.session.query(Member)\
			  .filter(Member.booking_id == each_booking.booking_public_id)\
			  .all()

			if get_member_bookings:
				for _get_member_bookings in get_member_bookings:
					db.session.delete(_get_member_bookings)

			get_partner_bookings = db.session.query(Partner)\
			   .filter(Partner.booking_id == each_booking.booking_public_id)\
			   .all()

			if get_partner_bookings:
				for _get_partner_bookings in get_partner_bookings:
					db.session.delete(_get_partner_bookings)

			get_salesforce_details = db.session.query(SalesforceData)\
			  .filter(SalesforceData.booking_id == each_booking.booking_public_id)\
			  .all()

			if get_salesforce_details:
				for _get_salesforce_details in get_salesforce_details:
					db.session.delete(_get_salesforce_details)

			get_school_bookings = db.session.query(SchoolBooking)\
			  .filter(SchoolBooking.booking_id == each_booking.booking_public_id)\
			  .all()

			if get_school_bookings:
				for _get_school_bookings in get_school_bookings:
					db.session.delete(_get_school_bookings)

			get_booking_transactions = db.session.query(Transaction)\
			 .filter(Transaction.booking_id == each_booking.booking_public_id)\
			 .all()

			if get_booking_transactions:
				for _get_booking_transactions in get_booking_transactions:
					db.session.delete(_get_booking_transactions)

			db.session.delete(each_booking)

		try:
			db.session.commit()
			messages.append(single_booking + ": Ok")

		except Exception as e:
			db.session.rollback()
			messages.append(single_booking + ": " + str(e))

	return jsonify({"messages": messages})


#############
#### Ref ####
#############
def get_booking_status_id(status_name):
	status_id = db.session.query(BookingStatus)\
	 .filter(BookingStatus.deletion_marker == None)\
	 .filter(BookingStatus.booking_status_name == status_name)\
	 .all()

	for single in status_id:
		booking_status_id = single.booking_status_public_id

		return booking_status_id


def get_booking_guest_type_id(guest_type_name):
	type_id = db.session.query(GuestType)\
	  .filter(GuestType.deletion_marker == None)\
	  .all()

	for single in type_id:
		if single.booking_guest_type_name.lower() == guest_type_name:
			booking_guest_type_id = single.booking_guest_type_public_id

			return booking_guest_type_id


@app.route('/user-details/<email>')
def getUserDetails(email):
	user = db.session.query(Detail).filter_by(email_address=email).first()

	if not user:
		responseObject = {'message': 'No such User Found'}
		return make_response(jsonify(responseObject)), 412
	else:

		responseObject = {
			'first_name': user.first_name,
			'last_name': user.last_name,
			'email': user.email_address,
		}
		return make_response(jsonify(responseObject)), 200


@app.route("/bookings/residency-proofs")
# @bookings_logger.logWrapper()
def view_all_bookings_residency_proofs():
	try:
		page = int(request.args["page"])
	except Exception:
		page = 1

	try:
		items = int(request.args["items"])
	except Exception:
		items = 50

	if page == 0:
		residency_db= db.session.query(ResidencyProof)\
		  .filter(ResidencyProof.deletion_marker == None)\
		  .order_by(ResidencyProof.created_at.desc())\
		  .options(FromCache(db_cache))\
		  .all()

	else:
		residency_db= db.session.query(ResidencyProof)\
		  .filter(ResidencyProof.deletion_marker == None)\
		  .order_by(ResidencyProof.created_at.desc())\
		  .options(FromCache(db_cache))\
		  .paginate(page, items, False)\
		  .items
	output = []

	if not set(residency_db):
		message = []
		message.append("No residency proofs found.")
		return jsonify({"message": message}), 412
	else:
		for residency in residency_db:

			return_booking = db.session.query(Booking)\
			.add_columns(Booking.booking_public_id, Booking.booking_ref_code, )\
			.filter(Booking.booking_public_id == residency.booking_id)\
			.first()

			residency_obj = {}
			residency_obj["first_name"] = residency.first_name
			residency_obj["last_name"] = residency.last_name
			residency_obj["document_id"] = residency.document_id
			residency_obj["created_at"] = residency.created_at
			residency_obj["proof_point"] = residency.proof_point
			residency_obj["booking_ref_code"] = return_booking.booking_ref_code
			residency_obj[
				"booking_public_id"] = return_booking.booking_public_id
			residency_proof_id_arr = []
			for residency_session in residency_db:
				residency_proof_id_arr.append(residency_session.session_id)
			post_data = {"users_ids": residency_proof_id_arr}
			return_user_proofs = requests.post(get_user_from_aumra,
											   json=post_data)
			try:
				for user in return_user_proofs.json()["data"]:
					if user["public_id"] == residency.session_id:
						name = user["full_name"]

			except (IndexError, KeyError):
				name = "N/A"

			verify = residency.verified
			if verify == 1:
				residency_obj["user"] = name
				residency_obj["verified"] = 'Yes'
				residency_obj[
					"booking_color"] = "background-color: #73a533; color: #fff"
			else:
				residency_obj["verified"] = "No"
				residency_obj["user"] = ''
				residency_obj[
					"booking_color"] = "background-color: #e74c3c; color: #fff"

			residency_id = residency.residency_id

			get_residence_name = db.session.query(Mandatory)\
			 .add_columns(Mandatory.payment_person,Mandatory.payment_public_id )\
			 .filter(Mandatory.payment_public_id == residency_id)\
			 .options(FromCache(db_cache))\
			 .first()
			residency_obj["residency"] = {
				"payment_person": get_residence_name.payment_person,
				"payment_public_id": get_residence_name.payment_public_id
			}

			output.append(residency_obj)

		return jsonify({"data": output}), 200