import math
import os
import uuid
from collections import OrderedDict
from datetime import date, datetime, timedelta, date
from ftplib import FTP
from json_simple_validator import field_validation

# import pandas as pd
import paramiko
import requests
import xlrd
from dateutil.relativedelta import *
from flask import (Flask, json, jsonify, make_response, redirect,
				   render_template, request, send_from_directory, url_for)
from werkzeug.utils import secure_filename

import boto
import boto3
import botocore
import pymysql
import sendgrid
import tinys3
from boto.s3.key import Key
from botocore.client import Config
from database.members import (Corporate, FamilyMember, FamilyType, Member,
							  MembershipLevel, Transaction)
from database.types import (Gender, Households, MemberSetting, MemberType,
							Registrationtype, Residence)
from flask_cache import Cache
from flask_sqlalchemy_cache import CachingQuery, FromCache
# File imports
from routes.v1 import app, cache, cache_db, clearCache, close, db
from routes.v1.salesforce import *

from sendgrid.helpers.mail import *

from .validation import Validation


def upload_file_to_s3(file, bucket_name, acl="public-read"):
	try:
		s3 = boto3.client(
			"s3",
			aws_access_key_id=app.config['S3_ACCESS_KEY'],
			aws_secret_access_key=app.config['S3_SECRET_KEY']
		)

		s3.upload_fileobj(
			file,
			bucket_name,
			file.filename,
			ExtraArgs={
				"ACL": acl,
				"ContentType": file.content_type
			}
		)
		return "{0}{1}".format(app.config["S3_LOCATION"], file.filename)
	except Exception as e:
		# This is a catch all exception, edit this part to fit your needs.
		print("Something Happened: ", e)
		return e


def uploadToFTPServer(filename):
	# domain name or server ip:
	ftp = FTP('zing-it.co.ke')
	ftp.login(user='zingitc1', passwd='254733560718')
	ftp.cwd('/public_html/public_opc/static/images')
	ftp.storbinary('STOR '+filename, open(filename, 'rb'))
	ftp.quit()


def allowed_file(filename):
	return '.' in filename and \
		filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']


def generateDate(stringDate):
	formatted_date = stringDate.replace("-", ",")

	year, month, day = formatted_date.split(",")

	new_date = date(int(year), int(month), int(day))

	return new_date


@app.route('/members')
@cache.cached(timeout=86400)
def getAllMembers():
	members = db.session.query(Member).filter_by(status=5).filter(Member.deletion_marker == None).order_by(
		Member.membershipid.asc()).options(FromCache(cache_db)).all()
	if members:
		output = []
		for member in members:
			response = {}
			family_output = []
			membership_fee, = db.session.query(MemberSetting.price).filter_by(
				public_id=member.member_setting).first()
			residence, = db.session.query(Residence.name).filter_by(
				public_id=member.residence).first()

			family_members = db.session.query(FamilyMember).filter_by(
				membership_id=member.public_id, status=5).all()
			if family_members:
				for family in family_members:
					response_message = {}
					# gender, = db.session.query(Gender.name).filter_by(public_id=member.gender).first()
					gender = requests.get(
						'https://{0}:9000/v1/gender/{1}'.format(app.config['SERVER'], family.gender))

					if family.gender == "bj45454343":
						gender_name = "Female"
					elif family.gender == "erenker":
						gender_name = "Male"
					else:
						gender_name = "Other"

					household_type, = db.session.query(Households.name).filter_by(
						public_id=member.household_type).first()
					# family_type, = db.session.query(FamilyType.name).filter_by(public_id=family.family_type).first()

					response_message['first_name'] = family.first_name
					response_message['sur_name'] = family.sur_name
					response_message['phone_number'] = family.tel_number
					response_message['email'] = family.email
					response_message['gender'] = gender_name
					# response_message['gender'] = gender.json(
					# )['name'] if gender.status_code == 200 else "N/A"
					response_message['type'] = household_type
					response_message['dob'] = family.dob
					response_message['public_id'] = family.public_id
					family_output.append(response_message)

			# check if there are extra family members under Family
			if len(family_output) > 3:
				# Check its family
				resident_fee = 4800
				citizen_fee = 2400
				if member.residence == 'berbere':
					membership_fee = membership_fee + \
						(resident_fee * (len(family_output)-3))
				else:
					membership_fee = membership_fee + \
						(citizen_fee * (len(family_output)-3))

			response['full_name'] = member.title.strip().title(
			) + " " + member.first_name.strip().title() + " " + member.sur_name.strip().title()
			response['first_name'], = member.first_name,
			response['surname'], = member.sur_name,
			gender = requests.get(
				'https://{0}:9000/v1/gender/{1}'.format(app.config['SERVER'], member.gender))
			if member.gender == "bj45454343":
				gender_name = "Female"
			elif member.gender == "erenker":
				gender_name = "Male"
			else:
				gender_name = "Other"
			response['gender'] = gender_name
			# response['gender'] = gender.json(
			# )['name'] if gender.status_code == 200 else "N/A"
			response['gender_public_id'] = member.gender
			response['public_id'] = member.public_id
			response['expiry_date'] = member.expiry_date if member.expiry_date else ""
			registration_type, = db.session.query(Registrationtype.name).filter_by(
				public_id=member.registration_type).first()
			response['registration_type'] = registration_type
			response['registration_type_public_id'] = member.registration_type
			response['dob'] = member.dob
			response['id_alien_number'] = member.id_alien_number
			response['postal_address'] = member.postal_address
			response['postal_code'] = member.postal_code
			response['title'] = member.title
			response['email'] = member.email
			response['tel_number'] = member.tel_number
			household_type, = db.session.query(Households.name).filter_by(
				public_id=member.household_type).first()
			response['household_type'] = household_type
			response['household_type_public_id'] = member.household_type
			response['status'] = member.status
			setting, = db.session.query(MemberSetting.name).filter_by(
				public_id=member.member_setting).first()
			response['setting'] = setting.lower()
			response['setting_public_id'] = member.member_setting
			response['residence'] = residence
			response['residence_public_id'] = member.residence
			response['memberID'] = member.membershipid
			response['level_public_id'] = member.member_level
			level_one, = db.session.query(MemberSetting.membertype_public_id).filter_by(
				public_id=member.member_setting).first()
			level, = db.session.query(MemberType.name).filter_by(
				public_id=level_one).first()
			response['level'] = level
			response['profile_image'] = member.profile_image
			response['payment_method'] = member.payment_method
			response['payment_status'] = False if member.payment_status == 0 else True
			response['p_status'] = member.payment_status
			response['payment_date'] = member.payment_date
			response['membership_fee'] = membership_fee
			response['family_count'] = len(
				family_output) if len(family_output) > 0 else 0
			response['family'] = family_output if family_output else ''
			num_of_persons, = db.session.query(MemberSetting.number_of_persons).filter_by(
				public_id=member.member_setting).first()
			num_of_vehicles, = db.session.query(MemberSetting.number_of_vehicles).filter_by(
				public_id=member.member_setting).first()
			num_of_children, =  db.session.query(MemberSetting.number_of_children).filter_by(
				public_id=member.member_setting).first()
			response['num_of_persons'] = num_of_persons
			response['num_of_vehicles'] = num_of_vehicles
			response['num_of_children'] = num_of_children
			response['salesforce_uuid'] = member.salesforce_uuid
			response['salesforce_account_id'] = member.salesforce_account_id
			response['salesforce_contact_id'] = member.contact_uuid
			output.append(response)

		return make_response(jsonify(output)), 200
	else:
		responseObject = {
			'message': 'No members curretly available'
		}
		return make_response(jsonify(responseObject)), 412


@app.route('/members/booking')
@cache.cached(timeout=86400)
def getAllBookingMembers():
	_now = datetime.now().strftime("%Y-%m-%d")
	members = db.session.query(Member).filter_by(status=5)\
		.filter(Member.deletion_marker == None)\
		.filter(Member.expiry_date != None)\
		.order_by(Member.membershipid.asc())\
		.options(FromCache(cache_db)).all()
	if members:
		output = []
		for member in members:
			response = {}
			membership_fee, = db.session.query(MemberSetting.price).filter_by(
				public_id=member.member_setting).first()
			entry_discount, = db.session.query(MemberSetting.entry_discount).filter_by(
				public_id=member.member_setting).first()
			activity_discount, = db.session.query(MemberSetting.activity_discount).filter_by(
				public_id=member.member_setting).first()
			accommodation_discount, = db.session.query(
				MemberSetting.accommodation_discount).filter_by(public_id=member.member_setting).first()
			residence, = db.session.query(Residence.name).filter_by(
				public_id=member.residence).first()

			response['corporate'] = False
			response['full_name'] = member.title.strip().title(
			) + " " + member.first_name.strip().title() + " " + member.sur_name.strip().title()
			response['first_name'], = member.first_name,
			response['surname'], = member.sur_name,
			gender = requests.get(
				'https://{0}:9000/v1/gender/{1}'.format(app.config['SERVER'], member.gender))
			response['gender'] = gender.json(
			)['name'] if gender.status_code == 200 else "N/A"
			response['gender_public_id'] = member.gender
			response['public_id'] = member.public_id
			response['expiry_date'] = member.expiry_date if member.expiry_date else ""
			response['entry_discount'] = int(entry_discount)
			response['activity_discount'] = int(activity_discount)
			response['accommodation_discount'] = int(accommodation_discount)
			registration_type, = db.session.query(Registrationtype.name).filter_by(
				public_id=member.registration_type).first()
			response['registration_type'] = registration_type
			response['registration_type_public_id'] = member.registration_type
			response['dob'] = member.dob
			response['id_alien_number'] = member.id_alien_number
			response['postal_address'] = member.postal_address
			response['postal_code'] = member.postal_code
			response['title'] = member.title
			response['email'] = member.email
			response['tel_number'] = member.tel_number
			household_type, = db.session.query(Households.name).filter_by(
				public_id=member.household_type).first()
			response['household_type'] = household_type
			response['household_type_public_id'] = member.household_type
			response['status'] = member.status
			setting, = db.session.query(MemberSetting.name).filter_by(
				public_id=member.member_setting).first()
			response['setting'] = setting.lower()
			response['setting_public_id'] = member.member_setting
			response['residence'] = residence
			response['residence_public_id'] = member.residence
			response['memberID'] = member.membershipid
			response['level_public_id'] = member.member_level
			level_one, = db.session.query(MemberSetting.membertype_public_id).filter_by(
				public_id=member.member_setting).first()
			level, = db.session.query(MemberType.name).filter_by(
				public_id=level_one).first()
			response['level'] = level
			response['profile_image'] = member.profile_image
			response['payment_method'] = member.payment_method
			response['payment_status'] = False if member.payment_status == 0 else True
			response['membership_fee'] = membership_fee
			num_of_persons, = db.session.query(MemberSetting.number_of_persons).filter_by(
				public_id=member.member_setting).first()
			num_of_vehicles, = db.session.query(MemberSetting.number_of_vehicles).filter_by(
				public_id=member.member_setting).first()
			num_of_children, =  db.session.query(MemberSetting.number_of_children).filter_by(
				public_id=member.member_setting).first()
			response['num_of_persons'] = num_of_persons
			response['num_of_vehicles'] = num_of_vehicles
			response['num_of_children'] = num_of_children

			# Only retutn booking that have not expired
			expiry_date = (member.expiry_date).strftime("%Y-%m-%d")
			if (str(expiry_date) > _now):
				output.append(response)

		return make_response(jsonify(output)), 200
	else:
		responseObject = {
			'message': 'No Green Members currently available'
		}
		return make_response(jsonify(responseObject)), 412


@app.route('/members/reports')
def getAllMembersReport():
	members = db.session.query(Member).filter_by(
		payment_status=1).filter(Member.deletion_marker == None).all()
	if members:
		output = []
		for member in members:
			response = OrderedDict()
			gender = requests.get(
				'https://{0}:9000/v1/gender/{1}'.format(app.config['SERVER'], member.gender))
			price, = db.session.query(MemberSetting.price).filter_by(
				public_id=member.member_setting).first()
			response["Date"] = (member.created_at).strftime("%Y-%m-%d")
			response['MemberID'] = member.membershipid
			response['FullName'] = member.title.strip().title(
			) + " " + member.first_name.strip().title() + " " + member.sur_name.strip().title()
			response['Gender'] = gender.json(
			)['name'] if gender.status_code == 200 else "N/A"
			response['dob'] = (member.dob).strftime("%Y-%m-%d")
			response['IDNumber'] = member.id_alien_number
			response['Email'] = member.email
			response['PhoneNumber'] = member.tel_number
			response['PaymentMethod'] = member.payment_method
			response['Price'] = price
			output.append(response)

		return jsonify(output), 200
	else:
		pass


@app.route('/members/reports/dates/<start_date>/<end_date>', methods=['GET'])
def getAllMembersReportWithDates(start_date, end_date):
	members = db.session.query(Member).filter(
		Member.created_at >= start_date, Member.created_at <= end_date).all()

	if members:
		output = []
		for member in members:
			response = {}

			response['full_name'] = member.title.strip().title(
			) + " " + member.first_name.strip().title() + " " + member.sur_name.strip().title()
			gender, = db.session.query(Gender.name).filter_by(
				public_id=member.gender).first()
			response['gender'] = gender
			response['public_id'] = member.public_id
			reg_type, = db.session.query(Registrationtype.name).filter_by(
				public_id=member.registration_type).first()
			response['registration_type'] = reg_type
			response['dob'] = member.dob
			response['id_alien_number'] = member.id_alien_number
			response['postal_address'] = member.postal_address
			response['postal_code'] = member.postal_code
			response['title'] = member.title
			response['email'] = member.email
			response['tel_number'] = member.tel_number
			household_type, = db.session.query(Households.name).filter_by(
				public_id=member.household_type).first()
			response['household_type'] = household_type
			setting, = db.session.query(MemberSetting.name).filter_by(
				public_id=member.member_setting).first()
			response['setting'] = setting
			residence, = db.session.query(Residence.name).filter_by(
				public_id=member.residence).first()
			response['residence'] = residence
			response['memberID'] = member.membershipid
			level, = db.session.query(MemberType.name).filter_by(
				ml_public_id=member.member_level).first()
			response['level'] = level

			output.append(response)

		if not output:
			responseObject = {
				'message': 'No data currently available'
			}
			return make_response(jsonify(responseObject)), 200
		else:
			df = pd.DataFrame(output)
			df.to_csv('date_based_members.csv', sep=',', encoding='utf-8')

			return send_from_directory(directory='/', filename='date_based_members.csv')
			# return ('<a href="https://167.99.85.35:8000/var/www/html/opc_services/date_based_members.csv"> Click Here to download</a>')
	else:
		responseObject = {
			'message': 'No members curretly available'
		}
		return make_response(jsonify(responseObject)), app.config['ERROR_CODE']


@app.route('/member/<public_id>')
@cache.cached(timeout=86400)
def searchMember(public_id):
	member = db.session.query(Member).filter_by(
		public_id=public_id).options(FromCache(cache_db)).first()
	if not member:
		response = {
			'message': 'Am afraid we can not locate that members information'
		}
		return make_response(jsonify(response)), app.config['ERROR_CODE']
	else:
		family_output = []

		family_members = db.session.query(FamilyMember).filter_by(
			membership_id=member.public_id, status=5).all()
		if family_members:
			for family in family_members:
				response_message = {}
				if family.gender:
					gender = requests.get(
						'https://{0}:9000/v1/gender/{1}'.format(app.config['SERVER'], family.gender))
					gender_name = gender.json(
					)['name'] if gender.status_code == 200 else "N/A"
				else:
					gender_name = "N/A"
				household_type, = db.session.query(Households.name).filter_by(
					public_id=member.household_type).first()
				# family_type, = db.session.query(FamilyType.name).filter_by(public_id=family.family_type).first()
				response_message['first_name'] = family.first_name
				response_message['sur_name'] = family.sur_name
				response_message['phone_number'] = family.tel_number
				response_message['id_alien_number'] = family.id_alien_number
				response_message['postal_address'] = family.postal_address
				response_message['postal_code'] = family.postal_code
				response_message['email'] = family.email
				response_message['gender_id'] = family.gender
				response_message['title'] = family.title
				response_message['gender'] = gender_name
				response_message['type'] = household_type
				response_message['dob'] = family.dob
				response_message['public_id'] = family.public_id
				family_output.append(response_message)

		m_gender = requests.get(
			'https://{0}:9000/v1/gender/{1}'.format(app.config['SERVER'], member.gender))

		registration_type, = db.session.query(Registrationtype.name).filter_by(
			public_id=member.registration_type).first()
		amount, = db.session.query(MemberSetting.price).filter_by(
			public_id=member.member_setting).first()
		household_type, = db.session.query(Households.name).filter_by(
			public_id=member.household_type).first()
		setting, = db.session.query(MemberSetting.name).filter_by(
			public_id=member.member_setting).first()
		level_one, = db.session.query(MemberSetting.membertype_public_id).filter_by(
			public_id=member.member_setting).first()
		level, = db.session.query(MemberType.name).filter_by(
			public_id=level_one).first()
		residence, = db.session.query(Residence.name).filter_by(
			public_id=member.residence).first()

		num_of_persons, = db.session.query(MemberSetting.number_of_persons).filter_by(
			public_id=member.member_setting).first()
		num_of_vehicles, = db.session.query(MemberSetting.number_of_vehicles).filter_by(
			public_id=member.member_setting).first()
		num_of_children, =  db.session.query(MemberSetting.number_of_children).filter_by(
			public_id=member.member_setting).first()

		# check if there are extra family members under Family
		if len(family_output) > 3:
			# Check its family
			resident_fee = 4800
			citizen_fee = 2400
			if member.residence == 'berbere':
				amount = amount + (resident_fee * (len(family_output)-3))
			else:
				amount = amount + (citizen_fee * (len(family_output)-3))

		response = {
			'member_id': member.membershipid,
			'public_id': member.public_id,
			'full_name': member.title.strip().title() + " " + member.first_name.strip().title() + " " + member.sur_name.strip().title(),
			'first_name': member.first_name.strip().title(),
			'surname': member.sur_name.strip().title(),
			'gender': m_gender.json()['name'] if m_gender.status_code == 200 else "N/A",
			'gender_public_id': member.gender,
			'dob': member.dob,
			'expiry_date': member.expiry_date if member.expiry_date else "",
			'registration_type': registration_type,
			'registration_type_public_id': member.registration_type,
			'id_alien_number': member.id_alien_number,
			'postal_address': member.postal_address,
			'postal_code': member.postal_code,
			'title': member.title,
			'email': member.email,
			'amount': amount,
			'tel_number': member.tel_number,
			'household_type': household_type,
			'household_type_public_id': member.household_type,
			'status': member.status,
			'setting': setting.lower(),
			'setting_public_id': member.member_setting,
			'level_public_id': member.member_level,
			'level': level,
			'residence': residence,
			'residence_public_id': member.residence,
			'profile_image': member.profile_image,
			'payment_method': member.payment_method,
			'p_status': member.payment_status,
			'payment_status': False if member.payment_status == 0 else True,
			'payment_date': member.payment_date,
			'family': family_output if family_output else '',
			'num_of_persons': num_of_persons,
			'num_of_vehicles': num_of_vehicles,
			'num_of_children': num_of_children,
			'salesforce_account_uuid': member.salesforce_account_id,
			'salesforce_contact_uuid': member.contact_uuid,
			'salesforce_membership_uuid': member.salesforce_uuid,
			'family_count': len(family_output) if len(family_output) > 0 else 0
		}
		return make_response(jsonify(response)), 200


@app.route('/member/id/<membership_id>')
@cache.cached(timeout=86400)
def searchMemberByMembershipID(membership_id):
	member = db.session.query(Member).filter_by(
		membershipid=membership_id).options(FromCache(cache_db)).first()
	if not member:
		response = {
			'message': 'Am afraid we can not locate that members information'
		}
		return make_response(jsonify(response)), app.config['ERROR_CODE']
	else:
		family_output = []

		family_members = db.session.query(FamilyMember).filter_by(
			membership_id=member.public_id, status=5).all()
		if family_members:
			for family in family_members:
				response_message = {}
				gender = requests.get(
					'https://{0}:9000/v1/gender/{1}'.format(app.config['SERVER'], family.gender))
				household_type, = db.session.query(Households.name).filter_by(
					public_id=member.household_type).first()
				# family_type, = db.session.query(FamilyType.name).filter_by(public_id=family.family_type).first()
				response_message['first_name'] = family.first_name
				response_message['sur_name'] = family.sur_name
				response_message['phone_number'] = family.tel_number
				response_message['id_alien_number'] = family.id_alien_number
				response_message['postal_address'] = family.postal_address
				response_message['postal_code'] = family.postal_code
				response_message['email'] = family.email
				response_message['gender_id'] = family.gender
				response_message['title'] = family.title
				response_message['gender'] = gender.json(
				)['name'] if gender.status_code == 200 else "N/A"
				response_message['type'] = household_type
				response_message['dob'] = family.dob
				response_message['public_id'] = family.public_id
				family_output.append(response_message)

		m_gender = requests.get(
			'https://{0}:9000/v1/gender/{1}'.format(app.config['SERVER'], member.gender))

		registration_type, = db.session.query(Registrationtype.name).filter_by(
			public_id=member.registration_type).first()
		amount, = db.session.query(MemberSetting.price).filter_by(
			public_id=member.member_setting).first()
		household_type, = db.session.query(Households.name).filter_by(
			public_id=member.household_type).first()
		setting, = db.session.query(MemberSetting.name).filter_by(
			public_id=member.member_setting).first()
		level_one, = db.session.query(MemberSetting.membertype_public_id).filter_by(
			public_id=member.member_setting).first()
		level, = db.session.query(MemberType.name).filter_by(
			public_id=level_one).first()
		residence, = db.session.query(Residence.name).filter_by(
			public_id=member.residence).first()

		num_of_persons, = db.session.query(MemberSetting.number_of_persons).filter_by(
			public_id=member.member_setting).first()
		num_of_vehicles, = db.session.query(MemberSetting.number_of_vehicles).filter_by(
			public_id=member.member_setting).first()
		num_of_children, =  db.session.query(MemberSetting.number_of_children).filter_by(
			public_id=member.member_setting).first()

		# check if there are extra family members under Family
		if len(family_output) > 3:
			# Check its family
			resident_fee = 4800
			citizen_fee = 2400
			if member.residence == 'berbere':
				amount = amount + (resident_fee * (len(family_output)-3))
			else:
				amount = amount + (citizen_fee * (len(family_output)-3))

		response = {
			'member_id': member.membershipid,
			'public_id': member.public_id,
			'full_name': member.title.strip().title() + " " + member.first_name.strip().title() + " " + member.sur_name.strip().title(),
			'first_name': member.first_name.strip().title(),
			'surname': member.sur_name.strip().title(),
			'gender': m_gender.json()['name'] if m_gender.status_code == 200 else "N/A",
			'gender_public_id': member.gender,
			'dob': member.dob,
			'expiry_date': member.expiry_date if member.expiry_date else "",
			'registration_type': registration_type,
			'registration_type_public_id': member.registration_type,
			'id_alien_number': member.id_alien_number,
			'postal_address': member.postal_address,
			'postal_code': member.postal_code,
			'title': member.title,
			'email': member.email,
			'amount': amount,
			'tel_number': member.tel_number,
			'household_type': household_type,
			'household_type_public_id': member.household_type,
			'status': member.status,
			'setting': setting.lower(),
			'setting_public_id': member.member_setting,
			'level_public_id': member.member_level,
			'level': level,
			'residence': residence,
			'residence_public_id': member.residence,
			'profile_image': member.profile_image,
			'payment_method': member.payment_method,
			'payment_status': False if member.payment_status == 0 else True,
			'family': family_output if family_output else '',
			'num_of_persons': num_of_persons,
			'num_of_vehicles': num_of_vehicles,
			'num_of_children': num_of_children,
			'salesforce_account_uuid': member.salesforce_account_id,
			'salesforce_contact_uuid': member.contact_uuid,
			'salesforce_membership_uuid': member.salesforce_uuid,
			'family_count': len(family_output) if len(family_output) > 0 else 0
		}
		return make_response(jsonify(response)), 200


@app.route('/profile/upload/<public_id>', methods=['POST'])
def upload_file(public_id):
	if request.method == 'POST':
		# check if the post request has the file part
		if 'file' not in request.files:
			responseObject = {'message': 'No file part'}
			return make_response(jsonify(responseObject)), 200
		file = request.files['file']
		# if user does not select file, browser also
		# submit a empty part without filename
		if file.filename == '':
			responseObject = {'message': 'No file Selected'}
			return make_response(jsonify(responseObject)), 200
		if file and allowed_file(file.filename):
			filename = secure_filename(file.filename)
			file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
			path = app.config['UPLOAD_FOLDER'] + filename
			try:
				ACCESS_KEY_ID = app.config['S3_ACCESS_KEY']
				ACCESS_SECRET_KEY = app.config['S3_SECRET_KEY']
				BUCKET_NAME = app.config['S3_BUCKET']
				FILE_NAME = path

				data = open(FILE_NAME, 'rb')

				# S3 Connect
				s3 = boto3.resource(
					's3',
					aws_access_key_id=ACCESS_KEY_ID,
					aws_secret_access_key=ACCESS_SECRET_KEY,
					config=Config(signature_version='s3v4')
				)

				# Image Uploaded
				s3.Bucket(BUCKET_NAME).put_object(
					Key=FILE_NAME, Body=data, ACL='public-read')

				user = db.session.query(Member).filter_by(
					public_id=public_id).first_or_404()

				if user is None:
					responseObject = {
						'message': 'Member does not exist'
					}
					return make_response(jsonify(responseObject)), app.config['ERROR_CODE']

				user.profile_image = 'https://bookings.olpejetaconservancy.org.s3.ca-central-1.amazonaws.com/images/profiles/{}'.format(
					filename)

				try:
					db.session.commit()
					close(db)
					clearCache()
					responseObject = {
						'message': 'Successfully uploaded'
					}
					return make_response(jsonify(responseObject)), 200
				except Exception as identifier:
					responseObject = {
						'message': str(identifier)
					}
					return make_response(jsonify(responseObject)), 401
			except Exception as identifier:
				responseObject = {
					'error': str(identifier),
					'message': 'Could not upload image to remote server'
				}
				return make_response(jsonify(responseObject)), 500


