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: