1

 

import os
import re
import pytz
import asyncio
import json
import csv
import base64
import datetime as dt
from pytz import UTC
from datetime import datetime, timedelta
from collections import defaultdict
from bson.objectid import ObjectId
from django.shortcuts import render
from django.views import generic
from django.http import HttpResponse
from django.conf import settings
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from therapist_mgr_app.utils import *
from clinic_mgr_app.utils.notification_city_list import notification_city_list_reversed
from therapist_mgr_app.views.view_commons import get_eligible_records, generate_therapist_auth_token
from therapist_mgr_app.forms import TherapyBookingForm
from therapist_mgr_app.views.therapist.insert_therapy_booking import THERAPY_BOOKING_DEFAULT_DICT
from geopy.geocoders import Nominatim


IST = pytz.timezone('Asia/Kolkata')
USER_ID_DATE_IDX = 'user_id_date_idx'
email = 'raghavan@ayursh.com'
CREDS = settings.GS_CREDENTIALS
CREDS = CREDS.with_scopes(['https://www.googleapis.com/auth/gmail.readonly'])
CREDS = CREDS.with_subject(email)
service = build("gmail", "v1", credentials=CREDS)
SKIP_NUMBERS = ['+919916788332', '+919632608009']


def convert_sec_to_time(seconds):
min, sec = divmod(seconds, 60)
hour, min = divmod(min, 60)
return '%02d:%02d' % (min, sec)


async def get_knowlarity_users(calendar_date, user_profiles_data, request, calendar_end_date=None):

all_call_logs = {}
merged_profiles = {}


if calendar_end_date:
url = (
f"{knowlarity_user_login_host}"
f"?calendar_date={calendar_date}"
f"&calendar_end_date={calendar_end_date}"
)
else:
url = f"{knowlarity_user_login_host}?calendar_date={calendar_date}"

knowlarity_response = await create_async_tasks(None, url, [''])
_, _, response = knowlarity_response[0]
data = json.loads(response)['data']

profiles = data['knowlarity_user_profiles']
call_logs = data['call_logs']


for phone, logs in call_logs.items():
normalized = phone if phone.startswith('+') else '+91' + phone
if normalized not in all_call_logs:
all_call_logs[normalized] = []
all_call_logs[normalized].extend(logs)

merged_profiles.update(profiles)

knowlarity_user_profiles_dict = {}
for phone_number, profile in merged_profiles.items():
profile['last_login_on'] = UTC.localize(
dt.datetime.fromtimestamp(profile['last_login_on'])
).astimezone(IST)


if phone_number not in SKIP_NUMBERS:
knowlarity_user_profiles_dict[phone_number] = profile

call_logs_dict = all_call_logs
is_list_input = isinstance(user_profiles_data, list)

if is_list_input:
for user_profile in user_profiles_data:
phone_number = user_profile.get('phone_number')
if phone_number:
formatted_phone = phone_number if phone_number.startswith('+') else '+91' + phone_number
if formatted_phone in call_logs_dict:
profile_update = knowlarity_user_profiles_dict.get(formatted_phone, {}).copy()
profile_update.pop('is_web_registration', None)
profile_update.pop('last_login_on', None)
profile_update.pop('last_login_on_time', None)
if user_profile.get('name'):
profile_update.pop('name', None)

user_profile.update(profile_update)
date_str = user_profile.get('date')
all_call_logs_for_phone = call_logs_dict.get(formatted_phone, [])
todays_call_logs = []
day_call_times = []

for call in all_call_logs_for_phone:
call_ts = call.get('call_start_time')
if call_ts:
call_dt = dt.datetime.fromtimestamp(call_ts, tz=IST)
if call_dt.strftime('%Y-%m-%d') == date_str:
todays_call_logs.append(call)
day_call_times.append(call_dt)

user_profile['call_logs'] = todays_call_logs

if not user_profile.get('last_activity_time') and day_call_times:
latest_call = max(day_call_times)
user_profile['last_login_on'] = latest_call
user_profile['last_login_on_time'] = latest_call.strftime('%H:%M')

else:
if user_profile.get('last_login_on'):
user_profile['last_login_on_time'] = user_profile['last_login_on'].strftime('%H:%M')

