Ejemplo n.º 1
0
def set_resolution_time(doc):
    start_date_time = get_datetime(
        doc.get("service_level_agreement_creation") or doc.creation)
    if doc.meta.has_field("resolution_time"):
        doc.resolution_time = time_diff_in_seconds(doc.resolution_date,
                                                   start_date_time)

    # total time taken by a user to close the issue apart from wait_time
    if not doc.meta.has_field("user_resolution_time"):
        return

    communications = frappe.get_all(
        "Communication",
        filters={
            "reference_doctype": doc.doctype,
            "reference_name": doc.name
        },
        fields=["sent_or_received", "name", "creation"],
        order_by="creation",
    )

    pending_time = []
    for i in range(len(communications)):
        if (communications[i].sent_or_received == "Received"
                and communications[i - 1].sent_or_received == "Sent"):
            wait_time = time_diff_in_seconds(communications[i].creation,
                                             communications[i - 1].creation)
            if wait_time > 0:
                pending_time.append(wait_time)

    total_pending_time = sum(pending_time)
    resolution_time_in_secs = time_diff_in_seconds(doc.resolution_date,
                                                   start_date_time)
    doc.user_resolution_time = resolution_time_in_secs - total_pending_time
Ejemplo n.º 2
0
def total_working_hours(doc, method):
    if doc.in_time and doc.out_time:
        in_time_f = datetime.strptime(doc.in_time, '%H:%M:%S')
        out_time_f = datetime.strptime(doc.out_time, '%H:%M:%S')
        frappe.errprint(type(doc.attendance_date))
        frappe.errprint(type(doc.out_date))
        actual_working_hours = frappe.db.get_value("Employee", doc.employee,
                                                   "working_hours")
        td = (out_time_f - in_time_f) - actual_working_hours
        if actual_working_hours > (out_time_f - in_time_f):
            td = (out_time_f - in_time_f)
        if doc.out_date > doc.attendance_date:
            next_day = timedelta(hours=24)
            worked_hrs = time_diff_in_seconds(out_time_f + next_day, in_time_f)
        else:
            worked_hrs = time_diff_in_seconds(out_time_f, in_time_f)
        total_working_hours = (worked_hrs / 3600.00)
        if td.seconds >= 2700:
            total_working_hours = math.ceil(total_working_hours)
        else:
            total_working_hours = math.floor(total_working_hours)
        att = frappe.get_doc("Attendance", doc.name)
        att.update({"total_working_hours": total_working_hours})
        att.db_update()
        frappe.db.commit()
Ejemplo n.º 3
0
def set_user_resolution_time(issue):
    # total time taken by a user to close the issue apart from wait_time
    communications = frappe.get_list(
        "Communication",
        filters={
            "reference_doctype": issue.doctype,
            "reference_name": issue.name
        },
        fields=["sent_or_received", "name", "creation"],
        order_by="creation")

    pending_time = []
    for i in range(len(communications)):
        if communications[i].sent_or_received == "Received" and communications[
                i - 1].sent_or_received == "Sent":
            wait_time = time_diff_in_seconds(communications[i].creation,
                                             communications[i - 1].creation)
            if wait_time > 0:
                pending_time.append(wait_time)

    total_pending_time = sum(pending_time)
    resolution_time_in_secs = time_diff_in_seconds(issue.resolution_date,
                                                   issue.creation)
    user_resolution_time = resolution_time_in_secs - total_pending_time
    issue.db_set("user_resolution_time", user_resolution_time)
Ejemplo n.º 4
0
	def set_response_and_resolution_time(self, priority=None, service_level_agreement=None):
		service_level_agreement = get_active_service_level_agreement_for(self)

		if not service_level_agreement:
			if frappe.db.get_value("Issue", self.name, "service_level_agreement"):
				frappe.throw(_("Couldn't Set Service Level Agreement {0}.").format(self.service_level_agreement))
			return

		if (service_level_agreement.customer and self.customer) and not (service_level_agreement.customer == self.customer):
			frappe.throw(_("This Service Level Agreement is specific to Customer {0}").format(service_level_agreement.customer))

		self.service_level_agreement = service_level_agreement.name
		if not self.priority:
			self.priority = service_level_agreement.default_priority

		priority = get_priority(self)

		if not self.creation:
			self.creation = now_datetime()
			self.service_level_agreement_creation = now_datetime()

		start_date_time = get_datetime(self.service_level_agreement_creation)
		self.response_by = get_expected_time_for(parameter="response", service_level=priority, start_date_time=start_date_time)
		self.resolution_by = get_expected_time_for(parameter="resolution", service_level=priority, start_date_time=start_date_time)

		self.response_by_variance = round(time_diff_in_seconds(self.response_by, now_datetime()))
		self.resolution_by_variance = round(time_diff_in_seconds(self.resolution_by, now_datetime()))
def execute():
	att = frappe.db.sql("""SELECT at.name, at.att_date, at.employee, at.employee_name, at.overtime,
		at.shift
		FROM `tabAttendance` at, `tabShift Type` sh
		WHERE at.docstatus = 1 AND sh.in_out_required = 1 AND at.shift = sh.name
		ORDER BY at.name""", as_list=1)
				
	for i in att:
		att = frappe.get_doc("Attendance", i[0])
		shft = frappe.get_doc("Shift Type", i[5])
		pu_data = []
		overtime = 0
		tt_in = 0
		tt_out = 0
		shft_hrs = shft.hours_required_per_day.seconds
		shft_marg = shft.time_margin.seconds
		shft_rounding = shft.time_rounding.seconds
		
		for d in att.attendance_time:
			pu_data.append([d.idx, d.time_type, d.date_time])
		
		#only calculate the ot if there are any IN and OUT entries
		for j in range(len(pu_data)-1):
			if pu_data[j][1] == 'In Time':
				tt_in +=  time_diff_in_seconds(pu_data[j+1][2], pu_data[j][2])
			else:
				tt_out += time_diff_in_seconds(pu_data[j+1][2], pu_data[j][2])
					
		overtime = ((tt_in - shft_hrs + shft_marg)- \
			((tt_in + shft_marg - shft_hrs)%shft_rounding))/3600
		
		frappe.db.set_value("Attendance", i[0], 'overtime', overtime)
		
		print ("Attendance Updated " + i[0] + " for date:" + i[1] + " employee: " + i[3] + " New OT=" + overtime)
