2018-03-21 16:50:46 +00:00
|
|
|
frappe.provide("erpnext.timesheet");
|
2018-03-21 13:55:56 +00:00
|
|
|
|
2018-03-21 16:50:11 +00:00
|
|
|
erpnext.timesheet.timer = function(frm, row, timestamp=0) {
|
2018-03-21 13:55:56 +00:00
|
|
|
let dialog = new frappe.ui.Dialog({
|
|
|
|
title: __("Timer"),
|
|
|
|
fields:
|
|
|
|
[
|
|
|
|
{"fieldtype": "Link", "label": __("Activity Type"), "fieldname": "activity_type",
|
2018-03-21 16:50:11 +00:00
|
|
|
"reqd": 1, "options": "Activity Type"},
|
|
|
|
{"fieldtype": "Link", "label": __("Project"), "fieldname": "project", "options": "Project"},
|
2018-03-23 06:16:45 +00:00
|
|
|
{"fieldtype": "Link", "label": __("Task"), "fieldname": "task", "options": "Task"},
|
2018-03-21 13:55:56 +00:00
|
|
|
{"fieldtype": "Float", "label": __("Expected Hrs"), "fieldname": "expected_hours"},
|
|
|
|
{"fieldtype": "Section Break"},
|
|
|
|
{"fieldtype": "HTML", "fieldname": "timer_html"}
|
|
|
|
]
|
|
|
|
});
|
2018-03-21 16:50:11 +00:00
|
|
|
|
2018-03-21 13:55:56 +00:00
|
|
|
if (row) {
|
|
|
|
dialog.set_values({
|
|
|
|
'activity_type': row.activity_type,
|
|
|
|
'project': row.project,
|
2018-03-23 06:16:45 +00:00
|
|
|
'task': row.task,
|
2018-03-21 13:55:56 +00:00
|
|
|
'expected_hours': row.expected_hours
|
|
|
|
});
|
|
|
|
}
|
2018-03-22 06:10:38 +00:00
|
|
|
dialog.get_field("timer_html").$wrapper.append(get_timer_html());
|
|
|
|
function get_timer_html() {
|
|
|
|
return `
|
|
|
|
<div class="stopwatch">
|
|
|
|
<span class="hours">00</span>
|
|
|
|
<span class="colon">:</span>
|
|
|
|
<span class="minutes">00</span>
|
|
|
|
<span class="colon">:</span>
|
|
|
|
<span class="seconds">00</span>
|
|
|
|
</div>
|
|
|
|
<div class="playpause text-center">
|
|
|
|
<button class= "btn btn-primary btn-start"> ${ __("Start") } </button>
|
|
|
|
<button class= "btn btn-primary btn-complete"> ${ __("Complete") } </button>
|
|
|
|
</div>
|
|
|
|
`;
|
2018-03-22 06:26:05 +00:00
|
|
|
}
|
2018-03-22 06:10:38 +00:00
|
|
|
erpnext.timesheet.control_timer(frm, dialog, row, timestamp);
|
2018-03-21 13:55:56 +00:00
|
|
|
dialog.show();
|
2018-03-21 16:50:46 +00:00
|
|
|
};
|
2018-03-21 13:55:56 +00:00
|
|
|
|
2018-03-22 06:10:38 +00:00
|
|
|
erpnext.timesheet.control_timer = function(frm, dialog, row, timestamp=0) {
|
2018-11-27 07:41:30 +00:00
|
|
|
var $btn_start = dialog.$wrapper.find(".playpause .btn-start");
|
|
|
|
var $btn_complete = dialog.$wrapper.find(".playpause .btn-complete");
|
2018-03-21 13:55:56 +00:00
|
|
|
var interval = null;
|
2018-03-21 16:50:46 +00:00
|
|
|
var currentIncrement = timestamp;
|
2022-11-20 14:15:51 +00:00
|
|
|
var initialized = row ? true : false;
|
2018-03-21 13:55:56 +00:00
|
|
|
var clicked = false;
|
2018-04-02 05:02:39 +00:00
|
|
|
var flag = true; // Alert only once
|
2018-03-21 13:55:56 +00:00
|
|
|
// If row with not completed status, initialize timer with the time elapsed on click of 'Start Timer'.
|
|
|
|
if (row) {
|
2022-11-20 14:15:51 +00:00
|
|
|
initialized = true;
|
2018-03-21 16:50:11 +00:00
|
|
|
$btn_start.hide();
|
|
|
|
$btn_complete.show();
|
2022-11-20 14:15:51 +00:00
|
|
|
initializeTimer();
|
2018-03-21 13:55:56 +00:00
|
|
|
}
|
2022-11-20 14:15:51 +00:00
|
|
|
|
|
|
|
if (!initialized) {
|
2018-03-21 16:50:11 +00:00
|
|
|
$btn_complete.hide();
|
|
|
|
}
|
2022-11-20 14:15:51 +00:00
|
|
|
|
2018-03-21 13:55:56 +00:00
|
|
|
$btn_start.click(function(e) {
|
2022-11-20 14:15:51 +00:00
|
|
|
if (!initialized) {
|
2018-03-21 13:55:56 +00:00
|
|
|
// New activity if no activities found
|
|
|
|
var args = dialog.get_values();
|
|
|
|
if(!args) return;
|
2023-04-25 15:27:59 +00:00
|
|
|
if (frm.doc.time_logs.length == 1 && !frm.doc.time_logs[0].activity_type && !frm.doc.time_logs[0].from_time) {
|
2018-03-21 13:55:56 +00:00
|
|
|
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();
|
2018-03-23 06:16:45 +00:00
|
|
|
row.project = args.project;
|
|
|
|
row.task = args.task;
|
2018-03-21 13:55:56 +00:00
|
|
|
row.expected_hours = args.expected_hours;
|
|
|
|
row.completed = 0;
|
2018-03-21 16:50:46 +00:00
|
|
|
let d = moment(row.from_time);
|
2018-03-21 13:55:56 +00:00
|
|
|
if(row.expected_hours) {
|
|
|
|
d.add(row.expected_hours, "hours");
|
2018-06-25 17:07:43 +00:00
|
|
|
row.to_time = d.format(frappe.defaultDatetimeFormat);
|
2018-03-21 13:55:56 +00:00
|
|
|
}
|
|
|
|
frm.refresh_field("time_logs");
|
2018-03-21 16:50:11 +00:00
|
|
|
frm.save();
|
2018-03-21 13:55:56 +00:00
|
|
|
}
|
2018-03-21 16:50:11 +00:00
|
|
|
|
2018-03-21 13:55:56 +00:00
|
|
|
if (clicked) {
|
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-11-20 14:15:51 +00:00
|
|
|
if (!initialized) {
|
|
|
|
initialized = true;
|
2018-03-21 16:50:11 +00:00
|
|
|
$btn_start.hide();
|
|
|
|
$btn_complete.show();
|
2022-11-20 14:15:51 +00:00
|
|
|
initializeTimer();
|
2018-03-21 13:55:56 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-03-21 16:50:11 +00:00
|
|
|
// Stop the timer and update the time logged by the timer on click of 'Complete' button
|
|
|
|
$btn_complete.click(function() {
|
2018-03-22 06:26:05 +00:00
|
|
|
var grid_row = cur_frm.fields_dict['time_logs'].grid.get_row(row.idx - 1);
|
2018-03-21 16:50:11 +00:00
|
|
|
var args = dialog.get_values();
|
2018-03-21 13:55:56 +00:00
|
|
|
grid_row.doc.completed = 1;
|
2018-03-21 16:50:11 +00:00
|
|
|
grid_row.doc.activity_type = args.activity_type;
|
|
|
|
grid_row.doc.project = args.project;
|
2018-03-23 06:16:45 +00:00
|
|
|
grid_row.doc.task = args.task;
|
2018-03-21 16:50:11 +00:00
|
|
|
grid_row.doc.expected_hours = args.expected_hours;
|
2018-03-21 13:55:56 +00:00
|
|
|
grid_row.doc.hours = currentIncrement / 3600;
|
|
|
|
grid_row.doc.to_time = frappe.datetime.now_datetime();
|
|
|
|
grid_row.refresh();
|
2022-11-20 14:15:51 +00:00
|
|
|
frm.dirty();
|
2018-03-21 13:55:56 +00:00
|
|
|
frm.save();
|
|
|
|
reset();
|
|
|
|
dialog.hide();
|
2018-03-21 16:50:46 +00:00
|
|
|
});
|
2022-11-20 14:15:51 +00:00
|
|
|
|
|
|
|
function initializeTimer() {
|
2018-03-21 13:55:56 +00:00
|
|
|
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);
|
|
|
|
|
2018-03-21 16:50:11 +00:00
|
|
|
// If modal is closed by clicking anywhere outside, reset the timer
|
2018-03-21 13:55:56 +00:00
|
|
|
if (!$('.modal-dialog').is(':visible')) {
|
|
|
|
reset();
|
|
|
|
}
|
2018-04-02 05:02:39 +00:00
|
|
|
if(hours > 99999)
|
2018-03-21 16:50:46 +00:00
|
|
|
reset();
|
2018-04-02 05:02:39 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2018-03-21 13:55:56 +00:00
|
|
|
$(".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;
|
2022-11-20 14:15:51 +00:00
|
|
|
initialized = false;
|
2018-03-21 13:55:56 +00:00
|
|
|
clearInterval(interval);
|
|
|
|
$(".hours").text("00");
|
|
|
|
$(".minutes").text("00");
|
|
|
|
$(".seconds").text("00");
|
2018-03-21 16:50:11 +00:00
|
|
|
$btn_complete.hide();
|
|
|
|
$btn_start.show();
|
2018-03-21 13:55:56 +00:00
|
|
|
}
|
2018-03-21 16:50:46 +00:00
|
|
|
};
|