app.route('/update/member/<public_id>', methods=['POST'])


def updateMember(public_id):

	member = db.session.query(Member).filter_by(
		public_id=public_id).filter(Member.status == 5).first()
	empty_set = []
	if not member:
		response = {
			'message': 'Am afraid we can not locate that members information'
		}
		return make_response(jsonify(response)), app.config['ERROR_CODE']
	else:
		first_name = request.json['first_name']
		last_name = request.json['sur_name']
		gender = request.json['gender_id']
		dob = request.json['dob']
		registration_type = request.json['registration_type']
		member_setting = request.json['member_setting']
		id_alien_number = request.json['id_alien_number']
		postal_address = request.json['postal_address']
		postal_code = request.json['postal_code']
		title = request.json['title']
		email = request.json['email'] if Validation.validateEmail(
			request.json['email']) == True else empty_set.append('Email address is invalid')
		tel_number = request.json['tel_number'] if Validation.validatePhoneNumber(
			request.json['tel_number'])[0] == True else empty_set.append('The Phone Number is invalid')
		household_type = request.json['household_type']
		residence = request.json['residence']
		payment_method = request.json['payment_method']
		membershipid = request.json['member_id']
		salesforce_uuid = request.json['salesforce_uuid']
		salesforce_contact_uuid = request.json['salesforce_contact_uuid']
		salesforce_account_uuid = request.json['salesforce_account_uuid']
		payment_status = request.json['payment_status']
		expiry_date = member.expiry_date
		if 'expiry_date' in request.json:
			expiry_date = request.json['expiry_date']

		if empty_set:
			return jsonify({'messages': empty_set}), 412

		member.title = title
		member.payment_status = 1 if payment_status == True else 0,
		member.membershipid = membershipid
		member.first_name = first_name
		member.sur_name = last_name
		member.gender = gender
		member.dob = dob
		member.registration_type = registration_type
		member.member_setting = member_setting
		member.id_alien_number = id_alien_number
		member.postal_address = postal_address
		member.postal_code = postal_code
		member.email = email
		member.expiry_date = expiry_date
		member.tel_number = tel_number
		member.household_type = household_type
		member.residence = residence
		member.payment_method = payment_method
		member.updated_at = datetime.now()
		member.salesforce_uuid = salesforce_uuid if salesforce_uuid else None
		member.contact_uuid = salesforce_contact_uuid if salesforce_contact_uuid else None
		member.salesforce_account_id = salesforce_account_uuid if salesforce_account_uuid else None

		db.session.commit()
		try:
			db.session.commit()
			close(db)
			# clear the cache
			clearCache()
			responseObject = {
				'message': 'Successfully updated {0} information'.format(first_name + " " + last_name)
			}
			return make_response(jsonify(responseObject)), 200
		except Exception as identifier:
			responseObject = {
				'status': str(identifier),
				'message': 'Error encountered while trying to update the information'
			}
			return make_response(jsonify(responseObject)), 500


@app.route('/update/member-details', methods=['POST'])
def updateMemberV1():
	empty_set = []

	public_id = request.json['public_id']
	member = db.session.query(Member).filter_by(
		public_id=public_id).filter(Member.status == 5).first()
	empty_set = []
	if not member:
		response = {
			'message': 'Am afraid we can not locate that members information'
		}
		return make_response(jsonify(response)), app.config['ERROR_CODE']
	else:
		first_name = request.json['first_name']
		last_name = request.json['sur_name']
		gender = request.json['gender_id']
		dob = request.json['dob']
		registration_type = request.json['registration_type']
		member_setting = request.json['member_setting']
		id_alien_number = request.json['id_alien_number']
		postal_address = request.json['postal_address']
		postal_code = request.json['postal_code']
		title = request.json['title']
		email = request.json['email'] if Validation.validateEmail(
			request.json['email']) == True else empty_set.append('Email address is invalid')
		tel_number = request.json['tel_number'] if Validation.validatePhoneNumber(
			request.json['tel_number'])[0] == True else empty_set.append('The Phone Number is invalid')
		household_type = request.json['household_type']
		residence = request.json['residence']
		payment_method = request.json['payment_method']
		membershipid = request.json['member_id']
		salesforce_uuid = request.json['salesforce_uuid']
		salesforce_contact_uuid = request.json['salesforce_contact_uuid']
		salesforce_account_uuid = request.json['salesforce_account_uuid']
		payment_status = request.json['payment_status']
		expiry_date = member.expiry_date
		if 'expiry_date' in request.json:
			expiry_date = request.json['expiry_date']

		if empty_set:
			return jsonify({'messages': empty_set}), 412

		member.title = title
		member.payment_status = 1 if payment_status == True else 0,
		member.membershipid = membershipid
		member.first_name = first_name
		member.sur_name = last_name
		member.gender = gender
		member.dob = dob
		member.registration_type = registration_type
		member.member_setting = member_setting
		member.id_alien_number = id_alien_number
		member.postal_address = postal_address
		member.postal_code = postal_code
		member.email = email
		member.expiry_date = expiry_date
		member.tel_number = tel_number
		member.household_type = household_type
		member.residence = residence
		member.payment_method = payment_method
		member.updated_at = datetime.now()
		member.salesforce_uuid = salesforce_uuid if salesforce_uuid else None
		member.contact_uuid = salesforce_contact_uuid if salesforce_contact_uuid else None
		member.salesforce_account_id = salesforce_account_uuid if salesforce_account_uuid else None

		db.session.commit()
		try:
			db.session.commit()
			close(db)
			# clear the cache
			clearCache()
			responseObject = {
				'message': 'Successfully updated {0} information'.format(first_name + " " + last_name)
			}
			return make_response(jsonify(responseObject)), 200
		except Exception as identifier:
			responseObject = {
				'status': str(identifier),
				'message': 'Error encountered while trying to update the information'
			}
			return make_response(jsonify(responseObject)), 500


@app.route('/update/corporate-member/<member_id>', methods=['PATCH'])
def updateCorporateMember():
	memberId = request.json["member_id"]
	corporate_member = db.session.query(Corporate).filter_by(
		member_id=memberId).filter(Corporate.status == 5).first()
	empty_set = []
	if not corporate_member:
		response = {
			'message': 'Am afraid we can not locate that members information'
		}
		return make_response(jsonify(response)), app.config['ERROR_CODE']
	else:
		member_id = request.json['member_id']
		company_name = request.json['company_name']
		email = request.json['email'] if Validation.validateEmail(
			request.json['email']) == True else errors.append('Email address is invalid')
		phone_number = request.json['phone_number'] if Validation.validatePhoneNumber(
			request.json['phone_number'])[0] == True else errors.append('The Phone Number is invalid')
		contact_person_name = request.json['contact_person_name']
		contact_person_phone_number = request.json['contact_person_phone_number']
		salesforce_uuid = request.json['salesforce_uuid']
		postal_address = request.json['postal_address']
		postal_code = request.json['postal_code']
		salesforce_contact_uuid = request.json['salesforce_contact_uuid']
		salesforce_account_uuid = request.json['salesforce_account_uuid']
		expiry_date = request.json['expiry_date']
		amount = request.json['amount']
		# should be 1 for yes 0 for No
		payment_status = request.json['payment_status']
		payment_method = request.json['payment_method']
		town = request.json['town']
		code = request.json['code']
		country = request.json['country']
		visits = request.json['visits']
		vehicles = request.json['vehicles']
		passengers = request.json['passengers']
		email1 = request.json['email1']
		email2 = request.json['email2']
		if payment_status == True:
			payment_status = 1
		else:
			payment_status = 0

	corporate_member.member_id = member_id,
	corporate_member.company_name = company_name,
	corporate_member.email = email,
	corporate_member.email1 = email1,
	corporate_member.email2 = email2,
	corporate_member.phone_number = phone_number,
	corporate_member.contact_person_name = contact_person_name,
	corporate_member.contact_person_phone_number = contact_person_phone_number,
	corporate_member.salesforce_uuid = salesforce_uuid,
	corporate_member.salesforce_account_uuid = salesforce_account_uuid,
	corporate_member.salesforce_contact_uuid = salesforce_contact_uuid,
	corporate_member.postal_address = postal_address,
	corporate_member.postal_code = postal_code,
	corporate_member.expiry_date = expiry_date,
	corporate_member.amount = amount if amount else 0,
	corporate_member.payment_status = payment_status,
	corporate_member.payment_method = payment_method,
	corporate_member.created_at = datetime.now(),
	corporate_member.code = code,
	corporate_member.country = country,
	corporate_member.town = town,
	corporate_member.visits = visits,
	corporate_member.passengers = passengers,
	corporate_member.vehicles = vehicles

	db.session.commit()
	try:
		db.session.commit()
		close(db)
		# clear the cache
		clearCache()
		responseObject = {
			'message': 'Successfully updated {0} information'.format(company_name)
		}
		return make_response(jsonify(responseObject)), 200
	except Exception as identifier:
		responseObject = {
			'status': str(identifier),
			'message': 'Error encountered while trying to update the information'
		}
		return make_response(jsonify(responseObject)), 500


