Merge pull request #5769 from rohitwaghchaure/timesheet_workstation_holiday_issue
[Fix] Timesheet workstation holiday issue
This commit is contained in:
commit
26452cb7eb
@ -7,6 +7,7 @@ import frappe
|
|||||||
import json
|
import json
|
||||||
from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
|
from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.utils import time_diff_in_seconds
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
|
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
|
||||||
@ -262,12 +263,14 @@ class ProductionOrder(Document):
|
|||||||
original_start_time = d.planned_start_time
|
original_start_time = d.planned_start_time
|
||||||
|
|
||||||
# validate operating hours if workstation [not mandatory] is specified
|
# validate operating hours if workstation [not mandatory] is specified
|
||||||
self.check_operation_fits_in_working_hours(d)
|
|
||||||
try:
|
try:
|
||||||
timesheet.validate_time_logs()
|
timesheet.validate_time_logs()
|
||||||
except OverlapError:
|
except OverlapError:
|
||||||
if frappe.message_log: frappe.message_log.pop()
|
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)
|
from_time, to_time = self.get_start_end_time(timesheet, d.name)
|
||||||
|
|
||||||
@ -294,7 +297,7 @@ class ProductionOrder(Document):
|
|||||||
def get_operations_data(self, data):
|
def get_operations_data(self, data):
|
||||||
return {
|
return {
|
||||||
'from_time': data.planned_start_time,
|
'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,
|
'to_time': data.planned_end_time,
|
||||||
'project': self.project,
|
'project': self.project,
|
||||||
'operation': data.operation,
|
'operation': data.operation,
|
||||||
|
@ -6,9 +6,12 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
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.utils import flt, time_diff_in_hours, get_datetime, getdate, cint, get_datetime_str
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.mapper import get_mapped_doc
|
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
|
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
|
||||||
|
|
||||||
class OverlapError(frappe.ValidationError): pass
|
class OverlapError(frappe.ValidationError): pass
|
||||||
@ -136,8 +139,8 @@ class Timesheet(Document):
|
|||||||
|
|
||||||
def validate_time_logs(self):
|
def validate_time_logs(self):
|
||||||
for data in self.get('time_logs'):
|
for data in self.get('time_logs'):
|
||||||
self.validate_overlap(data)
|
|
||||||
self.check_workstation_timings(data)
|
self.check_workstation_timings(data)
|
||||||
|
self.validate_overlap(data)
|
||||||
|
|
||||||
def validate_overlap(self, data):
|
def validate_overlap(self, data):
|
||||||
if self.production_order:
|
if self.production_order:
|
||||||
@ -179,29 +182,45 @@ class Timesheet(Document):
|
|||||||
def check_workstation_timings(self, args):
|
def check_workstation_timings(self, args):
|
||||||
"""Checks if **Time Log** is between operating hours of the **Workstation**."""
|
"""Checks if **Time Log** is between operating hours of the **Workstation**."""
|
||||||
if args.workstation and args.from_time and args.to_time:
|
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)
|
check_if_within_operating_hours(args.workstation, args.operation, args.from_time, args.to_time)
|
||||||
|
|
||||||
def move_to_next_non_overlapping_slot(self, index):
|
def schedule_for_production_order(self, index):
|
||||||
from datetime import timedelta
|
for data in self.time_logs:
|
||||||
if self.time_logs:
|
if data.idx == index:
|
||||||
for data in self.time_logs:
|
self.move_to_next_day(data) #check for workstation holiday
|
||||||
if data.idx == index:
|
self.move_to_next_non_overlapping_slot(data) #check for overlap
|
||||||
overlapping = self.get_overlap_for("workstation", data, data.workstation)
|
break
|
||||||
if not overlapping:
|
|
||||||
frappe.throw(_("Logical error: Must find overlapping"))
|
def move_to_next_non_overlapping_slot(self, data):
|
||||||
|
overlapping = self.get_overlap_for("workstation", data, data.workstation)
|
||||||
if overlapping:
|
if overlapping:
|
||||||
time_sheet = self.get_last_working_slot(overlapping.name, data.workstation)
|
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.from_time = get_datetime(time_sheet.to_time) + get_mins_between_operations()
|
||||||
data.to_time = get_datetime(data.from_time) + timedelta(hours=data.hours)
|
data.to_time = self.get_to_time(data)
|
||||||
break
|
self.check_workstation_working_day(data)
|
||||||
|
|
||||||
def get_last_working_slot(self, time_sheet, workstation):
|
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
|
return frappe.db.sql(""" select max(from_time) as from_time, max(to_time) as to_time
|
||||||
from `tabTimesheet Detail` where workstation = %(workstation)s""",
|
from `tabTimesheet Detail` where workstation = %(workstation)s""",
|
||||||
{'workstation': workstation}, as_dict=True)[0]
|
{'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):
|
def update_cost(self):
|
||||||
for data in self.time_logs:
|
for data in self.time_logs:
|
||||||
if data.activity_type and not data.billing_amount:
|
if data.activity_type and not data.billing_amount:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user