From 91a564989f883293aeeca7479d9f5eaa0a02bc65 Mon Sep 17 00:00:00 2001 From: Pranav Nachanekar Date: Tue, 17 Sep 2019 16:58:41 +0530 Subject: [PATCH] Styling and PR review changes --- .../crm/doctype/appointment/appointment.py | 33 +++---- .../doctype/appointment/test_appointment.py | 14 +-- .../appointment_booking_settings.py | 13 ++- erpnext/crm/doctype/timezone/timezone.py | 6 +- erpnext/www/book-appointment/index.js | 87 ++++++++++--------- erpnext/www/book-appointment/index.py | 18 ++-- 6 files changed, 79 insertions(+), 92 deletions(-) diff --git a/erpnext/crm/doctype/appointment/appointment.py b/erpnext/crm/doctype/appointment/appointment.py index 3a588fbcd8..5408b4d91a 100644 --- a/erpnext/crm/doctype/appointment/appointment.py +++ b/erpnext/crm/doctype/appointment/appointment.py @@ -14,22 +14,21 @@ from frappe.desk.form.assign_to import add as add_assignemnt class Appointment(Document): def validate(self): - number_of_appointments_in_same_slot = frappe.db.count('Appointment',filters={'scheduled_time':self.scheduled_time}) + number_of_appointments_in_same_slot = frappe.db.count('Appointment', filters = {'scheduled_time':self.scheduled_time}) settings = frappe.get_doc('Appointment Booking Settings') if(number_of_appointments_in_same_slot >= settings.number_of_agents): frappe.throw('Time slot is not available') def before_insert(self): - appointment_event = frappe.new_doc('Event') appointment_event = frappe.get_doc({ 'doctype': 'Event', 'subject': ' '.join(['Appointment with', self.customer_name]), 'starts_on': self.scheduled_time, 'status': 'Open', 'type': 'Private', - 'event_participants': [dict(reference_doctype="Lead", reference_docname=self.lead)] + 'event_participants': [dict(reference_doctype = "Lead", reference_docname = self.lead)] }) - appointment_event.insert(ignore_permissions=True) + appointment_event.insert(ignore_permissions = True) self.calendar_event = appointment_event.name def after_insert(self): @@ -37,7 +36,6 @@ class Appointment(Document): for agent in available_agents: if(_check_agent_availability(agent, self.scheduled_time)): agent = agent[0] - agent = frappe.json.loads(agent)[0] add_assignemnt({ 'doctype':self.doctype, 'name':self.name, @@ -45,33 +43,25 @@ class Appointment(Document): }) employee = _get_employee_from_user(agent) if employee: - print(employee) calendar_event = frappe.get_doc('Event', self.calendar_event) calendar_event.append('event_participants', dict( - reference_doctype='Employee', - reference_docname=employee[0].name)) - print(calendar_event) + reference_doctype= 'Employee', + reference_docname= employee.name)) calendar_event.save() break - def _get_agents_sorted_by_asc_workload(): appointments = frappe.db.get_list('Appointment', fields='*') - agent_list = _get_agent_list_as_strings() - + agent_list = _get_agent_list_as_strings() if not appointments: return agent_list - appointment_counter = Counter(agent_list) - for appointment in appointments: assigned_to = frappe.parse_json(appointment._assign) - print(assigned_to) - if appointment._assign == '[]' or not appointment._assign: + if not assigned_to: continue if assigned_to[0] in agent_list: appointment_counter[assigned_to[0]] += 1 - sorted_agent_list = appointment_counter.most_common() sorted_agent_list.reverse() @@ -81,15 +71,13 @@ def _get_agents_sorted_by_asc_workload(): def _get_agent_list_as_strings(): agent_list_as_strings = [] agent_list = frappe.get_doc('Appointment Booking Settings').agent_list - for agent in agent_list: agent_list_as_strings.append(agent.user) - return agent_list_as_strings def _check_agent_availability(agent_email,scheduled_time): - appointemnts_at_scheduled_time = frappe.get_list('Appointment', filters={'scheduled_time':scheduled_time}) + appointemnts_at_scheduled_time = frappe.get_list('Appointment', filters = {'scheduled_time':scheduled_time}) for appointment in appointemnts_at_scheduled_time: if appointment._assign == agent_email: return False @@ -97,4 +85,7 @@ def _check_agent_availability(agent_email,scheduled_time): def _get_employee_from_user(user): - return frappe.get_list('Employee', fields='*',filters={'user_id':user}) \ No newline at end of file + employee_docname = frappe.db.exists({'doctype':'Employee','user_id':user}) + if employee_docname: + return frappe.get_doc('Employee',employee_docname[0][0]) # frappe.db.exists returns a tuple of a tuple + return None \ No newline at end of file diff --git a/erpnext/crm/doctype/appointment/test_appointment.py b/erpnext/crm/doctype/appointment/test_appointment.py index c1a1c4ff46..3c977505b5 100644 --- a/erpnext/crm/doctype/appointment/test_appointment.py +++ b/erpnext/crm/doctype/appointment/test_appointment.py @@ -8,20 +8,8 @@ import unittest import datetime -def create_appointments(number): - for i in range(1, number): - frappe.get_doc({ - 'doctype': 'Appointment', - 'scheduled_time': datetime.datetime.min, - 'customer_name': 'Test Customer'+str(i), - 'customer_phone_number': '8088', - 'customer_skype': 'test'+str(i), - }) - def delete_appointments(): - doc_list = frappe.get_list('Appointment',filters={'scheduled_time':datetime.datetime.min,'customer_phone_number':'8088'}) - for doc in doc_list: - doc.delete() + pass class TestAppointment(unittest.TestCase): diff --git a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py index 8f1fb14f5b..da181ae119 100644 --- a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py +++ b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py @@ -14,17 +14,22 @@ class AppointmentBookingSettings(Document): list_of_days = [] date = '01/01/1970 ' format_string = "%d/%m/%Y %H:%M:%S" + for record in self.availability_of_slots: list_of_days.append(record.day_of_week) # Difference between from_time and to_time is multiple of appointment_duration - from_time = datetime.datetime.strptime(date+record.from_time,format_string) - to_time = datetime.datetime.strptime(date+record.to_time,format_string) + from_time = datetime.datetime.strptime(date+record.from_time, format_string) + to_time = datetime.datetime.strptime(date+record.to_time, format_string) timedelta = to_time-from_time - if(from_time>to_time): + + if(from_time > to_time): frappe.throw('From Time cannot be later than To Time for '+record.day_of_week) - if timedelta.total_seconds() % (self.appointment_duration*60): + + if timedelta.total_seconds() % (self.appointment_duration * 60): frappe.throw('The difference between from time and To Time must be a multiple of Appointment ') + set_of_days = set(list_of_days) + if len(list_of_days) > len(set_of_days): frappe.throw(_('Days of week must be unique')) diff --git a/erpnext/crm/doctype/timezone/timezone.py b/erpnext/crm/doctype/timezone/timezone.py index 2c77023b39..539ffa2547 100644 --- a/erpnext/crm/doctype/timezone/timezone.py +++ b/erpnext/crm/doctype/timezone/timezone.py @@ -10,8 +10,6 @@ from frappe.model.document import Document class Timezone(Document): def validate(self): if self.offset > 720 or self.offset < -720: - frappe.throw( - 'Timezone offsets must be between -720 and +720 minutes') + frappe.throw('Timezone offsets must be between -720 and +720 minutes') if frappe.db.exists({'doctype':'Timezone','offset':self.offset}): - frappe.throw( - 'Timezone offsets need to be unique') \ No newline at end of file + frappe.throw('Timezone offsets need to be unique') \ No newline at end of file diff --git a/erpnext/www/book-appointment/index.js b/erpnext/www/book-appointment/index.js index 5302d1b626..8fc5e31708 100644 --- a/erpnext/www/book-appointment/index.js +++ b/erpnext/www/book-appointment/index.js @@ -13,6 +13,7 @@ async function initialise_select_date() { } async function get_global_variables() { + // Using await window.appointment_settings = (await frappe.call({ method: 'erpnext.www.book-appointment.index.get_appointment_settings' })).message @@ -29,9 +30,9 @@ async function get_global_variables() { function setup_timezone_selector() { let timezones_element = document.getElementById('appointment-timezone'); - var offset = new Date().getTimezoneOffset(); + let offset = new Date().getTimezoneOffset(); window.timezones.forEach(timezone => { - var opt = document.createElement('option'); + let opt = document.createElement('option'); opt.value = timezone.offset; opt.innerHTML = timezone.timezone_name; opt.defaultSelected = (offset == timezone.offset) @@ -44,16 +45,16 @@ function setup_date_picker() { let today = new Date(); date_picker.min = today.toISOString().substr(0, 10); today.setDate(today.getDate() + window.appointment_settings.advance_booking_days); - date_picker.max = today.toISOString().substr(0,10); + date_picker.max = today.toISOString().substr(0, 10); } -function hide_next_button(){ +function hide_next_button() { let next_button = document.getElementById('next-button'); next_button.disabled = true; - next_button.onclick = ()=>{frappe.msgprint("Please select a date and time")}; + next_button.onclick = () => frappe.msgprint("Please select a date and time"); } -function show_next_button(){ +function show_next_button() { let next_button = document.getElementById('next-button'); next_button.disabled = false; next_button.onclick = setup_details_page; @@ -95,28 +96,36 @@ async function update_time_slots(selected_date, selected_timezone) { timeslot_container.appendChild(message_div); return } - window.slots.forEach((slot,index) => { - if(index%8==0){ + window.slots.forEach((slot, index) => { + // Add a break after each 8 elements + if (index % 8 == 0) { let break_element = document.createElement('div'); break_element.classList.add('w-100'); timeslot_container.appendChild(break_element); } - let start_time = new Date(slot.time) - var timeslot_div = document.createElement('div'); - timeslot_div.classList.add('time-slot'); - timeslot_div.classList.add('col-md'); - if (!slot.availability) { - timeslot_div.classList.add('unavailable') - } - timeslot_div.innerHTML = get_slot_layout(start_time); - timeslot_div.id = slot.time.substr(11, 20); - timeslot_div.addEventListener('click', select_time); + // Get and append timeslot div + let timeslot_div = get_timeslot_div_layout(slot) timeslot_container.appendChild(timeslot_div); }); set_default_timeslot(); } +function get_timeslot_div_layout(timeslot) { + let start_time = new Date(timeslot.time) + let timeslot_div = document.createElement('div'); + timeslot_div.classList.add('time-slot'); + timeslot_div.classList.add('col-md'); + if (!timeslot.availability) { + timeslot_div.classList.add('unavailable') + } + timeslot_div.innerHTML = get_slot_layout(start_time); + timeslot_div.id = timeslot.time.substr(11, 20); + timeslot_div.addEventListener('click', select_time); + return timeslot_div +} + function clear_time_slots() { + // Clear any existing divs in timeslot container let timeslot_container = document.getElementById('timeslot-container'); while (timeslot_container.firstChild) { timeslot_container.removeChild(timeslot_container.firstChild) @@ -126,23 +135,24 @@ function clear_time_slots() { function get_slot_layout(time) { time = new Date(time) let start_time_string = moment(time).format("LT"); - let end_time = moment(time).add(window.appointment_settings.appointment_duration,'minutes'); + let end_time = moment(time).add(window.appointment_settings.appointment_duration, 'minutes'); let end_time_string = end_time.format("LT"); return `${start_time_string}
to ${end_time_string}`; } function select_time() { - if (this.classList.contains("unavailable")) { + if (this.classList.contains('unavailable')) { return } - try { - selected_element = document.getElementsByClassName('selected')[0] - } catch (e) { - this.classList.add("selected") + let selected_element = document.getElementsByClassName('selected'); + if (!(selected_element.length > 0)){ + this.classList.add('selected') + return } + selected_element = selected_element[0] window.selected_time = this.id - selected_element.classList.remove("selected"); - this.classList.add("selected"); + selected_element.classList.remove('selected'); + this.classList.add('selected'); show_next_button(); } @@ -151,17 +161,17 @@ function set_default_timeslot() { for (let i = 0; i < timeslots.length; i++) { const timeslot = timeslots[i]; if (!timeslot.classList.contains('unavailable')) { - timeslot.classList.add("selected"); + timeslot.classList.add('selected'); break; } } } -function navigate_to_page(page_number){ +function navigate_to_page(page_number) { let page1 = document.getElementById('select-date-time'); let page2 = document.getElementById('enter-details'); - switch(page_number){ - case 1: + switch (page_number) { + case 1: page1.style.display = 'block'; page2.style.display = 'none'; break; @@ -170,21 +180,21 @@ function navigate_to_page(page_number){ page2.style.display = 'block'; break; default: - console.log("That's not a valid page") + break; } } -function setup_details_page(){ +function setup_details_page() { navigate_to_page(2) let date_container = document.getElementsByClassName('date-span')[0]; let time_container = document.getElementsByClassName('time-span')[0]; date_container.innerHTML = moment(window.selected_date).format("MMM Do YYYY"); - time_container.innerHTML = moment(window.selected_time,"HH:mm:ss").format("LT"); + time_container.innerHTML = moment(window.selected_time, "HH:mm:ss").format("LT"); } async function submit() { // form validation here - form_validation(); + get_form_data(); let appointment = (await frappe.call({ method: 'erpnext.www.book-appointment.index.create_appointment', args: { @@ -196,12 +206,10 @@ async function submit() { frappe.msgprint(__('Appointment Created Successfully')); let button = document.getElementById('submit-button'); button.disabled = true; - button.onclick = () => { console.log('This should never have happened') } -} + button.onclick = null +} -function form_validation(){ - var date = window.selected_date; - var time = window.selected_time; +function get_form_data() { contact = {}; contact.name = document.getElementById('customer_name').value; contact.number = document.getElementById('customer_number').value; @@ -209,5 +217,4 @@ function form_validation(){ contact.notes = document.getElementById('customer_notes').value; contact.email = document.getElementById('customer_email').value; window.contact = contact - console.log({ date, time, contact }); } diff --git a/erpnext/www/book-appointment/index.py b/erpnext/www/book-appointment/index.py index 530445ff91..6f6d4ac45c 100644 --- a/erpnext/www/book-appointment/index.py +++ b/erpnext/www/book-appointment/index.py @@ -2,6 +2,10 @@ import frappe import datetime import json + +WEEKDAYS = ["Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday", "Sunday"] + no_cache = 1 @@ -98,11 +102,9 @@ def create_appointment(date, time, contact): appointment.insert() def find_lead_by_email(email): - if frappe.db.exists({ - 'doctype':'Lead', - 'email_id':email - }): - return frappe.get_list('Lead',filters={'email_id':email})[0] + lead_list = frappe.get_list('Lead',filters={'email_id':email})[0] + if lead_list: + return lead_list frappe.throw('Email ID not associated with any Lead. Please make sure to use the email address you got this mail on') # Helper Functions @@ -156,8 +158,4 @@ def _convert_to_tz(datetime_object, timezone): datetime_object = datetime_object - offset offset = datetime.timedelta(minutes=-330) datetime_object = datetime_object + offset - return datetime_object - - -WEEKDAYS = ["Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday", "Sunday"] + return datetime_object \ No newline at end of file