Ejemplo n.º 6
0
def set_service_level_agreement_variance(issue=None):
	current_time = frappe.flags.current_time or now_datetime()

	filters = {"status": "Open", "agreement_status": "Ongoing"}
	if issue:
		filters = {"name": issue}

	for issue in frappe.get_list("Issue", filters=filters):
		doc = frappe.get_doc("Issue", issue.name)

		if not doc.first_responded_on:  # first_responded_on set when first reply is sent to customer
			variance = round(time_diff_in_seconds(doc.response_by, current_time), 2)
			frappe.db.set_value(
				dt="Issue", dn=doc.name, field="response_by_variance", val=variance, update_modified=False
			)
			if variance < 0:
				frappe.db.set_value(
					dt="Issue", dn=doc.name, field="agreement_status", val="Failed", update_modified=False
				)

		if not doc.resolution_date:  # resolution_date set when issue has been closed
			variance = round(time_diff_in_seconds(doc.resolution_by, current_time), 2)
			frappe.db.set_value(
				dt="Issue", dn=doc.name, field="resolution_by_variance", val=variance, update_modified=False
			)
			if variance < 0:
				frappe.db.set_value(
					dt="Issue", dn=doc.name, field="agreement_status", val="Failed", update_modified=False
				)
Ejemplo n.º 7
0
	def update_agreement_status_on_custom_status(self):
		"""
			Update Agreement Fulfilled status using Custom Scripts for Custom Issue Status
		"""
		if not self.first_responded_on: # first_responded_on set when first reply is sent to customer
			self.response_by_variance = round(time_diff_in_seconds(self.response_by, now_datetime()), 2)

		if not self.resolution_date: # resolution_date set when issue has been closed
			self.resolution_by_variance = round(time_diff_in_seconds(self.resolution_by, now_datetime()), 2)

		self.agreement_status = "Fulfilled" if self.response_by_variance > 0 and self.resolution_by_variance > 0 else "Failed"
Ejemplo n.º 8
0
	def handle_hold_time(self, status):
		if self.service_level_agreement:
			# set response and resolution variance as None as the issue is on Hold
			pause_sla_on = frappe.db.get_all(
				"Pause SLA On Status", fields=["status"], filters={"parent": self.service_level_agreement}
			)
			hold_statuses = [entry.status for entry in pause_sla_on]
			update_values = {}

			if hold_statuses:
				if self.status in hold_statuses and status not in hold_statuses:
					update_values["on_hold_since"] = frappe.flags.current_time or now_datetime()
					if not self.first_responded_on:
						update_values["response_by"] = None
						update_values["response_by_variance"] = 0
					update_values["resolution_by"] = None
					update_values["resolution_by_variance"] = 0

				# calculate hold time when status is changed from any hold status to any non-hold status
				if self.status not in hold_statuses and status in hold_statuses:
					hold_time = self.total_hold_time if self.total_hold_time else 0
					now_time = frappe.flags.current_time or now_datetime()
					last_hold_time = 0
					if self.on_hold_since:
						# last_hold_time will be added to the sla variables
						last_hold_time = time_diff_in_seconds(now_time, self.on_hold_since)
						update_values["total_hold_time"] = hold_time + last_hold_time

					# re-calculate SLA variables after issue changes from any hold status to any non-hold status
					# add hold time to SLA variables
					start_date_time = get_datetime(self.service_level_agreement_creation)
					priority = get_priority(self)
					now_time = frappe.flags.current_time or now_datetime()

					if not self.first_responded_on:
						response_by = get_expected_time_for(
							parameter="response", service_level=priority, start_date_time=start_date_time
						)
						response_by = add_to_date(response_by, seconds=round(last_hold_time))
						response_by_variance = round(time_diff_in_seconds(response_by, now_time))
						update_values["response_by"] = response_by
						update_values["response_by_variance"] = response_by_variance + last_hold_time

					resolution_by = get_expected_time_for(
						parameter="resolution", service_level=priority, start_date_time=start_date_time
					)
					resolution_by = add_to_date(resolution_by, seconds=round(last_hold_time))
					resolution_by_variance = round(time_diff_in_seconds(resolution_by, now_time))
					update_values["resolution_by"] = resolution_by
					update_values["resolution_by_variance"] = resolution_by_variance + last_hold_time
					update_values["on_hold_since"] = None

				self.db_set(update_values)
Ejemplo n.º 9
0
def update_first_response_time(parent, communication):
	if parent.meta.has_field("first_response_time") and not parent.get("first_response_time"):
		if is_system_user(communication.sender):
			first_responded_on = communication.creation
			if parent.meta.has_field("first_responded_on") and communication.sent_or_received == "Sent":
				parent.db_set("first_responded_on", first_responded_on)
			parent.db_set("first_response_time", round(time_diff_in_seconds(first_responded_on, parent.creation), 2))
Ejemplo n.º 10
0
def set_avg_response_time(parent, communication):
    if parent.meta.has_field(
            "avg_response_time") and communication.sent_or_received == "Sent":
        # avg response time for all the responses
        communications = frappe.get_list(
            "Communication",
            filters={
                "reference_doctype": parent.doctype,
                "reference_name": parent.name
            },
            fields=["sent_or_received", "name", "creation"],
            order_by="creation")

        if len(communications):
            response_times = []
            for i in range(len(communications)):
                if communications[
                        i].sent_or_received == "Sent" and communications[
                            i - 1].sent_or_received == "Received":
                    response_time = round(
                        time_diff_in_seconds(communications[i].creation,
                                             communications[i - 1].creation),
                        2)
                    if response_time > 0:
                        response_times.append(response_time)
            if response_times:
                avg_response_time = sum(response_times) / len(response_times)
                parent.db_set("avg_response_time", avg_response_time)
Ejemplo n.º 11
0
    def get_role_permission(self, username):
        from cloud.cloud.doctype.cloud_company_group.cloud_company_group import list_users

        if not self.owner_id:
            return None
        if self.owner_type == 'User':
            if self.owner_id == username:
                return 'Admin'
        else:
            for user in list_users(self.owner_id):
                if user.name == username:
                    return user.role

        share_role = None
        for d in frappe.db.get_values("IOT ShareGroupDevice", {
                "device": self.name,
                "parenttype": 'IOT Share Group'
        }, "parent"):
            if frappe.get_value("IOT ShareGroupUser", {
                    "parent": d[0],
                    "user": username
            }, "parent") == d[0]:
                if share_role != 'Admin':
                    share_role = frappe.get_value("IOT Share Group", d[0],
                                                  'role')

        for d in frappe.db.get_values("IOT Device Share", {
                "device": self.name,
                "share_to": username
        }, "name"):
            end_time = frappe.get_value("IOT Device Share", d[0], "end_time")
            if time_diff_in_seconds(end_time, get_datetime()) > 0:
                share_role = 'Admin'

        return share_role
Ejemplo n.º 12
0
def get_expected_time_for(parameter, service_level, start_date_time):
    current_date_time = start_date_time
    expected_time = current_date_time
    start_time = None
    end_time = None

    if parameter == "response":
        allotted_seconds = service_level.get("response_time")
    elif parameter == "resolution":
        allotted_seconds = service_level.get("resolution_time")
    else:
        frappe.throw(_("{0} parameter is invalid").format(parameter))

    expected_time_is_set = 0

    support_days = {}
    for service in service_level.get("support_and_resolution"):
        support_days[service.workday] = frappe._dict({
            "start_time":
            service.start_time,
            "end_time":
            service.end_time,
        })

    holidays = get_holidays(service_level.get("holiday_list"))
    weekdays = get_weekdays()

    while not expected_time_is_set:
        current_weekday = weekdays[current_date_time.weekday()]

        if not is_holiday(current_date_time,
                          holidays) and current_weekday in support_days:
            start_time = current_date_time - datetime(current_date_time.year, current_date_time.month, current_date_time.day) \
             if getdate(current_date_time) == getdate(start_date_time) and get_time_in_timedelta(current_date_time.time()) > support_days[current_weekday].start_time \
             else support_days[current_weekday].start_time
            end_time = support_days[current_weekday].end_time
            time_left_today = time_diff_in_seconds(end_time, start_time)

            # no time left for support today
            if time_left_today <= 0: pass
            elif allotted_seconds:
                if time_left_today >= allotted_seconds:
                    expected_time = datetime.combine(
                        getdate(current_date_time), get_time(start_time))
                    expected_time = add_to_date(expected_time,
                                                seconds=allotted_seconds)
                    expected_time_is_set = 1
                else:
                    allotted_seconds = allotted_seconds - time_left_today

        if not expected_time_is_set:
            current_date_time = add_to_date(current_date_time, days=1)

    if end_time and allotted_seconds >= 86400:
        current_date_time = datetime.combine(getdate(current_date_time),
                                             get_time(end_time))
    else:
        current_date_time = expected_time

    return current_date_time
Ejemplo n.º 13
0
def should_remove_barcode_image(barcode):
	'''Check if it's time to delete barcode image from server. '''
	if isinstance(barcode, string_types):
		barcode = frappe.get_doc('File', barcode)
	lifespan = frappe.db.get_value('System Settings', 'System Settings', 'lifespan_qrcode_image')
	if time_diff_in_seconds(get_datetime(), barcode.creation) > int(lifespan):
		return True
	return False
Ejemplo n.º 14
0
def should_remove_barcode_image(barcode):
	'''Check if it's time to delete barcode image from server. '''
	if isinstance(barcode, string_types):
		barcode = frappe.get_doc('File', barcode)
	lifespan = frappe.db.get_value('System Settings', 'System Settings', 'lifespan_qrcode_image')
	if time_diff_in_seconds(get_datetime(), barcode.creation) > int(lifespan):
		return True
	return False
Ejemplo n.º 15
0
def update_mins_to_first_communication(parent, communication):
	if parent.meta.has_field('mins_to_first_response') and not parent.get('mins_to_first_response'):
		if frappe.db.get_all('User', filters={'email': communication.sender,
			'user_type': 'System User', 'enabled': 1}, limit=1):
			first_responded_on = communication.creation
			if parent.meta.has_field('first_responded_on'):
				parent.db_set('first_responded_on', first_responded_on)
			parent.db_set('mins_to_first_response', round(time_diff_in_seconds(first_responded_on, parent.creation) / 60), 2)
Ejemplo n.º 16
0
def update_mins_to_first_communication(parent, communication):
	if parent.meta.has_field('mins_to_first_response') and not parent.get('mins_to_first_response'):
		if frappe.db.get_all('User', filters={'email': communication.sender,
			'user_type': 'System User', 'enabled': 1}, limit=1):
			first_responded_on = communication.creation
			if parent.meta.has_field('first_responded_on'):
				parent.db_set('first_responded_on', first_responded_on)
			parent.db_set('mins_to_first_response', round(time_diff_in_seconds(first_responded_on, parent.creation) / 60), 2)
Ejemplo n.º 17
0
	def calculate_total_hours(self):
		
		if self.arrival_time == "#--:--" or self.arrival_time == "00:00" or self.arrival_time == "0:00:00":
			self.arrival_time = "00:00:00"
			
		if self.departure_time == "#--:--" or self.departure_time == "00:00" or self.departure_time == "0:00:00":
			self.departure_time = "00:00:00"
		
		
		try:
			totalworkhours = flt(time_diff_in_seconds(self.departure_time,self.arrival_time))/3600
		except:
			try:
				time = time_diff(self.departure_time,self.arrival_time)
				totalworkhours = flt(time.hour) + flt(time.minute)/60 + flt(time.second)/3600
			except:
				frappe.throw(_("Possible error in arrival time {0} or departure time {1} for employee {2}").format(self.arrival_time,self.departure_time,self.employee))

		
		
		self.working_time = totalworkhours
		weekday = get_datetime(self.att_date).weekday()
		
		working_hours = frappe.db.sql("""select working_hours from `tabWorking Hours`
				where %s between from_date and to_date and docstatus < 2""", (self.att_date))

		if working_hours:
			self.normal_time = flt(working_hours[0][0])
		else:
			self.normal_time = flt(frappe.db.get_single_value("Regulations", "working_hours"))
			
		self.overtime = 0
		self.overtime_fridays = 0
		self.overtime_holidays = 0
		self.status = 'Present'
		
		if len(self.get_holidays_for_employee(self.att_date,self.att_date)):
			self.normal_time = 0
			self.overtime_holidays = flt(totalworkhours) - flt(self.normal_time)
		elif weekday == 4:
			self.normal_time = 0
			self.overtime_fridays = flt(totalworkhours) - flt(self.normal_time)
		else:		
			if totalworkhours > self.normal_time:
				self.overtime = flt(totalworkhours) - flt(self.normal_time)
			elif totalworkhours > 2:
				self.normal_time = totalworkhours
			elif totalworkhours > 0:
				frappe.throw(_("Work Hours under 2. Please check the time for employee {0}, date {1}").format(self.employee,self.att_date))
			elif totalworkhours < 0:
				frappe.throw(_("Work Hours negative. Please check the time for employee {0}, date {1}").format(self.employee,self.att_date))
			else:
				if self.arrival_time == "00:00:00" and self.departure_time == "00:00:00":
					self.normal_time = 0
					self.status = 'Absent'
				else:
					frappe.throw(_("Please check the time for employee {0}, date {1}").format(self.employee,self.att_date))
Ejemplo n.º 18
0
def should_remove_barcode_image(barcode):
    """Check if it's time to delete barcode image from server."""
    if isinstance(barcode, string_types):
        barcode = frappe.get_doc("File", barcode)
    lifespan = (frappe.db.get_value("System Settings", "System Settings",
                                    "lifespan_qrcode_image") or 240)
    if time_diff_in_seconds(get_datetime(), barcode.creation) > int(lifespan):
        return True
    return False
Ejemplo n.º 19
0
    def calculate_hold_hours():
        # In case issue was closed and after few days it has been opened
        # The hold time should be calculated from resolution_date

        on_hold_since = doc.resolution_date or doc.on_hold_since
        if on_hold_since:
            current_hold_hours = time_diff_in_seconds(now_time, on_hold_since)
            doc.total_hold_time = (doc.total_hold_time
                                   or 0) + current_hold_hours
        doc.on_hold_since = None
Ejemplo n.º 20
0
def is_within_operating_hours(workstation, operation, from_datetime, to_datetime):
	operation_length = time_diff_in_seconds(to_datetime, from_datetime)
	workstation = frappe.get_doc("Workstation", workstation)

	for working_hour in workstation.working_hours:
		slot_length = (get_datetime(working_hour.end_time) - get_datetime(working_hour.start_time)).total_seconds()
		if slot_length >= operation_length:
			return

	frappe.throw(_("Operation {0} longer than any available working hours in workstation {1}, break down the operation into multiple operations").format(operation, workstation.name), NotInWorkingHoursError)
Ejemplo n.º 21
0
def calculate_hours(in_date, out_date, in_time, out_time, employee):
    working_hrs = frappe.db.get_value("Employee", employee, "working_hours")
    if working_hrs:
        shift_hrs = working_hrs.seconds
        in_time_f = datetime.strptime(in_time, '%H:%M:%S')
        out_time_f = datetime.strptime(out_time, '%H:%M:%S')

        if in_date < out_date:
            next_day = timedelta(hours=24)
            worked_hrs = time_diff_in_seconds(out_time_f + next_day, in_time_f)
        else:
            worked_hrs = time_diff_in_seconds(out_time_f, in_time_f)
        overtime = cint(worked_hrs - shift_hrs)
        # overtime_f = datetime.strptime(
        #     overtime, '%H:%M:%S')
        min_hr = timedelta(seconds=3600)
        ot_f = timedelta(seconds=overtime)
        if ot_f > min_hr:
            return ot_f.seconds
Ejemplo n.º 22
0
def list():
	try:
		valid_auth_code()
		# frappe.logger(__name__).debug("List Devices for user {0}").format(user)
		# Get Enteprise Devices
		ent_devices = []
		user = frappe.session.user
		groups = _list_user_groups(user)
		companies = list_user_companies(user)
		for g in groups:
			dev_list = [d[0] for d in frappe.db.get_values("IOT Device", {
				"owner_id": g.name,
				"owner_type": "Cloud Company Group"
			}, "name")]

			ent_devices.append({"group": g.name, "devices": dev_list, "role": g.role})

		# Get Shared Devices
		shd_devices = []
		for shared_group in [ d[0] for d in frappe.db.get_values("IOT ShareGroupUser", {"user": user}, "parent")]:
			# Make sure we will not having shared device from your company
			if frappe.get_value("IOT Share Group", shared_group, "company") in companies:
				continue
			role = frappe.get_value("IOT Share Group", shared_group, "role")

			dev_list = []
			for dev in [d[0] for d in frappe.db.get_values("IOT ShareGroupDevice", {"parent": shared_group}, "device")]:
				dev_list.append(dev)
			shd_devices.append({"group": shared_group, "devices": dev_list, "role": role})

		device_share_list = []
		for d in frappe.db.get_values("IOT Device Share", {"share_to": user}, "name"):
			end_time = frappe.get_value("IOT Device Share", d[0], "end_time")
			if time_diff_in_seconds(end_time, get_datetime()) > 0:
				device_share_list.append(frappe.get_value("IOT Device Share", d[0], "device"))

		shd_devices.append({"group": "IOT Device Share", "devices": device_share_list, "role": 'Admin'})

		# Get Private Devices
		pri_devices = [d[0] for d in frappe.db.get_values("IOT Device", {"owner_id": user, "owner_type": "User"}, "name")]

		devices = {
			"company_devices": ent_devices,
			"private_devices": pri_devices,
			"shared_devices": shd_devices,
		}
		frappe.response.update({
			"ok": True,
			"data": devices
		})
	except Exception as ex:
		frappe.response.update({
			"ok": False,
			"error": str(ex)
		})
Ejemplo n.º 23
0
def valide_date(data):
	obj = json.loads(data)
	from frappe.utils import time_diff_in_seconds
	
	from_date_time = datetime.datetime.strptime(obj.get('from_date_time'), '%d/%m/%Y %H:%M').strftime('%Y-%m-%d %H:%M:%S')
	curr_date_time = datetime.datetime.strptime(obj.get('curr_date_time'), '%Y-%m-%d %H:%M:%S').strftime('%Y-%m-%d %H:%M:%S')

	if time_diff_in_seconds(from_date_time, curr_date_time) < 0:
		return False
	
	return True
def validate_duration(doc):
	if not doc.duration or doc.duration <= 0:
		frappe.throw(_("Duration must be geater than zero"))
	else:
		# time diff in minutes = in seconds / 60
		total_time_diff = time_diff_in_seconds(doc.to_time, doc.from_time)/60
		if total_time_diff <= 0:
			frappe.throw(_("From Time should not be greater than or equal to To Time"))
		if total_time_diff < doc.duration:
			frappe.throw(_("Duration between from time and to time must be greater than or equal to duration given"))
		elif total_time_diff % doc.duration != 0:
			frappe.throw(_("Duration between from time and to time must be multiple of duration given"))
Ejemplo n.º 25
0
def validate_duration(doc):
	if doc.duration <= 0:
		frappe.throw(_("Duration must be geater than zero"))
	else:
		# time diff in minutes = in seconds / 60
		total_time_diff = time_diff_in_seconds(doc.to_time, doc.from_time)/60
		if total_time_diff <= 0:
			frappe.throw(_("From Time should not be greater than or equal to To Time"))
		if total_time_diff < doc.duration:
			frappe.throw(_("Duration between from time and to time must be greater than or equal to duration given"))
		elif total_time_diff % doc.duration != 0:
			frappe.throw(_("Duration between from time and to time must be multiple of duration given"))
Ejemplo n.º 26
0
def calculate_overtime(doc,method):
	doc.overtime = 0
	tt_in = 0
	tt_out = 0
	
	shft_intime, shft_lunchout, shft_lunchin, shft_hrs, \
		shft_rounding, shft_marg = validate_time_with_shift(doc,method)
	
	pu_data = check_punch_data(doc, method)
	
	#only calculate the ot if there are any IN and OUT entries
	#if doc.attendance_time:
	for i in range(len(doc.attendance_time)-1):
		pass
	for i in range(len(pu_data)-1):
		if pu_data[i][1] == 'In Time':
			tt_in +=  time_diff_in_seconds(pu_data[i+1][2], pu_data[i][2])
		else:
			tt_out += time_diff_in_seconds(pu_data[i+1][2], pu_data[i][2])
				
	doc.overtime = ((tt_in - shft_hrs + shft_marg)- \
		((tt_in + shft_marg - shft_hrs)%shft_rounding))/3600
Ejemplo n.º 27
0
def bulk_total_working_hours():
    # days = ["2018-07-01", "2018-07-02", "2018-07-03", "2018-07-04", "2018-07-06",
    #         "2018-07-07", "2018-07-08", "2018-07-09", "2018-07-10", "2018-07-11", "2018-07-12", "2018-07-13",
    #         "2018-07-14", "2018-07-15", "2018-07-16", "2018-07-17", "2018-07-18", "2018-07-19", "2018-07-20"]
    days = ["2018-07-22"]
    # # day = datetime.strptime('25042018', "%d%m%Y").date()
    for day in days:
        attendance = frappe.get_all("Attendance",
                                    fields=[
                                        'name', 'employee', 'attendance_date',
                                        'out_date', 'in_time', 'out_time',
                                        'total_working_hours'
                                    ],
                                    filters={'attendance_date': day})
        for doc in attendance:
            if doc.attendance_date and doc.out_date and doc.in_time and doc.out_time:
                in_time_f = datetime.strptime(doc.in_time, '%H:%M:%S')
                out_time_f = datetime.strptime(doc.out_time, '%H:%M:%S')
                maxhr = timedelta(seconds=2400)
                actual_working_hours = frappe.db.get_value(
                    "Employee", doc.employee, "working_hours")
                td = (out_time_f - in_time_f) - actual_working_hours
                if actual_working_hours > (out_time_f - in_time_f):
                    td = (out_time_f - in_time_f)
                if doc.attendance_date < doc.out_date:
                    next_day = timedelta(hours=24)
                    worked_hrs = time_diff_in_seconds(out_time_f + next_day,
                                                      in_time_f)
                else:
                    worked_hrs = time_diff_in_seconds(out_time_f, in_time_f)
                total_working_hours = (worked_hrs / 3600.00)
                if td.seconds >= 2700:
                    total_working_hours = math.ceil(total_working_hours)
                else:
                    total_working_hours = math.floor(total_working_hours)
                att = frappe.get_doc("Attendance", doc.name)
                att.update({"total_working_hours": total_working_hours})
                att.db_update()
                frappe.db.commit()
Ejemplo n.º 28
0
def calculate_overtime(doc, method):
    doc.overtime = 0
    tt_in = 0
    tt_out = 0

    shft_intime, shft_lunchout, shft_lunchin, shft_hrs, \
     shft_rounding, shft_marg = validate_time_with_shift(doc,method)

    pu_data = check_punch_data(doc, method)

    #only calculate the ot if there are any IN and OUT entries
    #if doc.attendance_time:
    for i in range(len(doc.attendance_time) - 1):
        pass
    for i in range(len(pu_data) - 1):
        if pu_data[i][1] == 'In Time':
            tt_in += time_diff_in_seconds(pu_data[i + 1][2], pu_data[i][2])
        else:
            tt_out += time_diff_in_seconds(pu_data[i + 1][2], pu_data[i][2])

    doc.overtime = ((tt_in - shft_hrs + shft_marg)- \
     ((tt_in + shft_marg - shft_hrs)%shft_rounding))/3600
Ejemplo n.º 29
0
def get_expected_time_for(parameter, service_level, start_date_time):
    current_date_time = start_date_time
    expected_time = current_date_time
    start_time = end_time = None
    expected_time_is_set = 0

    allotted_seconds = get_allotted_seconds(parameter, service_level)
    support_days = get_support_days(service_level)
    holidays = get_holidays(service_level.get("holiday_list"))
    weekdays = get_weekdays()

    while not expected_time_is_set:
        current_weekday = weekdays[current_date_time.weekday()]

        if not is_holiday(current_date_time,
                          holidays) and current_weekday in support_days:
            if (getdate(current_date_time) == getdate(start_date_time)
                    and get_time_in_timedelta(current_date_time.time()) >
                    support_days[current_weekday].start_time):
                start_time = current_date_time - datetime(
                    current_date_time.year, current_date_time.month,
                    current_date_time.day)
            else:
                start_time = support_days[current_weekday].start_time

            end_time = support_days[current_weekday].end_time
            time_left_today = time_diff_in_seconds(end_time, start_time)
            # no time left for support today
            if time_left_today <= 0:
                pass

            elif allotted_seconds:
                if time_left_today >= allotted_seconds:
                    expected_time = datetime.combine(
                        getdate(current_date_time), get_time(start_time))
                    expected_time = add_to_date(expected_time,
                                                seconds=allotted_seconds)
                    expected_time_is_set = 1
                else:
                    allotted_seconds = allotted_seconds - time_left_today

        if not expected_time_is_set:
            current_date_time = add_to_date(current_date_time, days=1)

    if end_time and allotted_seconds >= 86400:
        current_date_time = datetime.combine(getdate(current_date_time),
                                             get_time(end_time))
    else:
        current_date_time = expected_time

    return current_date_time
def execute():
    att = frappe.db.sql(
        """SELECT at.name, at.att_date, at.employee, at.employee_name, at.overtime,
		at.shift
		FROM `tabAttendance` at, `tabShift Type` sh
		WHERE at.docstatus = 1 AND sh.in_out_required = 1 AND at.shift = sh.name
		ORDER BY at.name""",
        as_list=1)

    for i in att:
        att = frappe.get_doc("Attendance", i[0])
        shft = frappe.get_doc("Shift Type", i[5])
        pu_data = []
        overtime = 0
        tt_in = 0
        tt_out = 0
        shft_hrs = shft.hours_required_per_day.seconds
        shft_marg = shft.time_margin.seconds
        shft_rounding = shft.time_rounding.seconds

        for d in att.attendance_time:
            pu_data.append([d.idx, d.time_type, d.date_time])

        #only calculate the ot if there are any IN and OUT entries
        for j in range(len(pu_data) - 1):
            if pu_data[j][1] == 'In Time':
                tt_in += time_diff_in_seconds(pu_data[j + 1][2], pu_data[j][2])
            else:
                tt_out += time_diff_in_seconds(pu_data[j + 1][2],
                                               pu_data[j][2])

        overtime = ((tt_in - shft_hrs + shft_marg)- \
         ((tt_in + shft_marg - shft_hrs)%shft_rounding))/3600

        frappe.db.set_value("Attendance", i[0], 'overtime', overtime)

        print("Attendance Updated " + i[0] + " for date:" + i[1] +
              " employee: " + i[3] + " New OT=" + overtime)
