Merge pull request #5748 from rohitwaghchaure/v7_timesheet_issue

[WIP] Timesheet overlap issue and fields rearranged
This commit is contained in:
Rushabh Mehta 2016-07-15 12:44:27 +05:30 committed by GitHub
commit 3f549980c9
7 changed files with 121 additions and 52 deletions

View File

@ -32,8 +32,8 @@ frappe.ui.form.on('Salary Structure', {
}, },
toggle_fields: function(frm) { toggle_fields: function(frm) {
frm.toggle_display('time_sheet_earning_detail', frm.doc.salary_slip_based_on_timesheet); frm.toggle_display(['salary_component', 'hour_rate'], frm.doc.salary_slip_based_on_timesheet);
frm.toggle_reqd('salary_component', frm.doc.salary_slip_based_on_timesheet); frm.toggle_reqd(['salary_component', 'hour_rate'], frm.doc.salary_slip_based_on_timesheet);
} }
}) })

View File

@ -8,6 +8,7 @@
"docstatus": 0, "docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Document", "document_type": "Document",
"editable_grid": 0,
"fields": [ "fields": [
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
@ -349,6 +350,31 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "time_sheet_earning_detail",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -379,14 +405,13 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"fieldname": "time_sheet_earning_detail", "fieldname": "column_break_17",
"fieldtype": "Section Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -428,30 +453,6 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_17",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -779,7 +780,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2016-07-02 18:04:06.529332", "modified": "2016-07-13 23:56:01.550518",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Salary Structure", "name": "Salary Structure",

View File

@ -292,3 +292,4 @@ erpnext.patches.v7_0.rename_prevdoc_fields
erpnext.patches.v7_0.rename_time_sheet_doctype erpnext.patches.v7_0.rename_time_sheet_doctype
execute:frappe.delete_doc_if_exists("Report", "Customers Not Buying Since Long Time") execute:frappe.delete_doc_if_exists("Report", "Customers Not Buying Since Long Time")
erpnext.patches.v7_0.make_is_group_fieldtype_as_check erpnext.patches.v7_0.make_is_group_fieldtype_as_check
execute:frappe.reload_doc('projects', 'doctype', 'timesheet', force=True)

View File

@ -86,28 +86,30 @@ def make_salary_structure(employee):
return salary_structure return salary_structure
def make_timesheet(employee, simulate=False, billable = 0): def make_timesheet(employee, simulate=False, billable = 0, activity_type="_Test Activity Type", project=None, task=None):
update_activity_type("_Test Activity Type") update_activity_type(activity_type)
timesheet = frappe.new_doc("Timesheet") timesheet = frappe.new_doc("Timesheet")
timesheet.employee = employee timesheet.employee = employee
timesheet_detail = timesheet.append('time_logs', {}) timesheet_detail = timesheet.append('time_logs', {})
timesheet_detail.billable = billable timesheet_detail.billable = billable
timesheet_detail.activity_type = "_Test Activity Type" timesheet_detail.activity_type = activity_type
timesheet_detail.from_time = now_datetime() timesheet_detail.from_time = now_datetime()
timesheet_detail.hours = 2 timesheet_detail.hours = 2
timesheet_detail.to_time = timesheet_detail.from_time + datetime.timedelta(hours= timesheet_detail.hours) timesheet_detail.to_time = timesheet_detail.from_time + datetime.timedelta(hours= timesheet_detail.hours)
timesheet_detail.project = project
timesheet_detail.task = task
for data in timesheet.get('time_logs'): for data in timesheet.get('time_logs'):
if simulate: if simulate:
while True: while True:
try: try:
timesheet.save() timesheet.save(ignore_permissions=True)
break break
except OverlapError: except OverlapError:
data.from_time = data.from_time + datetime.timedelta(minutes=10) data.from_time = data.from_time + datetime.timedelta(minutes=10)
data.to_time = data.from_time + datetime.timedelta(hours= data.hours) data.to_time = data.from_time + datetime.timedelta(hours= data.hours)
else: else:
timesheet.save() timesheet.save(ignore_permissions=True)
timesheet.submit() timesheet.submit()

View File

@ -1,5 +1,6 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
cur_frm.add_fetch('employee', 'employee_name', 'employee_name');
frappe.ui.form.on("Timesheet", { frappe.ui.form.on("Timesheet", {
setup: function(frm) { setup: function(frm) {

View File

@ -225,8 +225,9 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"depends_on": "employee",
"fieldname": "employee_name", "fieldname": "employee_name",
"fieldtype": "Read Only", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -235,12 +236,12 @@
"label": "Employee Name", "label": "Employee Name",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "employee.employee_name", "options": "",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 1,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -636,7 +637,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2016-07-13 01:18:57.918882", "modified": "2016-07-13 23:44:05.086570",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Projects", "module": "Projects",
"name": "Timesheet", "name": "Timesheet",
@ -661,6 +662,66 @@
"share": 1, "share": 1,
"submit": 1, "submit": 1,
"write": 1 "write": 1
},
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "HR User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Manufacturing User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Employee",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 1
} }
], ],
"quick_entry": 0, "quick_entry": 0,

View File

@ -141,31 +141,34 @@ class Timesheet(Document):
def validate_overlap(self, data): def validate_overlap(self, data):
if self.production_order: if self.production_order:
self.validate_overlap_for("workstation", data) self.validate_overlap_for("workstation", data, data.workstation)
else: else:
self.validate_overlap_for("user", data) self.validate_overlap_for("user", data, self.user)
self.validate_overlap_for("employee", data) self.validate_overlap_for("employee", data, self.employee)
def validate_overlap_for(self, fieldname, args): def validate_overlap_for(self, fieldname, args, value):
existing = self.get_overlap_for(fieldname, args) if not value: return
existing = self.get_overlap_for(fieldname, args, value)
if existing: if existing:
frappe.throw(_("Row {0}: From Time and To Time overlap with existing from and to time").format(args.idx), frappe.throw(_("Row {0}: From Time and To Time overlap with existing from and to time").format(args.idx),
OverlapError) OverlapError)
def get_overlap_for(self, fieldname, args): def get_overlap_for(self, fieldname, args, value):
if not args.get(fieldname): cond = "ts.`{0}`".format(fieldname)
return if fieldname == 'workstation':
cond = "tsd.`{0}`".format(fieldname)
existing = frappe.db.sql("""select ts.name as name, tsd.from_time as from_time, tsd.to_time as to_time from existing = frappe.db.sql("""select ts.name as name, tsd.from_time as from_time, tsd.to_time as to_time from
`tabTimesheet Detail` tsd, `tabTimesheet` ts where tsd.`{0}`=%(val)s and tsd.parent = ts.name and `tabTimesheet Detail` tsd, `tabTimesheet` ts where {0}=%(val)s and tsd.parent = ts.name and
( (
(%(from_time)s > tsd.from_time and %(from_time)s < tsd.to_time) or (%(from_time)s > tsd.from_time and %(from_time)s < tsd.to_time) or
(%(to_time)s > tsd.from_time and %(to_time)s < tsd.to_time) or (%(to_time)s > tsd.from_time and %(to_time)s < tsd.to_time) or
(%(from_time)s <= tsd.from_time and %(to_time)s >= tsd.to_time)) (%(from_time)s <= tsd.from_time and %(to_time)s >= tsd.to_time))
and tsd.name!=%(name)s and tsd.name!=%(name)s
and ts.docstatus < 2""".format(fieldname), and ts.docstatus < 2""".format(cond),
{ {
"val": args.get(fieldname), "val": value,
"from_time": args.from_time, "from_time": args.from_time,
"to_time": args.to_time, "to_time": args.to_time,
"name": args.name or "No Name" "name": args.name or "No Name"
@ -184,7 +187,7 @@ class Timesheet(Document):
if self.time_logs: if self.time_logs:
for data in self.time_logs: for data in self.time_logs:
if data.idx == index: if data.idx == index:
overlapping = self.get_overlap_for("workstation", data) overlapping = self.get_overlap_for("workstation", data, data.workstation)
if not overlapping: if not overlapping:
frappe.throw(_("Logical error: Must find overlapping")) frappe.throw(_("Logical error: Must find overlapping"))