diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index df84322187..ada2b4bd3f 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -50,139 +50,51 @@ frappe.ui.form.on("Timesheet", { } } - if (frm.doc.total_hours && frm.doc.docstatus < 2) { - frm.add_custom_button(__('Start Timer'), function() { - frm.trigger("timer") - }).addClass("btn-primary"); - } + if (frm.doc.docstatus < 2) { + frm.add_custom_button(__('Start Timer'), function() { + var flag = true; + + // Fetch the row for timer where status = Pending i.e in progress + $.each(frm.doc.time_logs || [], function(i, row) { + if(row.status == 'Pending') { + timer(frm, row); + flag = false; + } + }) + + // Fetch the row for timer where status = Not Started + if (flag) { + $.each(frm.doc.time_logs || [], function(i, row) { + if(row.status == 'Not Started') { + timer(frm, row); + flag = false; + } + }) + } + // If no activities found to start a timer + if (flag) { + frappe.msgprint(__("No activities remaining.")); + } + }).addClass("btn-primary"); + + frm.add_custom_button(__("Create Activity"), function() { + create_activity(frm); + }) + } if(frm.doc.per_billed > 0) { frm.fields_dict["time_logs"].grid.toggle_enable("billing_hours", false); frm.fields_dict["time_logs"].grid.toggle_enable("billable", false); } - }, - - timer: function(frm) { - let dialog = new frappe.ui.Dialog({ - title: __("Timer"), - fields: [ - {"fieldtype": "Select", "label": __("Activity"), - "fieldname": "activity", - "options": frm.doc.time_logs.map(d => d.activity_type), - "reqd": 1, - onchange: () => { - const activity = dialog.get_value("activity") - const hours = frm.doc.time_logs.filter(d => d.activity_type == activity).map(d => d.hours); - const project = frm.doc.time_logs.filter(d => d.activity_type == activity).map(d => d.project) - - dialog.set_value("hours", hours) - dialog.set_value("project", project) - }}, - {"fieldtype": "Read Only", "label": __("Project"), - "fieldname": "project"}, - {"fieldtype": "Read Only", "label": __("Hours"), - "fieldname": "hours"} - ] - }); - dialog.wrapper.append(frappe.render_template("timesheet")); - frm.trigger("control_timer"); - dialog.show(); - }, - - control_timer: function() { - var interval = null; - var currentIncrement = 0; - var isPaused = false; - var initialised = false; - var clicked = false; - var paused_time = 0; - - $(".playpause").click(function(e) { - if (!cur_dialog.get_value('activity')) { - frappe.msgprint(__("Please select Activity")); - return false; - } - - if (clicked) { - e.preventDefault(); - return false; - } - - if (!initialised) { - initialised = true; - isPaused = false; - $(".playpause span").removeClass(); - $(".playpause span").addClass("pause"); - initialiseTimer(); - } - else { - $(".playpause span").removeClass(); - if (isPaused) { - isPaused = false; - $(".playpause span").addClass("pause"); - } - else { - isPaused = true; - $(".playpause span").addClass("play"); - paused_time = currentIncrement; - } - } - }); - - $(".stop").click(function() { - console.log(currentIncrement); - reset(); - }); - - function initialiseTimer() { - interval = setInterval(function() { - if (isPaused) return; - var current = setCurrentIncrement(); - updateStopwatch(current); - }, 1000); - } - - function updateStopwatch(increment) { - var hours = Math.floor(increment / 3600); - var minutes = Math.floor((increment - (hours * 3600)) / 60); - var seconds = increment - (hours * 3600) - (minutes * 60); - // if(!$('modal-open:visible')){ - // reset(); - // } - if (!$('.modal-dialog').is(':visible')) { - reset(); - } - if(hours > 99) - reset(); - if(cur_dialog && cur_dialog.get_value('hours') == hours) { - isPaused = true; - initialised = false; - frappe.utils.play_sound("alert"); - frappe.msgprint(__("Timer exceeded the given hours")); - } - $(".hours").text(hours < 10 ? ("0" + hours.toString()) : hours.toString()); - $(".minutes").text(minutes < 10 ? ("0" + minutes.toString()) : minutes.toString()); - $(".seconds").text(seconds < 10 ? ("0" + seconds.toString()) : seconds.toString()); - } - - function setCurrentIncrement() { - currentIncrement += 1; - return currentIncrement; - } - - function reset() { - currentIncrement = 0; - isPaused = true; - initialised = false; - clearInterval(interval); - $(".hours").text("00"); - $(".minutes").text("00"); - $(".seconds").text("00"); - $(".playpause span").removeClass(); - $(".playpause span").addClass("play"); - } - }, + }, + // var $trigger = $('.form-grid').find('.grid-row').find('.btn-open-row'); + // $trigger.on('click', () => { + // $('.form-grid') + // .find('[data-fieldname="timer"]') + // .append(frappe.render_template("timesheet")); + // frm.trigger("control_timer"); + // }) make_invoice: function(frm) { let dialog = new frappe.ui.Dialog({ title: __("Select Item (optional)"), @@ -213,7 +125,6 @@ frappe.ui.form.on("Timesheet", { } }) }) - dialog.show(); }, @@ -241,7 +152,15 @@ frappe.ui.form.on("Timesheet Detail", { frappe.model.set_value(cdt, cdn, "hours", moment(child.to_time).diff(moment(child.from_time), "seconds") / 3600); }, - + time_logs_add: function(frm) { + var $trigger_again = $('.form-grid').find('.grid-row').find('.btn-open-row'); + $trigger_again.on('click', () => { + $('.form-grid') + .find('[data-fieldname="timer"]') + .append(frappe.render_template("timesheet")); + frm.trigger("control_timer"); + }) + }, hours: function(frm, cdt, cdn) { calculate_end_time(frm, cdt, cdn) }, @@ -285,6 +204,173 @@ frappe.ui.form.on("Timesheet Detail", { } }); +// Spawn dialog for timer when clicked on 'Start RTimer' button +var timer = function(frm, row) { + let dialog = new frappe.ui.Dialog({ + title: __("Timer"), + fields: [ + {"fieldtype": "Read Only", "label": __("Activity"), + "fieldname": "activity" + // onchange: () => { + // const activity = dialog.get_value("activity") + // const hours = frm.doc.time_logs.filter(d => d.activity_type == activity).map(d => d.hours); + // const project = frm.doc.time_logs.filter(d => d.activity_type == activity).map(d => d.project) + + // dialog.set_value("hours", hours) + // dialog.set_value("project", project) + // } + }, + {"fieldtype": "Read Only", "label": __("Project"), + "fieldname": "project"}, + {"fieldtype": "Read Only", "label": __("Hours"), + "fieldname": "hours"} + ] + }); + dialog.set_values({ + 'activity': row.activity_type, + 'project': row.project, + 'hours': row.hours + }); + dialog.wrapper.append(frappe.render_template("timesheet")); + control_timer(frm, row, dialog); + dialog.show(); +} + +var control_timer = function(frm, row, dialog) { + var interval = null; + var currentIncrement = 0; + var isPaused = false; + var initialised = row ? true : false; + var clicked = false; + var paused_time = 0; + + // If row with status = Pending/ Not Completed found, initialize timer on click of 'Start Timer' + if (row) { + initialised = true; + $(".playpause span").removeClass(); + $(".playpause span").addClass("pause"); + initialiseTimer(); + } + + $(".playpause").click(function(e) { + if (clicked) { + e.preventDefault(); + return false; + } + + if (!initialised) { + initialised = true; + isPaused = false; + $(".playpause span").removeClass(); + $(".playpause span").addClass("pause"); + initialiseTimer(); + } + else { + $(".playpause span").removeClass(); + if (isPaused) { + isPaused = false; + $(".playpause span").addClass("pause"); + } + else { + isPaused = true; + $(".playpause span").addClass("play"); + paused_time = currentIncrement; + } + } + }); + + // $(".stop").click(function() { + // reset(); + // }); + + // Stop the timer and save the time logged by the timer on click of 'Complete' button + dialog.set_primary_action(__("Complete"), function() { + var grid_row = cur_frm.fields_dict['time_logs'].grid.grid_rows_by_docname[row.name]; + // console.log(grid_row); + grid_row.doc.timer_timestamp = currentIncrement; + grid_row.doc.status = "Completed"; + grid_row.refresh(); + // Save the form + frm.save(); + // frm.set_value(row.timer_timestamp, currentIncrement); + reset(); + dialog.hide(); + }) + function initialiseTimer() { + interval = setInterval(function() { + if (isPaused) return; + var current = setCurrentIncrement(); + updateStopwatch(current); + }, 1000); + } + + function updateStopwatch(increment) { + var hours = Math.floor(increment / 3600); + var minutes = Math.floor((increment - (hours * 3600)) / 60); + var seconds = increment - (hours * 3600) - (minutes * 60); + + // If modal is closed by clicking outside anywhere the modal, reset the timer + if (!$('.modal-dialog').is(':visible')) { + reset(); + } + if(hours > 99) + reset(); + if(cur_dialog && cur_dialog.get_value('hours') == hours) { + isPaused = true; + initialised = false; + frappe.utils.play_sound("alert"); + frappe.msgprint(__("Timer exceeded the given hours")); + } + $(".hours").text(hours < 10 ? ("0" + hours.toString()) : hours.toString()); + $(".minutes").text(minutes < 10 ? ("0" + minutes.toString()) : minutes.toString()); + $(".seconds").text(seconds < 10 ? ("0" + seconds.toString()) : seconds.toString()); + } + + function setCurrentIncrement() { + currentIncrement += 1; + return currentIncrement; + } + + function reset() { + currentIncrement = 0; + isPaused = true; + initialised = false; + clearInterval(interval); + $(".hours").text("00"); + $(".minutes").text("00"); + $(".seconds").text("00"); + $(".playpause span").removeClass(); + $(".playpause span").addClass("play"); + } +} + +var create_activity = function(frm) { + let dialog = new frappe.ui.Dialog({ + title: __("New Activity"), + fields: [ + {"fieldtype": "Link", "label": __("Activity Type"), "fieldname": "activity_type", + "options": "Activity Type", "reqd": 1}, + {"fieldtype": "Float", "label": __("Hrs"), "fieldname": "hours"}, + {"fieldtype": "Link", "label": __("Project"), "fieldname": "project", + "options": "Project"} + ] + }) + dialog.set_primary_action(__("Add Activity"), () => { + var args = dialog.get_values(); + if(!args) return; + var row = frappe.model.add_child(frm.doc, "Timesheet Detail", "time_logs"); + row.activity_type = args.activity_type; + row.hours = args.hours; + row.from_time = frappe.datetime.now_datetime(); + row.project = args.project; + frm.refresh_field("time_logs"); + dialog.hide(); + timer(frm, row); + }) + + dialog.show(); +} + var calculate_end_time = function(frm, cdt, cdn) { let child = locals[cdt][cdn]; diff --git a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json index 2b171d17fc..fb95683786 100644 --- a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json +++ b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json @@ -166,8 +166,6 @@ }, { "allow_bulk_edit": 0, -<<<<<<< HEAD -======= "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -200,7 +198,6 @@ }, { "allow_bulk_edit": 0, ->>>>>>> added status field/ "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -965,11 +962,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, -<<<<<<< HEAD - "modified": "2018-01-07 11:46:04.045313", -======= "modified": "2018-03-19 09:50:53.116469", ->>>>>>> added status field/ "modified_by": "Administrator", "module": "Projects", "name": "Timesheet Detail",