frappe.provide("erpnext.timesheet"); erpnext.timesheet.timer = function(frm, row, timestamp=0) { let dialog = new frappe.ui.Dialog({ title: __("Timer"), fields: [ {"fieldtype": "Link", "label": __("Activity Type"), "fieldname": "activity_type", "reqd": 1, "options": "Activity Type"}, {"fieldtype": "Link", "label": __("Project"), "fieldname": "project", "options": "Project"}, {"fieldtype": "Link", "label": __("Task"), "fieldname": "task", "options": "Task"}, {"fieldtype": "Float", "label": __("Expected Hrs"), "fieldname": "expected_hours"}, {"fieldtype": "Section Break"}, {"fieldtype": "HTML", "fieldname": "timer_html"} ] }); if (row) { dialog.set_values({ 'activity_type': row.activity_type, 'project': row.project, 'task': row.task, 'expected_hours': row.expected_hours }); } dialog.get_field("timer_html").$wrapper.append(get_timer_html()); function get_timer_html() { return `
00 : 00 : 00
`; } erpnext.timesheet.control_timer(frm, dialog, row, timestamp); dialog.show(); }; erpnext.timesheet.control_timer = function(frm, dialog, row, timestamp=0) { var $btn_start = dialog.$wrapper.find(".playpause .btn-start"); var $btn_complete = dialog.$wrapper.find(".playpause .btn-complete"); var interval = null; var currentIncrement = timestamp; var initialized = row ? true : false; var clicked = false; var flag = true; // Alert only once // If row with not completed status, initialize timer with the time elapsed on click of 'Start Timer'. if (row) { initialized = true; $btn_start.hide(); $btn_complete.show(); initializeTimer(); } if (!initialized) { $btn_complete.hide(); } $btn_start.click(function(e) { if (!initialized) { // New activity if no activities found var args = dialog.get_values(); if(!args) return; if (frm.doc.time_logs.length <= 1 && !frm.doc.time_logs[0].activity_type && !frm.doc.time_logs[0].from_time) { frm.doc.time_logs = []; } row = frappe.model.add_child(frm.doc, "Timesheet Detail", "time_logs"); row.activity_type = args.activity_type; row.from_time = frappe.datetime.get_datetime_as_string(); row.project = args.project; row.task = args.task; row.expected_hours = args.expected_hours; row.completed = 0; let d = moment(row.from_time); if(row.expected_hours) { d.add(row.expected_hours, "hours"); row.to_time = d.format(frappe.defaultDatetimeFormat); } frm.refresh_field("time_logs"); frm.save(); } if (clicked) { e.preventDefault(); return false; } if (!initialized) { initialized = true; $btn_start.hide(); $btn_complete.show(); initializeTimer(); } }); // Stop the timer and update the time logged by the timer on click of 'Complete' button $btn_complete.click(function() { var grid_row = cur_frm.fields_dict['time_logs'].grid.get_row(row.idx - 1); var args = dialog.get_values(); grid_row.doc.completed = 1; grid_row.doc.activity_type = args.activity_type; grid_row.doc.project = args.project; grid_row.doc.task = args.task; grid_row.doc.expected_hours = args.expected_hours; grid_row.doc.hours = currentIncrement / 3600; grid_row.doc.to_time = frappe.datetime.now_datetime(); grid_row.refresh(); frm.dirty(); frm.save(); reset(); dialog.hide(); }); function initializeTimer() { interval = setInterval(function() { 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 anywhere outside, reset the timer if (!$('.modal-dialog').is(':visible')) { reset(); } if(hours > 99999) reset(); if(cur_dialog && cur_dialog.get_value('expected_hours') > 0) { if(flag && (currentIncrement >= (cur_dialog.get_value('expected_hours') * 3600))) { frappe.utils.play_sound("alert"); frappe.msgprint(__("Timer exceeded the given hours.")); flag = false; } } $(".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; initialized = false; clearInterval(interval); $(".hours").text("00"); $(".minutes").text("00"); $(".seconds").text("00"); $btn_complete.hide(); $btn_start.show(); } };