@app.route('/add/member', methods=['POST'])
def addMember():
	empty_set = []
	results = db.session.query(Member.id).order_by(Member.id.desc()).first()
	last_valuation = results[0] if results else 0

	first_name = request.json['first_name']
	last_name = request.json['sur_name']
	gender = request.json['gender_id']
	dob = request.json['dob']
	registration_type = request.json['registration_type']
	member_setting = request.json['member_setting']
	# id_alien_number = request.json['id_alien_number']
	postal_address = request.json['postal_address']
	postal_code = request.json['postal_code']
	title = request.json['title']
	email = request.json['email'] if Validation.validateEmail(
		request.json['email']) == True else empty_set.append('Email address is invalid')
	tel_number = request.json['tel_number'] if Validation.validatePhoneNumber(
		request.json['tel_number'])[0] == True else empty_set.append('The Phone Number is invalid')
	household_type = request.json['household_type']
	residence = request.json['residence']
	promo_code = request.json['promo_code']

	try:
		id_alien_number = request.json['id_alien_number']
	except Exception:
		id_alien_number = None

	if db.session.query(Member).filter(Member.membership_status == 1).filter_by(email=email).first():
		return jsonify({'message': 'We already have such an email in use'}), 412

	family = []
	age_count = []

	if 'family' in request.json:
		family = request.json['family']

		# check if there are more that two people over the age of 18
		for data in family:
			datetime_object = datetime.strptime(data['dob'], '%Y-%m-%d')
			age = (datetime.now() - datetime_object) // timedelta(days=365.2425)

			if age > 18:
				age_count.append(age)

		if len(age_count) > 2:
			empty_set.append(
				'You are not allowed to have more than 2 people above the age of 18')

	if not residence or not household_type or not registration_type or not gender:
		# if not residence or not household_type or not registration_type or not id_alien_number or not gender:
		try:
			if not residence:
				empty_set.append('Residence is required')

			if not household_type:
				empty_set.append('House type is required')

			if not registration_type:
				empty_set.append("Registration type is required")

			# if not id_alien_number:
			# 	empty_set.append("ID Number is required")

			if not gender:
				empty_set.append("Gender is required")

			if not dob:
				empty_set.append("Date of Birth is required")

			if empty_set:
				responseObject = {
					'messages': empty_set
				}
				return make_response(jsonify(responseObject)), 422
		except Exception as error:
			responseObject = {
				'message': 'An error is occuring',
				'error': str(error)
			}
			return make_response(jsonify(responseObject)), 500
	elif empty_set:
		responseObject = {
			'messages': empty_set
		}
		return make_response(jsonify(responseObject)), 422
	else:
		# get the member class prefix
		member_type_public_id, = db.session.query(
			MemberSetting.membertype_public_id).filter_by(public_id=member_setting).first()
		get_relation_to_level, = db.session.query(MemberType.ml_public_id).filter_by(
			public_id=member_type_public_id).first()
		prefix, = db.session.query(MembershipLevel.prefix).filter_by(
			public_id=get_relation_to_level).first()
		level_name, = db.session.query(MembershipLevel.name).filter_by(
			public_id=get_relation_to_level).first()

		# get total member count
		member_count = db.session.query(MemberSetting).filter_by(
			public_id=member_setting).filter(MemberSetting.deletion_marker == None).first()

		valid_members = int(member_count.number_of_persons +
							member_count.number_of_children)
		input_members = int(len(family) + 1)

		if input_members > valid_members:
			responseObject = {
				'message': 'Yourz are currently exceeding the amount of persons required under this membership'
			}
			return make_response(jsonify(responseObject)), 422

		datetime_object = datetime.strptime(dob, '%Y-%m-%d')
		age = (datetime.now() - datetime_object) // timedelta(days=365.2425)

		if age < 18:
			responseObject = {
				'message': 'Sorry, but our membership policy, states that the lead contact must be above 18 years of age'
			}
			return make_response(jsonify(responseObject)), 422

		# print probable member ID
		last_valuation = int(last_valuation) + 1
		member_id = "{}{}{}".format(
			str(prefix), str(0000), str(last_valuation))

		if not db.session.query(Member).filter_by(email=email, tel_number=tel_number).filter(Member.deletion_marker == None).first():
			m_public_id = str(uuid.uuid4())[:20]
			new_member = Member(
				public_id=m_public_id,
				first_name=first_name,
				sur_name=last_name,
				gender=gender,
				dob=dob,
				residence=residence,
				registration_type=registration_type,
				member_setting=member_setting,
				id_alien_number=id_alien_number,
				postal_address=postal_address,
				postal_code=postal_code,
				title=title,
				email=email,
				tel_number=tel_number,
				household_type=household_type,
				status=5,
				membershipid=member_id,
				member_level=member_type_public_id,
				salesforce_flag=0,
				payment_status=0,
				promo_code=promo_code,
				membership_status=0,
				created_at=datetime.now()
			)

			db.session.add(new_member)

			# loop through the details of the family tag
			if family:
				id_number = None
				for data in family:
					try:
						id_nmuber = data['id_alien_number']
					except Exception:
						id_nmuber = None

					family_member = FamilyMember(
						membership_id=m_public_id,
						public_id=str(uuid.uuid4())[:10],
						first_name=data['first_name'],
						sur_name=data['sur_name'],
						title=data['title'],
						email=data['email'] if data['email'] else "",
						tel_number=data['phone_number'] if data['phone_number'] else "",
						gender=data['gender_id'],
						dob=data['dob'],
						id_alien_number=id_number,
						postal_address=data['postal_address'],
						postal_code=data['postal_code'] if data['postal_code'] else 0,
						family_type=household_type,
						created_at=datetime.now(),
						salesforce_flag=0
					)
					db.session.add(family_member)

			try:
				db.session.commit()

				amount, = db.session.query(MemberSetting.price).filter_by(
					public_id=member_setting).first()
				datenow = (datetime.now()).strftime("%B %Y")

				# send an email
				full_name = title.strip().title() + " " + first_name.strip().title() + \
					" " + last_name.strip().title()
				recipients = email
				sender = app.config['MAIL_ADDRESS']
				sg = sendgrid.SendGridAPIClient(
					apikey=app.config['SENDGRID_API_KEY'])
				from_email = Email(sender)
				to_email = Email(recipients)
				subject = "Ol Pejeta Conservancy Membership Registration"
				pass_data = {
					'logo_url': 'https://bookings.olpejetaconservancy.org/img/OlPejetaLogo.b6baecd7.png',
					'email': email,
					'datenow': datenow,
					'full_name': full_name,
					'membership_level': level_name,
					'amount': amount,
					'membership_ref_code': m_public_id,
					'confirm_account_url': 'https://{0}/membership-payment/{1}'.format(app.config['SERVER'], m_public_id),
					'copyright_year': datetime.now().strftime("%Y")
				}
				content = Content(
					"text/html", render_template('new_member.html', data=pass_data))
				mail = Mail(from_email, subject, to_email, content)
				response = sg.client.mail.send.post(request_body=mail.get())
				close(db)

				# clear the cache data
				clearCache()

				responseObject = {
					'message': '{0} has successfully been added, An email has being sent to {1}'.format(full_name, email),
					'amount': amount,
					'member_ref_code': m_public_id
				}
				return make_response(jsonify(responseObject)), 200
			except Exception as identifier:
				db.session.rollback()
				close(db)
				clearCache()
				responseObject = {
					'status': str(identifier),
					'message': 'Could not add the member'
				}
				return make_response(jsonify(responseObject)), 500
		else:
			resposeObject = {
				'message': 'Seems like there is a repeating email or phone number'
			}
			return make_response(jsonify(resposeObject)), 201