if user_profile.get('is_web_registration') and not user_profile.get('login_method'):
user_profile['login_method'] = 'web'

else:
for user_id, user_profile in user_profiles_data.items():
phone_number = user_profile.get('phone_number')

if phone_number:
formatted_phone = phone_number if phone_number.startswith('+') else '+91' + phone_number
if formatted_phone in call_logs_dict:
profile_update = knowlarity_user_profiles_dict.get(formatted_phone, {}).copy()
profile_update.pop('is_web_registration', None)

if user_profile.get('name'):
profile_update.pop('name', None)

user_profile.update(profile_update)
user_profile['call_logs'] = call_logs_dict.get(formatted_phone, [])

if user_profile.get('last_login_on'):
user_profile['last_login_on_time'] = user_profile['last_login_on'].strftime('%H:%M')

if user_profile.get('is_web_registration') and not user_profile.get('login_method'):
user_profile['login_method'] = 'web'

app_users = len(user_profiles_data)
knowlarity_users = len(knowlarity_user_profiles_dict)
total_users = len(user_profiles_data)
return app_users, knowlarity_users, total_users


async def get_message_status_update(request_id):
freshworks_api_header = {'Authorization': 'Bearer ' + settings.FRESHWORKS_AUTH_TOKEN}
get_url = 'https://api.in.freshchat.com/v2/outbound-messages?request_id=' + request_id
response = await create_async_tasks(
None,
get_url,
[''],
headers=freshworks_api_header
)
_, _, response = response[0]
response_json = json.loads(response)
outbound_messages = response_json['outbound_messages']
message_created_on = outbound_messages[0]['created_on']
message_status = outbound_messages[0]['status']
return message_status, message_created_on


def fetch_clinic_data(clinics_list):
clinic_profiles_dict = dict()
clinic_list_obj = [ObjectId(clinic) for clinic in clinics_list]
for clinic in clinic_profile_collection.find(
{'_id': {"$in": clinic_list_obj}},
{'clinic_name': 1}
):
clinic_profiles_dict[str(clinic['_id'])] = clinic['clinic_name']
for clinic in google_clinics_collection.find(
{'_id': {"$in": clinic_list_obj}},
{'title': 1}
):
clinic_profiles_dict[str(clinic['_id'])] = clinic['title']
return clinic_profiles_dict


async def get_clinic_notifications(calendar_date, user_profiles_dict, app_user=None):
clinics_list = list()
user_clinic_list_dict = defaultdict(list)
for notification in clinic_notification_collection.find(
{
'date': calendar_date,
'user_id': {"$in": list(user_profiles_dict.keys())}
},
{
'clinic_id': 1, 'whatsapp_request_id': 1, 'whatsapp_request_status': 1, 'user_id': 1
}
):
clinics_list.append(notification['clinic_id'])
message_status = notification['whatsapp_request_status']
if message_status in ['IN_PROGRESS', 'ACCEPTED', 'DELIVERED']:
message_status, message_created_on = await get_message_status_update(notification['whatsapp_request_id'])
update_response = clinic_notification_collection.find_one_and_update(
{
'_id': ObjectId(notification['_id'])
},
{
'$set': {
'whatsapp_request_status': message_status,
}
},
# hint=THERAPY_BOOKINGS_SESSIONS_ID_IDX
)
user_clinic_list_dict[notification['user_id']].append(
{
'clinic_id': notification['clinic_id'],
'message_status': message_status
}
)

clinic_profiles_dict = fetch_clinic_data(clinics_list)
for user_id, clinic_dict_list in user_clinic_list_dict.items():
for clinic_dict in clinic_dict_list:
clinic_id = clinic_dict['clinic_id']
clinic_name = clinic_profiles_dict[clinic_id]
clinic_dict.update({
'clinic_name': clinic_name
})
user_profiles_dict[user_id].update(
{'clinic_notifications': clinic_dict_list}
)


def read_cities_list():
print(os.getcwd())
geolocator = Nominatim(user_agent="MyApp")