Ejemplo n.º 31
0
def valide_date(arg, data):
	arg = json.loads(arg)
	obj = json.loads(data)
	from frappe.utils import time_diff_in_seconds
	
	try:
		from_date_time = datetime.datetime.strptime(obj.get('date'), '%d/%m/%Y %H:%M').strftime('%Y-%m-%d %H:%M:%S')
	except:
		from_date_time = datetime.datetime.strptime(obj.get('date'), '%d/%m/%Y').strftime('%Y-%m-%d %H:%M:%S')

	curr_date_time = datetime.datetime.strptime(arg.get('curr_date_time'), '%Y-%m-%d %H:%M:%S').strftime('%Y-%m-%d %H:%M:%S')
	if time_diff_in_seconds(from_date_time, curr_date_time) > 0:
		return False
	return True
Ejemplo n.º 32
0
def is_within_operating_hours(workstation, operation, from_datetime,
                              to_datetime):
    operation_length = time_diff_in_seconds(to_datetime, from_datetime)
    workstation = frappe.get_doc("Workstation", workstation)

    for working_hour in workstation.working_hours:
        slot_length = (parse(working_hour.end_time) -
                       parse(working_hour.start_time)).total_seconds()
        if slot_length >= operation_length:
            return

    frappe.throw(
        _("Operation {0} longer than any available working hours in workstation {1}, break down the operation into multiple operations"
          ).format(operation, workstation.name), NotInWorkingHoursError)
Ejemplo n.º 33
0
def valide_date(data):
    obj = json.loads(data)
    from frappe.utils import time_diff_in_seconds

    from_date_time = datetime.datetime.strptime(
        obj.get('from_date_time'),
        '%d/%m/%Y %H:%M').strftime('%Y-%m-%d %H:%M:%S')
    curr_date_time = datetime.datetime.strptime(
        obj.get('curr_date_time'),
        '%Y-%m-%d %H:%M:%S').strftime('%Y-%m-%d %H:%M:%S')

    if time_diff_in_seconds(from_date_time, curr_date_time) < 0:
        return False

    return True
Ejemplo n.º 34
0
def check_date_time_diff(date_time, type_of_check, name_of_field, days_diff=0, hours_diff=0):
	d = get_datetime(date_time)
	d1 = now_datetime()
	d0 = add_days(d1.date(), days_diff)
	if type_of_check == 'date':
		if d.date() >= d0 and d.date() <= d1.date():
			pass
		else:
			frappe.throw(("{} Date should be between {} and {}").\
				format(name_of_field, str(d0), str(d1.date())))
	else:
		if d.date() < d1.date():
			frappe.throw("{} Date cannot be less than Today's Date".format(name_of_field))
		if d.date() == d1.date():
			if time_diff_in_seconds(d, d1) < (3600*hours_diff):
				frappe.throw("{} Time has to be {} hours after the current time".\
					format(name_of_field, hours_diff))
Ejemplo n.º 35
0
    def add_time_log(self, args):
        last_row = []
        employees = args.employees
        if isinstance(employees, str):
            employees = json.loads(employees)

        if self.time_logs and len(self.time_logs) > 0:
            last_row = self.time_logs[-1]

        self.reset_timer_value(args)
        if last_row and args.get("complete_time"):
            for row in self.time_logs:
                if not row.to_time:
                    row.update({
                        "to_time":
                        get_datetime(args.get("complete_time")),
                        "operation":
                        args.get("sub_operation"),
                        "completed_qty":
                        args.get("completed_qty") or 0.0,
                    })
        elif args.get("start_time"):
            new_args = frappe._dict({
                "from_time":
                get_datetime(args.get("start_time")),
                "operation":
                args.get("sub_operation"),
                "completed_qty":
                0.0,
            })

            if employees:
                for name in employees:
                    new_args.employee = name.get("employee")
                    self.add_start_time_log(new_args)
            else:
                self.add_start_time_log(new_args)

        if not self.employee and employees:
            self.set_employees(employees)

        if self.status == "On Hold":
            self.current_time = time_diff_in_seconds(last_row.to_time,
                                                     last_row.from_time)

        self.save()
Ejemplo n.º 36
0
def get_new_messages():
	last_update = frappe.cache().hget("notifications_last_update", frappe.session.user)
	now_timestamp = now()
	frappe.cache().hset("notifications_last_update", frappe.session.user, now_timestamp)

	if not last_update:
		return []

	if last_update and time_diff_in_seconds(now_timestamp, last_update) > 1800:
		# no update for 30 mins, consider only the last 30 mins
		last_update = (now_datetime() - relativedelta(seconds=1800)).strftime(DATETIME_FORMAT)

	return frappe.db.sql("""select comment_by_fullname, comment
		from tabComment
			where comment_doctype='Message'
			and comment_docname = %s
			and ifnull(creation, "2000-01-01") > %s
			order by creation desc""", (frappe.session.user, last_update), as_dict=1)
Ejemplo n.º 37
0
def get_new_messages():
	last_update = frappe.cache().hget("notifications_last_update", frappe.session.user)
	now_timestamp = now()
	frappe.cache().hset("notifications_last_update", frappe.session.user, now_timestamp)

	if not last_update:
		return []

	if last_update and time_diff_in_seconds(now_timestamp, last_update) > 1800:
		# no update for 30 mins, consider only the last 30 mins
		last_update = (now_datetime() - relativedelta(seconds=1800)).strftime(DATETIME_FORMAT)

	return frappe.db.sql("""select comment_by_fullname, comment
		from tabComment
			where comment_doctype='Message'
			and comment_docname = %s
			and ifnull(creation, "2000-01-01") > %s
			order by creation desc""", (frappe.session.user, last_update), as_dict=1)
Ejemplo n.º 38
0
def valide_date(arg, data):
    arg = json.loads(arg)
    obj = json.loads(data)
    from frappe.utils import time_diff_in_seconds

    try:
        from_date_time = datetime.datetime.strptime(
            obj.get('date'), '%d/%m/%Y %H:%M').strftime('%Y-%m-%d %H:%M:%S')
    except:
        from_date_time = datetime.datetime.strptime(
            obj.get('date'), '%d/%m/%Y').strftime('%Y-%m-%d %H:%M:%S')

    curr_date_time = datetime.datetime.strptime(
        arg.get('curr_date_time'),
        '%Y-%m-%d %H:%M:%S').strftime('%Y-%m-%d %H:%M:%S')
    if time_diff_in_seconds(from_date_time, curr_date_time) > 0:
        return False
    return True