@app.route('/add/corporate/member', methods=['POST'])
def addCorporate():
	errors = []

	member_id = request.json['member_id']
	company_name = request.json['company_name']
	email = request.json['email'] if Validation.validateEmail(
		request.json['email']) == True else errors.append('Email address is invalid')
	phone_number = request.json['phone_number'] if Validation.validatePhoneNumber(
		request.json['phone_number'])[0] == True else errors.append('The Phone Number is invalid')
	contact_person_name = request.json['contact_person_name']
	contact_person_phone_number = request.json['contact_person_phone_number']
	salesforce_uuid = request.json['salesforce_uuid']
	postal_address = request.json['postal_address']
	postal_code = request.json['postal_code']
	salesforce_contact_uuid = request.json['salesforce_contact_uuid']
	salesforce_account_uuid = request.json['salesforce_account_uuid']
	expiry_date = request.json['expiry_date']
	amount = request.json['amount']
	# should be 1 for yes 0 for No
	payment_status = request.json['payment_status']
	payment_method = request.json['payment_method']
	town = request.json['town']
	code = request.json['code']
	country = request.json['country']
	visits = request.json['visits']
	vehicles = request.json['vehicles']
	passengers = request.json['passengers']
	email1 = request.json['email1']
	email2 = request.json['email2']

	if payment_status == True:
		payment_status = 1
	else:
		payment_status = 0
	if db.session.query(Corporate).filter(Corporate.deletion_marker == None).filter_by(email=email).first():
		return jsonify({'message': 'We already have such an email in use'}), 412

	new_corporate = Corporate(
		public_id=str(uuid.uuid4())[:10],
		member_id=member_id,
		company_name=company_name,
		email=email,
		phone_number=phone_number,
		contact_person_name=contact_person_name,
		contact_person_phone_number=contact_person_phone_number,
		salesforce_uuid=salesforce_uuid,
		salesforce_account_uuid=salesforce_account_uuid,
		salesforce_contact_uuid=salesforce_contact_uuid,
		postal_address=postal_address,
		postal_code=postal_code,
		expiry_date=expiry_date,
		amount=amount if amount else 0,
		payment_status=payment_status,
		payment_method=payment_method,
		created_at=datetime.now(),
		code=code,
		country=country,
		town=town,
		visits=visits,
		passengers=passengers,
		vehicles=vehicles,
		email1=email1,
		email2=email2
	)
	db.session.add(new_corporate)
	db.session.commit()
	clearCache()
	return jsonify({'message': 'Successfully added the corporate member'}), 200


@app.route('/corporate/member')
def corporateMembers():
	members = Corporate.query.all()

	if not members:
		return jsonify({'message': 'No current corporate members'}), 412

	withFullNameArr = []
	for member in members:
		withFullNameObj = member.to_json()
		withFullNameObj["full_name"] = member.company_name
		withFullNameArr.append(withFullNameObj)

	return jsonify({'data': withFullNameArr}), 200
	# return jsonify({'data' : [c_member.to_json() for c_member in members]}), 200


@app.route("/corporate/member/<member_id>", methods=["GET"])
def single_corporate_member(member_id):
	member = db.session.query(Corporate)\
		.filter(Corporate.member_id == member_id)\
		.first()

	if not member:
		return jsonify({"message": "The selected member does not exist."}), 412

	return jsonify(member.to_json()), 200


@app.route('/add/existing/member', methods=['POST'])
def addExistingMember():
	errors = []
	family = []

	first_name = request.json['first_name']
	last_name = request.json['sur_name']
	gender = request.json['gender_id']
	dob = request.json['dob']
	registration_type = request.json['registration_type']
	id_alien_number = request.json['id_alien_number']
	postal_address = request.json['postal_address']
	postal_code = request.json['postal_code']
	title = request.json['title']
	email = request.json['email'] if Validation.validateEmail(
		request.json['email']) == True else errors.append('The provided email address is invalid')
	tel_number = request.json['tel_number'] if Validation.validatePhoneNumber(
		request.json['tel_number'])[0] == True else errors.append('The phone number is invalid')
	household_type = request.json['household_type']
	residence = request.json['residence']
	registration_date = request.json['registration_date']
	member_id = request.json['member_id']
	promo_code = request.json['promo_code']
	# should be 1 for yes 0 for No
	payment_status = request.json['payment_status']
	expiry_date = request.json['expiry_date']
	member_setting = request.json['member_setting']
	payment_method = request.json['payment_method']
	salesforce_uuid = request.json['salesforce_id']
	salesforce_contact_uuid = request.json['salesforce_contact_uuid']
	# The UI misbehaves, sending the field as UUID or ID
	temp_uuid = request.json['salesforce_account_id']
	salesforce_account_uuid = request.json.get(
		'salesforce_account_uuid', temp_uuid)

	validation_list = [
		{"field": "first_name", "alias": "First name"},
		{"field": "sur_name", "alias": "Last name"},
		{"field": "gender_id", "alias": "Gender"},
		{"field": "dob", "alias": "Date of birth"},
		{"field": "registration_type", "alias": "Registration type"},
		{"field": "postal_address", "alias": "Postal address"},
		{"field": "postal_code", "alias": "Postal code"},
		{"field": "title"},
		{"field": "household_type", "alias": "Household type"},
		{"field": "residence"},
		{"field": "member_id", "alias": "Member ID"},
		{"field": "payment_status", "alias": "Payment status"},
		{"field": "expiry_date", "alias": "Membership expiry date"},
		{"field": "member_setting", "alias": "Member setting"},
		{"field": "payment_method", "alias": "Payment method"},
		{"field": "salesforce_id", "alias": "Salesforce opportunity ID"},
		{"field": "salesforce_contact_uuid", "alias": "Salesforce contact ID"},
		{"field": "session_id", "alias": "Session ID"}
	]

	validation_errors = field_validation(request.json, validation_list)
	errors = errors + validation_errors

	# if 'payment_status' not in request.json:
	# 	errors.append('Payment status is missing')

	# if 'expiry_date' not in request.json:
	# 	errors.append('Expiry Date is missing')

	# if 'payment_method' not in request.json:
	# 	errors.append('Payment Method is missing')

	if errors:
		return jsonify({'messages': errors}), 422

	if request.json['family']:
		family = request.json['family']

	if db.session.query(Member).filter_by(email=email).first():
		return jsonify({
			'message': 'The email address {} is already in use'.format(email)
		}), 412

	if db.session.query(Member).filter_by(membershipid=member_id).first():
		return jsonify({
			'message': 'The membership ID has already been registered'
		}), 412

	if db.session.query(Member).filter_by(tel_number=tel_number).first():
		return jsonify({
			'message': 'The phone number {} is already in use'.format(tel_number)
		}), 412

	member_type_public_id, = db.session.query(MemberSetting.membertype_public_id)\
		.filter_by(public_id=member_setting)\
		.first()

	m_public_id = str(uuid.uuid4())[:20]

	new_member = Member(
		public_id=m_public_id,
		first_name=first_name,
		sur_name=last_name,
		gender=gender,
		dob=dob,
		residence=residence,
		registration_type=registration_type,
		id_alien_number=id_alien_number,
		postal_address=postal_address,
		postal_code=postal_code,
		title=title,
		email=email,
		tel_number=tel_number,
		household_type=household_type,
		status=5,
		membershipid=member_id,
		payment_status=1 if payment_status == True else 0,
		promo_code=promo_code,
		salesforce_flag=0,
		expiry_date=expiry_date,
		member_level=member_type_public_id,
		member_setting=member_setting,
		payment_method=payment_method,
		created_at=datetime.now(),
		salesforce_uuid=salesforce_uuid if salesforce_uuid else None,
		contact_uuid=salesforce_contact_uuid if salesforce_contact_uuid else None,
		salesforce_account_id=salesforce_account_uuid if salesforce_account_uuid else None
	)
	db.session.add(new_member)
	db.session.commit()
	close(db)
	# clear the cache data
	clearCache()

	if family:
		for data in family:
			family_member = FamilyMember(
				membership_id=m_public_id,
				public_id=str(uuid.uuid4())[:10],
				first_name=data['first_name'],
				sur_name=data['sur_name'],
				title=data['title'],
				email=data['email'] if data['email'] else "",
				tel_number=data['phone_number'] if data['email'] else "",
				gender=data['gender_id'],
				dob=data['dob'],
				id_alien_number=data['id_alien_number'],
				postal_address=data['postal_address'],
				postal_code=data['postal_code'] if data['postal_code'] else 0,
				family_type=household_type,
				created_at=datetime.now(),
				salesforce_flag=0
			)
			db.session.add(family_member)
		db.session.commit()
		clearCache()

	try:
		db.session.commit()
		close(db)
		# clear the cache data
		clearCache()

		return jsonify({'message': 'Member has successfully been added'})
	except Exception as identifier:
		db.session.rollback()
		close(db)
		responseObject = {
			'status': str(identifier),
			'message': 'Could not add the member'
		}
		return make_response(jsonify(responseObject)), 500


@app.route('/renew/membership/<public_id>', methods=['POST'])
def renewMembership(public_id):
	member_setting = request.json['member_setting']
	if member_setting:
		member = db.session.query(Member).filter_by(
			public_id=public_id).first()

		if member:
			# GET MEMEBER EXPIRY DATE
			if member.expiry_date:
				member.expiry_date = member.expiry_date + timedelta(days=379)
				member.payment_status = 1
				member.status = 5
				member.member_setting = member_setting
				member.updated_at = datetime.now()
			else:
				member.expiry_date = datetime.now() + timedelta(days=379)
				member.payment_status = 1
				member.status = 5
				member.member_setting = member_setting
				member.updated_at = datetime.now()

			try:
				db.session.commit()

				# get the membership applied for
				member_type_id, = db.session.query(MemberSetting.membertype_public_id).filter_by(
					public_id=member.member_setting).first()
				member_type, = db.session.query(MemberType.name).filter_by(
					public_id=member_type_id).first()
				residence, = db.session.query(Residence.name).filter_by(
					public_id=member.residence).first()
				setting, = db.session.query(MemberSetting.name).filter_by(
					public_id=member.member_setting).first()
				datenow = (datetime.now()).strftime("%B %Y")
				membership_content = '{0} / {1} / {2}'.format(
					member_type, setting, residence)

				sender = app.config['MAIL_ADDRESS']
				sg = sendgrid.SendGridAPIClient(
					apikey=app.config['SENDGRID_API_KEY'])
				from_email = Email(sender)
				to_email = Email(member.email)
				subject = "Membership Renewal"
				payload = {
					'logo_url': 'https://bookings.olpejetaconservancy.org/img/OlPejetaLogo.b6baecd7.png',
					'full_name': member.first_name.strip().title(),
					'payment_date': datetime.now(),
					'datenow': datenow,
					'membership': membership_content,
					'membership_ref_code': member.membershipid,
					'expiry_date': member.expiry_date,
					'copyright_year': datetime.now().strftime("%Y")
				}
				content = Content(
					"text/html", render_template('renewed.html', data=payload))
				mail = Mail(from_email, subject, to_email, content)
				response = sg.client.mail.send.post(request_body=mail.get())
				close(db)
				# clear the cache data
				clearCache()

				responseObject = {
					'message': 'Successfully renewed your application'
				}
				return make_response(jsonify(responseObject)), 200
			except Exception as err:
				db.session.rollback()
				close(db)
				responseObject = {
					'error': str(err),
					'message': 'An error has occured'
				}
				return make_response(jsonify(responseObject))
		else:
			responseObject = {
				'message': 'Could not find the member'
			}
			return make_response(jsonify(responseObject)), 412
	else:
		responseObject = {
			'message': 'Not all fields have been provided'
		}
		return make_response(jsonify(responseObject)), 422


@app.route('/delete/member/<public_id>', methods=['POST'])
def deleteMemberOld(public_id):
	member = db.session.query(Member).filter_by(public_id=public_id).first()
	if not member:
		responseObject = {
			'message': 'Member is not available'
		}
		return make_response(jsonify(responseObject)), app.config['ERROR_CODE']
	else:
		# member.updated_at = datetime.utcnow
		member.deletion_marker = 1
		member.status = 10  # marks it as a deleted element
		member.updated_at = datetime.now()

		try:
			db.session.commit()
			close(db)
			# clear the cache data
			clearCache()

			responseObject = {
				'message': 'Successfully removed the member'
			}
			return make_response(jsonify(responseObject)), 200
		except Exception as identifier:
			db.session.rollback()
			close(db)
			responseObject = {
				'message': str(identifier)
			}
			return make_response(jsonify(responseObject)), 500


@app.route('/delete/member', methods=['POST'])
def deleteMember():
	public_id = request.json['member_id']
	member = db.session.query(Member).filter_by(public_id=public_id).first()
	if not member:
		responseObject = {
			'message': 'Member is not available'
		}
		return make_response(jsonify(responseObject)), app.config['ERROR_CODE']
	else:
		member.updated_at = datetime.utcnow
		member.deletion_marker = 1
		member.status = 10  # marks it as a deleted element
		member.updated_at = datetime.now()

		try:
			db.session.commit()
			close(db)
			# clear the cache data
			clearCache()

			responseObject = {
				'message': 'Successfully removed the member'
			}
			return make_response(jsonify(responseObject)), 200
		except Exception as identifier:
			db.session.rollback()
			close(db)
			responseObject = {
				'message': str(identifier)
			}
			return make_response(jsonify(responseObject)), 500


@app.route('/iveri/confirm/member/<public_id>')
def confirmMember(public_id):
	member = db.session.query(Member).filter_by(public_id=public_id).first()

	if not member:
		responseObject = {
			'message': 'No such member account is available'
		}
		return make_response(jsonify(responseObject)), app.config['ERROR_CODE']
	else:
		post_member_records_salesforce(public_id)
		member.membership_status = 1
		member.status = 5
		member.payment_status = 1  # denotes a paid member
		member.payment_method = 'Credit Card'
		# calculate Expiry Date
		member.expiry_date = datetime.now() + timedelta(days=379)
		member.payment_date = datetime.now()

		db.session.commit()
		sender = app.config['MAIL_ADDRESS']
		sg = sendgrid.SendGridAPIClient(apikey=app.config['SENDGRID_API_KEY'])
		from_email = Email(sender)
		to_email = Email(member.email)
		subject = "Ol Pejeta Conservancy Membership Payment"

		# get the membership applied for
		member_type_id, = db.session.query(MemberSetting.membertype_public_id).filter_by(
			public_id=member.member_setting).first()
		member_type, = db.session.query(MemberType.name).filter_by(
			public_id=member_type_id).first()
		residence, = db.session.query(Residence.name).filter_by(
			public_id=member.residence).first()
		setting, = db.session.query(MemberSetting.name).filter_by(
			public_id=member.member_setting).first()
		datenow = (datetime.now()).strftime("%B %Y")
		membership_content = '{0} / {1} / {2}'.format(
			member_type, setting, residence)

		payload = {
			'logo_url': 'https://bookings.olpejetaconservancy.org/img/OlPejetaLogo.b6baecd7.png',
			'full_name': member.first_name.strip().title(),
			'payment_date': datetime.now(),
			'datenow': datenow,
			'membership': membership_content,
			'membership_ref_code': member.membershipid,
			'expiry_date': (datetime.now() + timedelta(days=379)).strftime('%x'),
			'copyright_year': datetime.now().strftime("%Y")
		}
		content = Content(
			"text/html", render_template('membershippayment.html', data=payload))
		mail = Mail(from_email, subject, to_email, content)
		response = sg.client.mail.send.post(request_body=mail.get())
		return redirect('https://www.olpejetaconservancy.org/', code=302)


@app.route('/mpesa/confirm/member/<public_id>', methods=['POST'])
def confirmMpesaMember(public_id):
	mpesa_txn = request.json['mpesa_ref']
	member = db.session.query(Member).filter_by(membershipid=public_id).first()
	if not member:
		responseObject = {
			'message': 'No such member account is available'
		}
		return make_response(jsonify(responseObject)), 412
	else:
		post_member_records_salesforce(member.public_id)
		member.membership_status = 1
		member.status = 5
		member.payment_status = 1  # denotes a paid member
		member.payment_method = 'Mpesa'
		member.mpesa_txn_code = mpesa_txn
		member.payment_date = datetime.now()

		# calculate Expiry Date
		member.expiry_date = datetime.now() + timedelta(days=379)
		datenow = (datetime.now()).strftime("%B %Y")
		db.session.commit()

		# send mail
		sender = app.config['MAIL_ADDRESS']
		sg = sendgrid.SendGridAPIClient(apikey=app.config['SENDGRID_API_KEY'])
		from_email = Email(sender)
		to_email = Email(member.email)
		subject = "Ol Pejeta Conservancy Membership Payment"

		# get the membership applied for
		member_type_id, = db.session.query(MemberSetting.membertype_public_id).filter_by(
			public_id=member.member_setting).first()
		member_type, = db.session.query(MemberType.name).filter_by(
			public_id=member_type_id).first()
		residence, = db.session.query(Residence.name).filter_by(
			public_id=member.residence).first()
		setting, = db.session.query(MemberSetting.name).filter_by(
			public_id=member.member_setting).first()

		membership_content = '{0} / {1} / {2}'.format(
			member_type, setting, residence)
		payload = {
			'logo_url': 'https://bookings.olpejetaconservancy.org/img/OlPejetaLogo.b6baecd7.png',
			'full_name': member.first_name.strip().title(),
			'payment_date': datetime.now(),
			'datenow': datenow,
			'membership': membership_content,
			'membership_ref_code': member.membershipid,
			'expiry_date': (datetime.now() + timedelta(days=379)).strftime('%x'),
			'copyright_year': datetime.now().strftime("%Y")
		}
		content = Content(
			"text/html", render_template('membershippayment.html', data=payload))
		mail = Mail(from_email, subject, to_email, content)
		response = sg.client.mail.send.post(request_body=mail.get())
		responseObject = {
			'message': 'successfully sent email'
		}
		return make_response(jsonify(responseObject)), 200


''' Check users whose membership is not paid after a month of signing up'''


@app.route('/membership/email/reminder')
def emailReminder():
	members = db.session.query(Member).filter_by(payment_status=0).all()
	if not members:
		return 'All have paid on time'

	for member in members:
		if datetime.now() > timedelta(days=30):
			# send mail to the member
			sender = app.config['MAIL_ADDRESS']
			sg = sendgrid.SendGridAPIClient(
				apikey=app.config['SENDGRID_API_KEY'])
			from_email = Email(sender)
			to_email = Email(member.email)
			subject = "Ol Pejeta Conservancy"
			full_name = member.title.strip().title() + " " + member.first_name.strip().title() + \
				" " + member.sur_name.strip().title()
			pass_data = {
				'logo_url': 'https://bookings.olpejetaconservancy.org/img/OlPejetaLogo.b6baecd7.png',
				'email': member.email,
				'full_name': full_name,
				'confirm_account_url': app.config['CONFIRMATION_URL'].format(member.public_id),
				'copyright_year': datetime.now().strftime("%Y")
			}
			content = Content(
				"text/html", render_template('reminder.html', data=pass_data))
			mail = Mail(from_email, subject, to_email, content)
			response = sg.client.mail.send.post(request_body=mail.get())
			close(db)

			return 'Successful sent mail'