with open('therapist_mgr_app/utils_dir/cities_list.csv', 'r') as f:
csv_reader = csv.reader(f, delimiter='\t')
for line in csv_reader:
location = geolocator.geocode(line[1] + ", " + line[4])
if location:
print(("('" + str(int(line[0]) - 1)) + "',",
"('" + line[1] + ', ' + line[4] + "', " +
"[" + str(location.latitude) + ", " + str(location.longitude) + "])),")


def get_users_by_date(calendar_date, eligible_records=None, user=None,
user_phone_numbers=None, user_profiles_dict=None):
date = datetime.strptime(calendar_date, '%Y-%m-%d')
if not date:
date = datetime.today()

if not user_phone_numbers:
start_date = dt.datetime.combine(date, dt.time(0, 0, 0)).astimezone(pytz.utc)
end_date = dt.datetime.combine(date, dt.time(23, 59, 59)).astimezone(pytz.utc)

find_query = {
"$or": [
{
'registered_on': {"$gte": start_date,"$lte": end_date}
},
{
'last_login_on': {"$gte": start_date,"$lte": end_date}
}
]
}
if user and user.clinic_id:
clinic_id = user.clinic_id
# find_query.update({
# 'therapies.clinic_id': clinic_id
# })
else:
clinic_id = None
if not user.is_staff:
return 'Invalid User'
else:
find_query = {
'phone_number': {"$in": user_phone_numbers}
}

if not user_profiles_dict:
user_profiles_dict = dict()
for user_profile in user_profile_collection.find(
find_query,
{
'pin': 0, 'referral_code': 0, 'fcm_token': 0
}
):
if user_profile['phone_number'] not in SKIP_NUMBERS:
if user_profile.get('registered_on'):
x = UTC.localize(user_profile['registered_on']).astimezone(IST)
user_profile['registered_on'] = x
if user_profile.get('last_login_on'):
x = UTC.localize(user_profile['last_login_on']).astimezone(IST)
user_profile['last_login_on'] = x
else:
user_profile['last_login_on'] = user_profile['registered_on']
user_profiles_dict[str(user_profile['_id'])] = user_profile

refetch = False
for user_activity in user_activity_collection.find(
{
"date": calendar_date
},
hint=USER_ID_DATE_IDX
):
is_closed = user_activity.get('is_closed')
closed_at = user_activity.get('closed_at')
if closed_at:
x = UTC.localize(closed_at).astimezone(IST)
closed_at = x
notes = user_activity.get('notes')

try:
coordinates = user_activity.get('coordinates')
if coordinates and isinstance(coordinates, dict):
coordinates = coordinates['coordinates']

user_profiles_dict[user_activity['user_id']].update({
'activities': user_activity.get('activities'),
'is_closed': is_closed,
'closed_at': closed_at
})
if coordinates and coordinates[0] and coordinates[1]:
user_profiles_dict[user_activity['user_id']].update({
'coordinates': coordinates,
})

if notes and notes != '':
user_profiles_dict[user_activity['user_id']].update({
'notes': notes
})
except KeyError:
refetch = True
user_profiles_dict[user_activity['user_id']] = {
'coordinates': coordinates,
'activities': user_activity.get('activities'),
'is_closed': is_closed,
'closed_at': closed_at
}
if notes and notes != '':
user_profiles_dict[user_activity['user_id']].update({
'notes': notes
})

if is_closed and is_closed != '' and is_closed == 'yes':
user_profiles_dict[user_activity['user_id']]['log_status'] = \
'bg-success h-5 border border-success'

if refetch:
for user_profile in user_profile_collection.find(
{
"_id": {
"$in": list(
map(lambda y: ObjectId(y), user_profiles_dict.keys())
)
}
},
):
if user_profile['phone_number'] not in SKIP_NUMBERS:
if user_profile.get('registered_on'):
x = UTC.localize(user_profile['registered_on']).astimezone(IST)
user_profile['registered_on'] = x
if user_profile.get('last_login_on'):
x = UTC.localize(user_profile['last_login_on']).astimezone(IST)
user_profile['last_login_on'] = x
else:
user_profile['last_login_on'] = user_profile['registered_on']

user_profiles_dict[str(user_profile['_id'])].update(user_profile)
else:
user_profiles_dict.pop(str(user_profile['_id']))

for user_id, user_profile in user_profiles_dict.items():
if user_profile.get('_id'):
user_profile['id'] = str(user_profile['_id'])
'''This is to make last login on as the last activity user has done in our systems.'''
activities = user_profile.get('activities', [])
closed_at = user_profile.get('closed_at')
if activities:
for activity in user_profile.get('activities', []):
activity['visit_time'] = UTC.localize(activity['visit_time']).astimezone(IST)
if activity['visit_time'] > user_profile['last_login_on']:
user_profile['last_login_on'] = activity['visit_time']
if closed_at:
if user_profile['last_login_on'] > closed_at:
user_profiles_dict[user_id]['log_status'] = ""
user_profiles_dict[user_id]['is_closed'] = "no"

return user_profiles_dict


def get_all_entries(phone_number=None, name=None):
if not phone_number and not name:
return []
entries = []

if phone_number:
formatted_phone = phone_number if phone_number.startswith('+') else '+91' + phone_number
query = {
"$or": [
{"phone_number": formatted_phone},
{"patient_phone_number": formatted_phone}
]
}
base_user_profiles = user_profile_collection.find_one(
query,
{"pin": 0, "referral_code": 0, "fcm_token": 0}
)
base_user_profiles = [base_user_profiles] if base_user_profiles else []

else:
if len(name) >= 4:
pattern = re.escape(name[:-1]) + ".*" + re.escape(name[-1])
else:
pattern = "^" + re.escape(name)

base_user_profiles = list(
user_profile_collection.find(
{
"$or": [
{"offline_name": {"$regex": pattern, "$options": "i"}},
{"name": {"$regex": pattern, "$options": "i"}}
]
},
{"pin": 0, "referral_code": 0, "fcm_token": 0}
).sort("last_login_on", -1).limit(50)
)

if not base_user_profiles:
return []

for base_user_profile in base_user_profiles:
user_id = str(base_user_profile['_id'])

for daily_record in user_activity_collection.find({"user_id": user_id}).sort("date", -1):
user_profile = base_user_profile.copy()

if user_profile.get('registered_on'):
user_profile['registered_on'] = UTC.localize(
user_profile['registered_on']
).astimezone(IST)

if user_profile.get('last_login_on'):
user_profile['last_login_on'] = UTC.localize(
user_profile['last_login_on']
).astimezone(IST)
user_profile['last_login_on_time'] = user_profile['last_login_on'].strftime('%H:%M')
else:
user_profile['last_login_on'] = user_profile.get('registered_on')
if user_profile['last_login_on']:
user_profile['last_login_on_time'] = user_profile['last_login_on'].strftime('%H:%M')

user_profile['id'] = str(daily_record['_id'])
user_profile['user_id'] = user_id

activities = daily_record.get('activities', [])
last_activity_time = None

for activity in activities:
vt = activity.get('visit_time')
if vt:
vt_ist = vt.astimezone(IST)
activity['visit_time'] = vt_ist
if not last_activity_time or vt_ist > last_activity_time:
last_activity_time = vt_ist

if last_activity_time:
user_profile['last_login_on'] = last_activity_time
user_profile['last_login_on_time'] = last_activity_time.strftime('%H:%M')

user_profile['activities'] = activities
user_profile['last_activity_time'] = last_activity_time
user_profile['is_closed'] = daily_record.get('is_closed', 'no')
user_profile['coordinates'] = daily_record.get('coordinates')
user_profile['geo_coordinates'] = daily_record.get('geo_coordinates')
user_profile['date'] = daily_record.get('date')

entries.append(user_profile)

def sort_key(x):
date_dt = datetime.strptime(x['date'], '%Y-%m-%d') if x.get('date') else datetime.min
time_dt = x.get('closed_at') if x.get('closed_at') else datetime.min
return (date_dt, time_dt)

entries.sort(key=sort_key, reverse=True)
return entries

class ClinicUser(AyurshUserMixin, generic.View):
login_url = "accounts:signin"

def filter_clinic_users(self, user_profiles_dict):
updated_user_profiles_dict = dict()
if self.request.user and self.request.user.clinic_id:
clinic_id = self.request.user.clinic_id
for user_id, user_profile in user_profiles_dict.items():
for notification in user_profile.get('clinic_notifications', []):
if notification['clinic_id'] == clinic_id:
updated_user_profiles_dict[user_id] = user_profiles_dict[user_id]
else:
if not self.request.user.is_staff:
return 'Invalid User'

'''Overwriting user_profiles_dict with filtered result'''
user_profiles_dict = updated_user_profiles_dict
return user_profiles_dict

async def check_clinic_doctor_therapist(self, user_profiles_dict):
numbers_user_id_dict = {v['phone_number']: k for k, v in user_profiles_dict.items()
if v.get('phone_number')}
numbers = list(numbers_user_id_dict.keys())

for therapist in therapist_profile_collection.find(
{'phone_number': {"$in": numbers}},
{'phone_number': 1}
):
user_id = numbers_user_id_dict[therapist['phone_number']]
user_profiles_dict[user_id].update({
'non_notification_reason': 'THERAPIST'
})

for clinic in google_clinics_collection.find(
{'phone_number': {"$in": numbers}},
{'phone_number': 1}
):
user_id = numbers_user_id_dict[clinic['phone_number']]
user_profiles_dict[user_id].update({
'non_notification_reason': 'CLINIC'
})
await asyncio.sleep(0.001)

def get(self, request, *args, **kwargs):
result_dict = dict()
query_date = request.GET.get('dateFilter')
query_filter = request.GET.get('phoneNumberFilter')
name_filter = request.GET.get('nameFilter')
if query_filter and not query_filter.startswith('+91'):
query_filter = '+91' + query_filter
therapist_query_filter = request.GET.get('therapistphoneNumberFilter')
query_therapy_booking_session_id = request.GET.get('therapyBookingSessionId')
stats = request.GET.get('stats') == 'true'
form = TherapyBookingForm(initial=THERAPY_BOOKING_DEFAULT_DICT)

eligible_records, dept_record = get_eligible_records(request.user.get_username())
unpack_error = None
therapy_bookings_list = list()
if query_date:
date_filter = query_date
else:
date_filter = datetime.today().strftime('%Y-%m-%d')

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
user_profiles_list = []
show_date = False

if query_filter:
user_profiles_list = get_all_entries(phone_number=query_filter)
show_date = True

elif name_filter:
if len(name_filter.strip()) < 3:
user_profiles_list = []
show_date = True
else:
user_profiles_list = get_all_entries(name=name_filter)
show_date = True

if user_profiles_list:
dates = set()
for user in user_profiles_list:
user_date = user.get('date') or user.get('created_at')
if user_date:
if isinstance(user_date, dt.datetime):
user_date = user_date.strftime('%Y-%m-%d')
dates.add(user_date)

dates = list(dates)
start_date = min(dates) if dates else None
end_date = max(dates) if dates else None
app_users, knowlarity_users, total_users = loop.run_until_complete(
get_knowlarity_users(
start_date,
user_profiles_list,
request,
end_date
)
)
else:
user_profiles_dict = get_users_by_date(date_filter, eligible_records, user=request.user)

x = loop.run_until_complete(
asyncio.gather(
*[
get_knowlarity_users(date_filter, user_profiles_dict, request),
# get_clinic_notifications(date_filter, user_profiles_dict, app_user=request.user),
self.check_clinic_doctor_therapist(user_profiles_dict)
]
)
)
if not self.request.user.is_superuser and not dept_record['OWNERS']:
'''Filtering only for clinics and not for Owners'''
user_profiles_dict = self.filter_clinic_users(user_profiles_dict)
app_users, knowlarity_users, total_users = x[0]
user_profiles_list = sorted(list(user_profiles_dict.values()),
key=lambda x: x.get('last_login_on', get_ist_time()),
reverse=True)
loop.close()
# print(notification_city_list)
# for city, coords in notification_city_list:
# print("['" + city + "', " +
# "[" + str(coords[1]) + ", " + str(coords[0]) + ']],')
# read_cities_list()
try:
result_dict.update({'date': date_filter,
'dept_record': dept_record
})
except ValueError:
unpack_error = user_profiles_list

result_dict.update(
{
'form': form,
'show_date':show_date,
'user_profiles': user_profiles_list,
'dept_record': dept_record,
'superuser': self.request.user.is_superuser,
'app_users': app_users,
'knowlarity_users': knowlarity_users,
'total_users': total_users,
'clinic_phone_number': self.request.user.phone_number[3:],
'countries': notification_city_list_reversed
# 'clinic_choices': CLINIC_CHOICES
}
)
if unpack_error:
result_dict.update({'errors': unpack_error})