Ejemplo n.º 39
0
def has_permission_inter(user,
                         doc_name,
                         company=None,
                         owner_type=None,
                         owner_id=None):
    company = company or frappe.get_value('IOT Device', doc_name, 'company')
    if frappe.get_value('Cloud Company', company, 'admin') == user:
        return True

    owner_type = owner_type or frappe.get_value('IOT Device', doc_name,
                                                'owner_type')
    owner_id = owner_id or frappe.get_value('IOT Device', doc_name, 'owner_id')

    if owner_type == '' or owner_id is None:
        return False

    if owner_type == 'User' and owner_id == user:
        return True

    if owner_type == "Cloud Company Group":
        from cloud.cloud.doctype.cloud_company_group.cloud_company_group import list_users
        for d in list_users(owner_id):
            if d.name == user:
                return True

    for d in frappe.db.get_values("IOT ShareGroupDevice", {
            "device": doc_name,
            "parenttype": 'IOT Share Group'
    }, "parent"):
        if frappe.get_value("IOT ShareGroupUser", {
                "parent": d[0],
                "user": user
        }, "parent") == d[0]:
            return True

    for d in frappe.db.get_values("IOT Device Share", {
            "device": doc_name,
            "share_to": user
    }, "name"):
        end_time = frappe.get_value("IOT Device Share", d[0], "end_time")
        if time_diff_in_seconds(end_time, get_datetime()) > 0:
            return True

    return False
Ejemplo n.º 40
0
def log_metrics(action, start_time, end_time, ctx, args, **kwargs):
    doc = frappe.new_doc("Action Execution Log").update(kwargs).update({
        "action":
        action,
        "start_time":
        start_time,
        "end_time":
        end_time,
        "execution_time":
        time_diff_in_seconds(end_time, start_time),
        "context":
        frappe.as_json(ctx),
        "arguments":
        frappe.as_json(args),
        "stack":
        log_stack(start=1)
    })
    doc.insert()
    frappe.db.commit()
Ejemplo n.º 41
0
def get_new_messages():
	last_update = frappe.cache().hget("notifications_last_update", frappe.session.user)
	now_timestamp = now()
	frappe.cache().hset("notifications_last_update", frappe.session.user, now_timestamp)

	if not last_update:
		return []

	if last_update and time_diff_in_seconds(now_timestamp, last_update) > 1800:
		# no update for 30 mins, consider only the last 30 mins
		last_update = (now_datetime() - relativedelta(seconds=1800)).strftime(DATETIME_FORMAT)

	return frappe.db.sql("""select sender_full_name, content
		from `tabCommunication`
			where communication_type in ('Chat', 'Notification')
			and reference_doctype='user'
			and reference_name = %s
			and creation > %s
			order by creation desc""", (frappe.session.user, last_update), as_dict=1)
Ejemplo n.º 42
0
def get_new_messages():
	last_update = frappe.cache().hget("notifications_last_update", frappe.session.user)
	now_timestamp = now()
	frappe.cache().hset("notifications_last_update", frappe.session.user, now_timestamp)

	if not last_update:
		return []

	if last_update and time_diff_in_seconds(now_timestamp, last_update) > 1800:
		# no update for 30 mins, consider only the last 30 mins
		last_update = (now_datetime() - relativedelta(seconds=1800)).strftime(DATETIME_FORMAT)

	return frappe.db.sql("""select sender_full_name, content
		from `tabCommunication`
			where communication_type in ('Chat', 'Notification')
			and reference_doctype='user'
			and reference_name = %s
			and creation > %s
			order by creation desc""", (frappe.session.user, last_update), as_dict=1)
Ejemplo n.º 43
0
def check_punch_data(doc,method):
	
	shft_intime, shft_lunchout, shft_lunchin, shft_hrs, \
		shft_rounding, shft_marg = validate_time_with_shift(doc,method)
	pu_data = []
	
	for d in doc.attendance_time:
		if d.idx == 1 and d.time_type != 'In Time':
			frappe.throw(("First Punch Data should be In Time for {0}").format(doc.name))
		pu_data.append([d.idx, d.time_type, d.date_time])

	for i in range(len(pu_data)-1):
		#Checks if In and Out are alternating
		if pu_data[i][1] == pu_data[i+1][1]:
			frappe.throw(("{1} should not be Followed by {1} for {2} check row # {3} & {4}").\
				format(pu_data[i][1], pu_data[i][1], doc.name, pu_data[i][0], pu_data[i+1][0]))
		#Checks if Time Data is following the minimum time difference rule in shift
		if time_diff_in_seconds(pu_data[i+1][2], pu_data[i][2]) <= shft_marg:
			frappe.throw(("Difference between 2 punch data cannot be less than \
				{0} mins check row# {1} and {2} for {3}").\
				format(shft_marg/60, pu_data[i][0], pu_data[i+1][0], doc.name))

	return pu_data
Ejemplo n.º 44
0
    def calculate_total_hours(self):
        if self.to_time and self.from_time:
            from frappe.utils import time_diff_in_seconds

            self.hours = flt(time_diff_in_seconds(self.to_time, self.from_time)) / 3600