@app.route('/membership/email/reminder/<public_id>')
def emailReminderSolo(public_id):
	"""
	Sends an email to an applicant who has yet to pay for the membership
	"""
	member = db.session.query(Member).filter_by(public_id=public_id).first()
	if not member:
		return jsonify({'message': 'No such member can be found'}), 422

	# get the membership applied for
	member_setting_query = db.session.query(MemberSetting)\
		.filter(MemberSetting.public_id == member.member_setting)\
		.first()

	member_type_id = member_setting_query.membertype_public_id
	setting = member_setting_query.name

	amount = member_setting_query.price

	member_type, = db.session.query(MemberType.name).filter_by(
		public_id=member_type_id).first()
	residence, = db.session.query(Residence.name).filter_by(
		public_id=member.residence).first()

	membership_content = '{0} / {1} / {2}'.format(
		member_type, setting, residence)

	family_members = db.session.query(FamilyMember)\
		.filter_by(membership_id=member.public_id, status=5)\
		.count()

	##
	if family_members > 3:
		resident_fee = 4800
		citizen_fee = 2400

		if member.residence == 'berbere':
			amount_due = amount + (resident_fee * (family_members - 3))
		else:
			amount_due = amount + (citizen_fee * (family_members - 3))

	else:
		amount_due = amount

	sender = "membership@olpejetaconservancy.org"
	sg = sendgrid.SendGridAPIClient(apikey=app.config['SENDGRID_API_KEY'])
	from_email = Email(sender)
	to_email = Email(member.email)
	subject = "Membership Payment Reminder"
	full_name = member.title.strip().title() + " " + member.first_name.strip().title() + \
		" " + member.sur_name.strip().title()
	pass_data = {
		'logo_url': 'https://bookings.olpejetaconservancy.org/img/OlPejetaLogo.b6baecd7.png',
		'email': member.email,
		'full_name': full_name,
		'membership': membership_content,
		'membership_ref_code': member.public_id,
		'amount_due': amount_due,
		'confirm_account_url': 'https://{0}/membership-payment/{1}'.format(app.config['SERVER'], member.public_id),
		'copyright_year': datetime.now().strftime("%Y")
	}
	content = Content(
		"text/html", render_template('reminder.html', data=pass_data))
	mail = Mail(from_email, subject, to_email, content)
	response = sg.client.mail.send.post(request_body=mail.get())
	close(db)
	return jsonify({'message': 'Email has successfully been sent to {}'.format(member.email)}), 200


@app.route('/membership/email/expiry/reminder/<public_id>')
def emailReminderExpiry(public_id):
	"""
	Sends an email to a member whose membership is nearing expiry or has already expired.
	"""
	member = db.session.query(Member).filter_by(public_id=public_id).first()
	if not member:
		return jsonify({'message': 'No such member can be found'}), 422

	sender = app.config['MAIL_ADDRESS']
	sg = sendgrid.SendGridAPIClient(apikey=app.config['SENDGRID_API_KEY'])
	from_email = Email(sender)
	to_email = Email(member.email)
	subject = "Ol Pejeta Conservancy"
	full_name = member.title.strip().title() + " " + member.first_name.strip().title() + \
		" " + member.sur_name.strip().title()
	pass_data = {
		'logo_url': 'https://bookings.olpejetaconservancy.org/img/OlPejetaLogo.b6baecd7.png',
		'email': member.email,
		'full_name': full_name,
		'membership_ref_code': member.public_id,
		'confirm_account_url': 'https://{0}/membership-payment/{1}'.format(app.config['SERVER'], member.public_id),
		'copyright_year': datetime.now().strftime("%Y")
	}
	content = Content(
		"text/html", render_template('reminder_membership.html', data=pass_data))
	mail = Mail(from_email, subject, to_email, content)
	response = sg.client.mail.send.post(request_body=mail.get())
	close(db)
	return jsonify({'message': 'Email has successfully been sent to {}'.format(member.email)}), 200


@app.route("/members/batchfile", methods=["POST"])
def members_batchfile_data():
	start_date = request.json["start_date"]
	end_date = request.json["end_date"]

	start = generateDate(start_date)
	end = generateDate(end_date)

	date_array = []

	while start <= end:
		date_array.append(start.strftime("%Y-%m-%d"))

		start = start + timedelta(days=1)

	get_memberships = db.session.query(Member)\
		.all()

	data = []
	existing_memberships = []

	if not get_memberships:
		message = []
		message.append("There are no membership records.")
		return jsonify({"message": message, "data": data}), 412

	for single_membership in get_memberships:
		for single_date in date_array:
			if single_membership.public_id in existing_memberships:
				pass
			else:
				if single_membership.payment_date:
					if single_membership.payment_date.strftime("%Y-%m-%d") == single_date:
						member_name = single_membership.first_name + " " + single_membership.sur_name

						if len(member_name) >= 30:
							customer_reference = member_name[:29]
						else:
							customer_reference = member_name

						amount, = db.session.query(MemberSetting.price)\
							.filter(MemberSetting.public_id == single_membership.member_setting)\
							.first()

						family_members = db.session.query(FamilyMember)\
							.filter(FamilyMember.membership_id == single_membership.public_id)\
							.filter(FamilyMember.status == 5)\
							.all()

						if len(family_members) > 3:
							resident_fee = 4800
							citizen_fee = 2400
							if single_membership.residence == 'berbere':
								amount = amount + \
									(resident_fee * (len(family_members)-3))
							else:
								amount = amount + \
									(citizen_fee * (len(family_members)-3))

						member_credit_data = {}
						member_credit_data["income_account"] = "104037"
						member_credit_data["customer_reference"] = customer_reference
						member_credit_data["currency"] = "KES"
						member_credit_data["sales_date"] = str(
							single_membership.payment_date.strftime("%d%m%Y"))
						member_credit_data["tran_quantity"] = 1
						member_credit_data["dc_marker"] = "C"
						member_credit_data["conversion_rate"] = 1
						member_credit_data["journal_type"] = "VI"
						member_credit_data["account_description"] = single_membership.membershipid
						member_credit_data["outlet"] = "O16"
						member_credit_data["department"] = "D27"
						member_credit_data["base_amount"] = amount

						data.append(member_credit_data)

						member_debit_data = {}
						member_debit_data["income_account"] = "104037"
						member_debit_data["customer_reference"] = customer_reference
						member_debit_data["currency"] = "KES"
						member_debit_data["sales_date"] = str(
							single_membership.payment_date.strftime("%d%m%Y"))
						member_debit_data["tran_quantity"] = 1
						member_debit_data["dc_marker"] = "D"
						member_debit_data["conversion_rate"] = 1
						member_debit_data["journal_type"] = "VI"
						member_debit_data["account_description"] = single_membership.membershipid
						member_debit_data["outlet"] = "#"
						member_debit_data["department"] = "#"
						member_debit_data["base_amount"] = amount

						data.append(member_debit_data)

						existing_memberships.append(
							single_membership.public_id)

	get_transactions = db.session.query(Transaction)\
		.all()

	payment_data = []
	existing_transactions = []

	for single_transaction in get_transactions:
		for single_date in date_array:
			if single_transaction.public_id in existing_transactions:
				pass
			else:
				if single_transaction.transaction_date.strftime("%Y-%m-%d") == single_date:
					get_member = db.session.query(Member)\
						.filter(Member.public_id == single_transaction.member_id)\
						.first()

					member_name = get_member.first_name + " " + get_member.sur_name

					if len(member_name) >= 30:
						customer_reference = member_name[:29]
					else:
						customer_reference = member_name

					customer_data = {}
					customer_data["sales_date"] = str(
						single_transaction.transaction_date.strftime("%d%m%Y"))
					customer_data["customer_reference"] = customer_reference
					customer_data["dc_marker"] = "C"
					customer_data["account_description"] = single_transaction.ticket
					customer_data["currency_code"] = single_transaction.currency
					customer_data["currency"] = "KES"
					customer_data["tran_quantity"] = 1
					customer_data["unit_price"] = round(
						float(single_transaction.transaction_total), 2)
					customer_data["journal_type"] = "VI"
					customer_data["outlet"] = "#"
					customer_data["department"] = "#"
					customer_data["conversion_rate"] = 1

					payment_data.append(bank_data)

					bank_data = {}

					payment_data.append(bank_data)

					existing_transactions.append(single_transaction.public_id)

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