return render(request, 'clinic_users2.html', result_dict)

def post(self, request, *args, **kwargs):
user_id = kwargs['user_id']
update_type = kwargs['update_type']
cal_date = kwargs['cal_date']
message = 'Customer ' + update_type + ' Not Saved'
cust_name = request.POST.get('cust_name')
cust_notes = request.POST.get('cust_notes')
cust_closed_status = request.POST.get('cust_closed_status')
status_code = 200
if update_type == 'name':
if cust_name and cust_name != '':
result = user_profile_collection.update_one(
{
'_id': ObjectId(user_id),
'name': {"$exists": False}
},
{
"$set": {
'offline_name': cust_name
}
}
)
if result.modified_count == 1:
message = 'Customer Name Saved'
status_code = 201
else:
result = user_profile_collection.update_one(
{
'_id': ObjectId(user_id)
},
{
"$set": {
'name': cust_name
}
}
)
if result.modified_count == 1:
message = 'Customer Name Saved'
status_code = 201
else:
message = 'Invalid Name'
status_code = 403
response = HttpResponse(json.dumps({'message': message,
'cust_name': cust_name}),
content_type="application/json")
response.status_code = status_code
elif update_type == 'notes':
if cust_notes and cust_notes != '':
user_activity_collection.find_one_and_update(
{
'user_id': user_id,
'date': cal_date
},
{
"$set": {
'notes': cust_notes
}
},
upsert=True,
hint=USER_ID_DATE_IDX
)
message = 'Customer Notes Saved'
status_code = 201
else:
message = 'Invalid Notes'
status_code = 403
response = HttpResponse(json.dumps({'message': message,
'cust_notes': cust_notes}),
content_type="application/json")
response.status_code = status_code
elif update_type == 'close-lead':
if cust_closed_status and cust_closed_status != '':
user_activity_collection.find_one_and_update(
{
'user_id': user_id,
'date': cal_date
},
{
"$set": {
'is_closed': cust_closed_status,
'closed_at': get_ist_time(),
'closed_by': self.request.user.email
}
},
upsert=True,
hint=USER_ID_DATE_IDX
)
message = 'Customer Lead Status Saved'
status_code = 201
else:
message = 'Invalid Type'
status_code = 403
response = HttpResponse(json.dumps({'message': message,
'cust_closed_status': cust_notes}),
content_type="application/json")
response.status_code = status_code
return response


class ClinicUserChat(AyurshUserMixin, generic.View):
login_url = "accounts:signin"

def get(self, request, *args, **kwargs):
user_id = kwargs['user_id']

user_profile = user_profile_collection.find_one({
"_id": ObjectId(user_id)
})

result_dict = {
"phone_number": user_profile['phone_number'],
"user_id": user_id,
"restore_id": user_profile.get('restore_id'),
"token": "15c3f8e3-346f-4477-8fc1-e0a27f61f4af",
"host": "https://ayursh-org-72e1fa982b95fb216697299.freshchat.com"
}
return render(request, 'clinic_user_chat.html', {
'result': result_dict
})

def post(self, request, *args, **kwargs):
user_id = kwargs['user_id']
update_type = kwargs['update_type']
cal_date = kwargs['cal_date']
message = 'Customer ' + update_type + ' Not Saved'
cust_name = request.POST.get('cust_name')
cust_notes = request.POST.get('cust_notes')
cust_closed_status = request.POST.get('cust_closed_status')
status_code = 200
if update_type == 'name':
if cust_name and cust_name != '':
result = user_profile_collection.update_one(
{
'_id': ObjectId(user_id),
'name': {"$exists": False}
},
{
"$set": {
'offline_name': cust_name
}
}
)
if result.modified_count == 1:
message = 'Customer Name Saved'
status_code = 201
else:
message = 'Invalid Name'
status_code = 403
response = HttpResponse(json.dumps({'message': message,
'cust_name': cust_name}),
content_type="application/json")
response.status_code = status_code
return response

Comments

Popular Posts