Ejemplo n.º 45
0
def get_availability_data(date, practitioner):
	"""
	Get availability data of 'practitioner' on 'date'
	:param date: Date to check in schedule
	:param practitioner: Name of the practitioner
	:return: dict containing a list of available slots, list of appointments and time of appointments
	"""

	date = getdate(date)
	weekday = date.strftime("%A")

	available_slots = []
	slot_details = []
	practitioner_schedule = None

	add_events = []
	remove_events = []

	employee = None

	practitioner_obj = frappe.get_doc("Healthcare Practitioner", practitioner)

	# Get practitioner employee relation
	if practitioner_obj.employee:
		employee = practitioner_obj.employee
	elif practitioner_obj.user_id:
		if frappe.db.exists({
			"doctype": "Employee",
			"user_id": practitioner_obj.user_id
			}):
			employee = frappe.get_doc("Employee", {"user_id": practitioner_obj.user_id}).name

	if employee:
		# Check if it is Holiday
		if is_holiday(employee, date):
			frappe.throw(_("{0} is a company holiday".format(date)))

		# Check if He/She on Leave
		leave_record = frappe.db.sql("""select half_day from `tabLeave Application`
			where employee = %s and %s between from_date and to_date
			and docstatus = 1""", (employee, date), as_dict=True)
		if leave_record:
			if leave_record[0].half_day:
				frappe.throw(_("{0} on Half day Leave on {1}").format(practitioner, date))
			else:
				frappe.throw(_("{0} on Leave on {1}").format(practitioner, date))

	# Remove events by repeat_on
	def remove_events_by_repeat_on(events_list):
		weekdays = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
		if events_list:
			i = 0
			for event in events_list:
				if event.repeat_this_event:
					if event.repeat_on == "Every Day":
						if event[weekdays[getdate(date).weekday()]]:
							add_events.append(event.copy())
						remove_events.append(event.copy())

					if event.repeat_on=="Every Week":
						if getdate(event.from_date).weekday() == getdate(date).weekday():
							add_events.append(event.copy())
						remove_events.append(event.copy())

					if event.repeat_on=="Every Month":
						if getdate(event.from_date).day == getdate(date).day:
							add_events.append(event.copy())
						remove_events.append(event.copy())

					if event.repeat_on=="Every Year":
						if getdate(event.from_date).strftime("%j") == getdate(date).strftime("%j"):
							add_events.append(event.copy())
						remove_events.append(event.copy())

	# Absent events
	absent_events = frappe.db.sql("""
		select
			name, event, from_time, to_time, from_date, to_date, duration, service_unit, service_unit, repeat_this_event, repeat_on, repeat_till,
			monday, tuesday, wednesday, thursday, friday, saturday, sunday
		from
			`tabPractitioner Event`
		where
			practitioner = %(practitioner)s and present != 1 and
			(
				(repeat_this_event = 1 and (from_date<=%(date)s and ifnull(repeat_till, "3000-01-01")>=%(date)s))
				or
				(repeat_this_event != 1 and (from_date<=%(date)s and to_date>=%(date)s))
			)
	""".format(),{"practitioner": practitioner, "date": getdate(date)}, as_dict=True)

	if absent_events:
		remove_events = []
		add_events = []
		remove_events_by_repeat_on(absent_events)
		for e in remove_events:
			absent_events.remove(e)
		absent_events = absent_events + add_events

	# get practitioners schedule
	enabled_schedule = False
	if practitioner_obj.practitioner_schedules:
		for schedule in practitioner_obj.practitioner_schedules:
			practitioner_schedule = None
			if schedule.schedule:
				if frappe.db.exists(
					"Practitioner Schedule",
					{
						"name": schedule.schedule,
						"disabled": ['!=', 1]
					}
				):
					practitioner_schedule = frappe.get_doc('Practitioner Schedule', schedule.schedule)
					enabled_schedule = True

			if practitioner_schedule:
				available_slots = []
				for t in practitioner_schedule.time_slots:
					if weekday == t.day:
						available_slots.append(t)

				if available_slots:
					appointments = []

					if schedule.service_unit:
						slot_name  = schedule.schedule+" - "+schedule.service_unit
						allow_overlap = frappe.get_value('Healthcare Service Unit', schedule.service_unit, 'overlap_appointments')
						if allow_overlap:
							# fetch all appointments to practitioner by service unit
							appointments = frappe.get_all(
								"Patient Appointment",
								filters={"practitioner": practitioner, "service_unit": schedule.service_unit, "appointment_date": date, "status": ["not in",["Cancelled"]]},
								fields=["name", "appointment_time", "duration", "status"],
								order_by= "appointment_date, appointment_time")
						else:
							# fetch all appointments to service unit
							appointments = frappe.get_all(
								"Patient Appointment",
								filters={"service_unit": schedule.service_unit, "appointment_date": date, "status": ["not in",["Cancelled"]]},
								fields=["name", "appointment_time", "duration", "status"],
								order_by= "appointment_date, appointment_time")
					else:
						slot_name = schedule.schedule
						# fetch all appointments to practitioner without service unit
						appointments = frappe.get_all(
							"Patient Appointment",
							filters={"practitioner": practitioner, "service_unit": '', "appointment_date": date, "status": ["not in",["Cancelled"]]},
							fields=["name", "appointment_time", "duration", "status"],
							order_by= "appointment_date, appointment_time")

					slot_details.append({"slot_name":slot_name, "service_unit":schedule.service_unit,
						"avail_slot":available_slots, 'appointments': appointments, 'absent_events': absent_events,
						'fixed_duration': schedule.always_use_slot_duration_as_appointment_duration, 'appointment_type': schedule.appointment_type})

	# Present events
	present_events = frappe.db.sql("""
		select
			name, event, from_time, to_time, from_date, to_date, duration, service_unit, repeat_this_event, repeat_on, repeat_till,
			monday, tuesday, wednesday, thursday, friday, saturday, sunday
		from
			`tabPractitioner Event`
		where
			practitioner = %(practitioner)s and present = 1 and
			(
				(repeat_this_event = 1 and (from_date<=%(date)s and ifnull(repeat_till, "3000-01-01")>=%(date)s))
				or
				(repeat_this_event != 1 and (from_date<=%(date)s and to_date>=%(date)s))
			)
	""".format(),{"practitioner":practitioner, "date":getdate(date)}, as_dict=True)

	present_events_details = []
	if present_events:
		remove_events = []
		add_events = []
		remove_events_by_repeat_on(present_events)
		for e in remove_events:
			present_events.remove(e)
		present_events = present_events + add_events

		for present_event in present_events:
			event_available_slots = []
			total_time_diff = time_diff_in_seconds(present_event.to_time, present_event.from_time)/60
			from_time = present_event.from_time
			slot_name = present_event.event
			appointments = []

			if present_event.service_unit:
				slot_name  = slot_name+" - "+present_event.service_unit
				allow_overlap = frappe.get_value('Healthcare Service Unit', present_event.service_unit, 'overlap_appointments')
				if allow_overlap:
					# fetch all appointments to practitioner by service unit
					appointments = frappe.get_all(
						"Patient Appointment",
						filters={"practitioner": practitioner, "service_unit": present_event.service_unit, "appointment_date": date, "status": ["not in",["Cancelled"]]},
						fields=["name", "appointment_time", "duration", "status"],
						order_by= "appointment_date, appointment_time")
				else:
					# fetch all appointments to service unit
					appointments = frappe.get_all(
						"Patient Appointment",
						filters={"service_unit": present_event.service_unit, "appointment_date": date, "status": ["not in",["Cancelled"]]},
						fields=["name", "appointment_time", "duration", "status"],
						order_by= "appointment_date, appointment_time")
			else:
				# fetch all appointments to practitioner without service unit
				appointments = frappe.get_all(
					"Patient Appointment",
					filters={"practitioner": practitioner, "service_unit": '', "appointment_date": date, "status": ["not in",["Cancelled"]]},
					fields=["name", "appointment_time", "duration", "status"],
					order_by= "appointment_date, appointment_time")

			for x in range(0, int(total_time_diff), present_event.duration):
				to_time = from_time + datetime.timedelta(seconds=present_event.duration*60)
				event_available_slots.append({'from_time': from_time, 'to_time': to_time})
				from_time = to_time
			present_events_details.append({'slot_name': slot_name, "service_unit":present_event.service_unit,
			'avail_slot': event_available_slots, 'appointments': appointments, 'absent_events': absent_events})
	else:
		if not practitioner_obj.practitioner_schedules:
			frappe.throw(_("{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master".format(practitioner)))
		elif not enabled_schedule:
			frappe.throw(_("{0} does not have an enabled Healthcare Practitioner Schedule.".format(practitioner)))
		elif not available_slots and not slot_details:
			frappe.throw(_("Healthcare Practitioner not available on {0}").format(weekday))

	return {
		"slot_details": slot_details,
		"present_events": present_events_details
	}