Feature - Employee Attendance Tool
This commit is contained in:
parent
1890c794d7
commit
07364f5ece
@ -60,9 +60,9 @@ def get_data():
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Process Payroll",
|
||||
"label": _("Process Payroll"),
|
||||
"description":_("Generate Salary Slips"),
|
||||
"name": "Employee Attendance Tool",
|
||||
"label": _("Employee Attendance Tool"),
|
||||
"description":_("Mark Employee Attendance in Bulk"),
|
||||
"hide_count": True
|
||||
},
|
||||
{
|
||||
@ -71,6 +71,14 @@ def get_data():
|
||||
"description":_("Upload attendance from a .csv file"),
|
||||
"hide_count": True
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Process Payroll",
|
||||
"label": _("Process Payroll"),
|
||||
"description":_("Generate Salary Slips"),
|
||||
"hide_count": True
|
||||
},
|
||||
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Leave Control Panel",
|
||||
|
@ -0,0 +1,21 @@
|
||||
.top-toolbar{
|
||||
padding-bottom: 30px;
|
||||
margin-left: -17px;
|
||||
}
|
||||
|
||||
.bottom-toolbar{
|
||||
margin-left: -17px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.btn{
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.marked-employee-label{
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.checkbox{
|
||||
margin-top: -3px;
|
||||
}
|
@ -0,0 +1,233 @@
|
||||
frappe.ui.form.on("Employee Attendance Tool", {
|
||||
refresh:function(frm){
|
||||
frm.disable_save();
|
||||
},
|
||||
|
||||
onload:function(frm){
|
||||
erpnext.employee_attendance_tool.load_employees(frm);
|
||||
},
|
||||
|
||||
date:function(frm){
|
||||
erpnext.employee_attendance_tool.load_employees(frm);
|
||||
},
|
||||
|
||||
department:function(frm){
|
||||
erpnext.employee_attendance_tool.load_employees(frm);
|
||||
},
|
||||
|
||||
branch:function(frm){
|
||||
erpnext.employee_attendance_tool.load_employees(frm);
|
||||
},
|
||||
|
||||
company:function(frm){
|
||||
erpnext.employee_attendance_tool.load_employees(frm);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
erpnext.employee_attendance_tool = {
|
||||
load_employees: function(frm){
|
||||
if(frm.doc.date){
|
||||
frappe.call({
|
||||
method:"erpnext.hr.doctype.employee_attendance_tool.employee_attendance_tool.get_employees",
|
||||
args:{
|
||||
date:frm.doc.date,
|
||||
department:frm.doc.department,
|
||||
branch:frm.doc.branch,
|
||||
company:frm.doc.company
|
||||
},
|
||||
callback:function(r){
|
||||
if(r.message['unmarked'].length > 0){
|
||||
unhide_field('unmarked_attendance_section')
|
||||
if(!frm.employee_area){
|
||||
frm.employee_area = $('<div>')
|
||||
.appendTo(frm.fields_dict.employees_html.wrapper);
|
||||
}
|
||||
frm.EmployeeSelector = new erpnext.EmployeeSelector(frm, frm.employee_area, r.message['unmarked'])
|
||||
}
|
||||
else{
|
||||
hide_field('unmarked_attendance_section')
|
||||
}
|
||||
|
||||
if(r.message['marked'].length > 0){
|
||||
unhide_field('marked_attendance_section')
|
||||
if(!frm.marked_employee_area){
|
||||
|
||||
frm.marked_employee_area = $('<div>')
|
||||
.appendTo(frm.fields_dict.marked_attendance_html.wrapper);
|
||||
}
|
||||
frm.MarkedEmployee = new erpnext.MarkedEmployee(frm, frm.marked_employee_area, r.message['marked'])
|
||||
}
|
||||
else{
|
||||
hide_field('marked_attendance_section')
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.MarkedEmployee = Class.extend({
|
||||
init: function(frm, wrapper, employee) {
|
||||
this.wrapper = wrapper;
|
||||
this.frm = frm;
|
||||
this.make(frm, employee);
|
||||
},
|
||||
make: function(frm, employee) {
|
||||
var me = this;
|
||||
$(this.wrapper).empty();
|
||||
|
||||
$.each(employee, function(i, m) {
|
||||
var attendance_icon = "'icon-check'"
|
||||
if(m.status == "Absent") {
|
||||
attendance_icon="'icon-check-empty'"
|
||||
}
|
||||
else if(m.status == "Half Day"){
|
||||
attendance_icon = "'icon-check-minus'"
|
||||
}
|
||||
$(repl('<div class="col-sm-3">\
|
||||
<label class="marked-employee-label"><span class=%(icon)s></span>\
|
||||
%(employee)s</label>\
|
||||
</div>', {employee: m.employee_name, icon: attendance_icon})).appendTo(me.wrapper);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
erpnext.EmployeeSelector = Class.extend({
|
||||
init: function(frm, wrapper, employee) {
|
||||
this.wrapper = wrapper;
|
||||
this.frm = frm;
|
||||
this.make(frm, employee);
|
||||
},
|
||||
make: function(frm, employee) {
|
||||
var me = this;
|
||||
|
||||
$(this.wrapper).empty();
|
||||
var employee_toolbar = $('<div class="col-sm-12 top-toolbar">\
|
||||
<button class="btn btn-default btn-add btn-xs"></button>\
|
||||
<button class="btn btn-xs btn-default btn-remove"></button>\
|
||||
</div>').appendTo($(this.wrapper));
|
||||
|
||||
var mark_employee_toolbar = $('<div class="col-sm-12 bottom-toolbar">\
|
||||
<button class="btn btn-default btn-primary btn-mark-present btn-xs"></button>\
|
||||
<button class="btn btn-default btn-primary btn-mark-absent btn-xs"></button>\
|
||||
<button class="btn btn-default btn-primary btn-mark-half-day btn-xs"></button></div>')
|
||||
|
||||
employee_toolbar.find(".btn-add")
|
||||
.html(__('Check all'))
|
||||
.on("click", function() {
|
||||
$(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
|
||||
if(!$(check).is(":checked")) {
|
||||
check.checked = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
employee_toolbar.find(".btn-remove")
|
||||
.html(__('Uncheck all'))
|
||||
.on("click", function() {
|
||||
$(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
|
||||
if($(check).is(":checked")) {
|
||||
check.checked = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
mark_employee_toolbar.find(".btn-mark-present")
|
||||
.html(__('Mark Present'))
|
||||
.on("click", function() {
|
||||
var employee_present = [];
|
||||
$(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
|
||||
if($(check).is(":checked")) {
|
||||
employee_present.push(employee[i]);
|
||||
}
|
||||
});
|
||||
frappe.call({
|
||||
method: "erpnext.hr.doctype.employee_attendance_tool.employee_attendance_tool.mark_employee_attendance",
|
||||
args:{
|
||||
"employee_list":employee_present,
|
||||
"status":"Present",
|
||||
"date":frm.doc.date,
|
||||
"company":frm.doc.company
|
||||
},
|
||||
|
||||
callback: function(r) {
|
||||
erpnext.employee_attendance_tool.load_employees(frm);
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
mark_employee_toolbar.find(".btn-mark-absent")
|
||||
.html(__('Mark Absent'))
|
||||
.on("click", function() {
|
||||
var employee_absent = [];
|
||||
$(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
|
||||
if($(check).is(":checked")) {
|
||||
employee_absent.push(employee[i]);
|
||||
}
|
||||
});
|
||||
frappe.call({
|
||||
method: "erpnext.hr.doctype.employee_attendance_tool.employee_attendance_tool.mark_employee_attendance",
|
||||
args:{
|
||||
"employee_list":employee_absent,
|
||||
"status":"Absent",
|
||||
"date":frm.doc.date,
|
||||
"company":frm.doc.company
|
||||
},
|
||||
|
||||
callback: function(r) {
|
||||
erpnext.employee_attendance_tool.load_employees(frm);
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
mark_employee_toolbar.find(".btn-mark-half-day")
|
||||
.html(__('Mark Half Day'))
|
||||
.on("click", function() {
|
||||
var employee_half_day = [];
|
||||
$(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
|
||||
if($(check).is(":checked")) {
|
||||
employee_half_day.push(employee[i]);
|
||||
}
|
||||
});
|
||||
frappe.call({
|
||||
method: "erpnext.hr.doctype.employee_attendance_tool.employee_attendance_tool.mark_employee_attendance",
|
||||
args:{
|
||||
"employee_list":employee_half_day,
|
||||
"status":"Half Day",
|
||||
"date":frm.doc.date,
|
||||
"company":frm.doc.company
|
||||
},
|
||||
|
||||
callback: function(r) {
|
||||
erpnext.employee_attendance_tool.load_employees(frm);
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$.each(employee, function(i, m) {
|
||||
$(repl('<div class="col-sm-3 unmarked-employee-checkbox">\
|
||||
<div class="checkbox">\
|
||||
<label><input type="checkbox" class="employee-check" employee="%(employee)s"/>\
|
||||
%(employee)s</label>\
|
||||
</div></div>', {employee: m.employee_name})).appendTo(me.wrapper);
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
mark_employee_toolbar.appendTo($(this.wrapper));
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -0,0 +1,275 @@
|
||||
{
|
||||
"allow_copy": 1,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"creation": "2016-01-27 14:59:47.849379",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"default": "Today",
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Date",
|
||||
"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,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "department",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Department",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Department",
|
||||
"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,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 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,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "branch",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Branch",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Branch",
|
||||
"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,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"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,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"depends_on": "date",
|
||||
"fieldname": "unmarked_attendance_section",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Unmarked Attendance",
|
||||
"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,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "employees_html",
|
||||
"fieldtype": "HTML",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Employees HTML",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"depends_on": "date",
|
||||
"fieldname": "marked_attendance_section",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Marked Attendance",
|
||||
"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,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "marked_attendance_html",
|
||||
"fieldtype": "HTML",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Marked Attendance HTML",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"hide_heading": 1,
|
||||
"hide_toolbar": 1,
|
||||
"idx": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-01-29 02:14:36.034952",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Attendance Tool",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"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": "HR Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import copy
|
||||
import json
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class EmployeeAttendanceTool(Document):
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_employees(date, department=None, branch=None, company=None):
|
||||
attendance_not_marked = []
|
||||
attendance_marked = []
|
||||
employee_list = frappe.get_list("Employee", fields=["employee", "employee_name"], filters={
|
||||
"status": "Active", "department": department, "branch": branch, "company": company}, order_by="employee_name")
|
||||
marked_employee = {}
|
||||
for emp in frappe.get_list("Attendance", fields=["employee", "status"],
|
||||
filters={"att_date": date}):
|
||||
marked_employee[emp['employee']] = emp['status']
|
||||
|
||||
for employee in employee_list:
|
||||
employee['status'] = marked_employee.get(employee['employee'])
|
||||
if employee['employee'] not in marked_employee:
|
||||
attendance_not_marked.append(employee)
|
||||
else:
|
||||
attendance_marked.append(employee)
|
||||
return {
|
||||
"marked": attendance_marked,
|
||||
"unmarked": attendance_not_marked
|
||||
}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def mark_employee_attendance(employee_list, status, date, company=None):
|
||||
employee_list = json.loads(employee_list)
|
||||
for employee in employee_list:
|
||||
attendance = frappe.new_doc("Attendance")
|
||||
attendance.employee = employee['employee']
|
||||
attendance.employee_name = employee['employee_name']
|
||||
attendance.att_date = date
|
||||
attendance.status = status
|
||||
if company:
|
||||
attendance.company = company
|
||||
else:
|
||||
attendance.company = frappe.db.get_value("Employee", employee['employee'], "Company")
|
||||
attendance.submit()
|
Loading…
x
Reference in New Issue
Block a user