Merge pull request #5772 from rohitwaghchaure/demo_records

Demo records for timesheet
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
index b949dfc..cd24f9b 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/production_order.py
@@ -7,6 +7,7 @@
 import json
 from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
 from frappe import _
+from frappe.utils import time_diff_in_seconds
 from frappe.model.document import Document
 from frappe.model.mapper import get_mapped_doc
 from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
@@ -262,12 +263,14 @@
 				original_start_time = d.planned_start_time
 
 				# validate operating hours if workstation [not mandatory] is specified
-				self.check_operation_fits_in_working_hours(d)
 				try:
 					timesheet.validate_time_logs()
 				except OverlapError:
 					if frappe.message_log: frappe.message_log.pop()
-					timesheet.move_to_next_non_overlapping_slot(d.idx)
+					timesheet.schedule_for_production_order(d.idx)
+				except WorkstationHolidayError:
+					if frappe.message_log: frappe.message_log.pop()
+					timesheet.schedule_for_production_order(d.idx)
 
 				from_time, to_time = self.get_start_end_time(timesheet, d.name)
 
@@ -294,7 +297,7 @@
 	def get_operations_data(self, data):
 		return {
 			'from_time': data.planned_start_time,
-			'hours': data.time_in_mins / 60,
+			'hours': data.time_in_mins / 60.0,
 			'to_time': data.planned_end_time,
 			'project': self.project,
 			'operation': data.operation,
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index 686f7c2..6881e0b 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -6,9 +6,12 @@
 import frappe
 from frappe import _
 
+from datetime import timedelta
 from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint, get_datetime_str
 from frappe.model.document import Document
 from frappe.model.mapper import get_mapped_doc
+from erpnext.manufacturing.doctype.workstation.workstation import (check_if_within_operating_hours,
+	WorkstationHolidayError)
 from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
 
 class OverlapError(frappe.ValidationError): pass
@@ -136,8 +139,8 @@
 
 	def validate_time_logs(self):
 		for data in self.get('time_logs'):
-			self.validate_overlap(data)
 			self.check_workstation_timings(data)
+			self.validate_overlap(data)
 
 	def validate_overlap(self, data):
 		if self.production_order:
@@ -179,29 +182,45 @@
 	def check_workstation_timings(self, args):
 		"""Checks if **Time Log** is between operating hours of the **Workstation**."""
 		if args.workstation and args.from_time and args.to_time:
-			from erpnext.manufacturing.doctype.workstation.workstation import check_if_within_operating_hours
 			check_if_within_operating_hours(args.workstation, args.operation, args.from_time, args.to_time)
 
-	def move_to_next_non_overlapping_slot(self, index):
-		from datetime import timedelta
-		if self.time_logs:
-			for data in self.time_logs:
-				if data.idx == index:
-					overlapping = self.get_overlap_for("workstation", data, data.workstation)
-					if not overlapping:
-						frappe.throw(_("Logical error: Must find overlapping"))
-					
-					if overlapping:
-						time_sheet = self.get_last_working_slot(overlapping.name, data.workstation)
-						data.from_time = get_datetime(time_sheet.to_time) + get_mins_between_operations()
-						data.to_time = get_datetime(data.from_time) + timedelta(hours=data.hours)
-					break
+	def schedule_for_production_order(self, index):
+		for data in self.time_logs:
+			if data.idx == index:
+				self.move_to_next_day(data) #check for workstation holiday
+				self.move_to_next_non_overlapping_slot(data) #check for overlap
+				break
+
+	def move_to_next_non_overlapping_slot(self, data):
+		overlapping = self.get_overlap_for("workstation", data, data.workstation)
+		if overlapping:
+			time_sheet = self.get_last_working_slot(overlapping.name, data.workstation)
+			data.from_time = get_datetime(time_sheet.to_time) + get_mins_between_operations()
+			data.to_time = self.get_to_time(data)
+			self.check_workstation_working_day(data)
 
 	def get_last_working_slot(self, time_sheet, workstation):
 		return frappe.db.sql(""" select max(from_time) as from_time, max(to_time) as to_time 
 			from `tabTimesheet Detail` where workstation = %(workstation)s""",
 			{'workstation': workstation}, as_dict=True)[0]
 
+	def move_to_next_day(self, data):
+		"""Move start and end time one day forward"""
+		self.check_workstation_working_day(data)
+
+	def check_workstation_working_day(self, data):
+		while True:
+			try:
+				self.check_workstation_timings(data)
+				break
+			except WorkstationHolidayError:
+				if frappe.message_log: frappe.message_log.pop()
+				data.from_time = get_datetime(data.from_time) + timedelta(hours=24)
+				data.to_time = self.get_to_time(data)
+
+	def get_to_time(self, data):
+		return get_datetime(data.from_time) + timedelta(hours=data.hours)
+
 	def update_cost(self):
 		for data in self.time_logs:
 			if data.activity_type and not data.billing_amount: