diff --git a/erpnext/demo/user/hr.py b/erpnext/demo/user/hr.py index 1570df59637..504478a2413 100644 --- a/erpnext/demo/user/hr.py +++ b/erpnext/demo/user/hr.py @@ -17,32 +17,32 @@ def work(): mark_attendance() make_leave_application() - # process payroll + # payroll entry if not frappe.db.sql('select name from `tabSalary Slip` where month(adddate(start_date, interval 1 month))=month(curdate())'): # process payroll for previous month - process_payroll = frappe.get_doc("Process Payroll", "Process Payroll") - process_payroll.company = frappe.flags.company - process_payroll.payroll_frequency = 'Monthly' + payroll_entry = frappe.new_doc("Payroll Entry") + payroll_entry.company = frappe.flags.company + payroll_entry.payroll_frequency = 'Monthly' # select a posting date from the previous month - process_payroll.posting_date = get_last_day(getdate(frappe.flags.current_date) - datetime.timedelta(days=10)) - process_payroll.payment_account = frappe.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name") + payroll_entry.posting_date = get_last_day(getdate(frappe.flags.current_date) - datetime.timedelta(days=10)) + payroll_entry.payment_account = frappe.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name") - process_payroll.set_start_end_dates() + payroll_entry.set_start_end_dates() # based on frequency - process_payroll.salary_slip_based_on_timesheet = 0 - process_payroll.create_salary_slips() - process_payroll.submit_salary_slips() - process_payroll.make_accural_jv_entry() - # process_payroll.make_journal_entry(reference_date=frappe.flags.current_date, + payroll_entry.salary_slip_based_on_timesheet = 0 + payroll_entry.create_salary_slips() + payroll_entry.submit_salary_slips() + payroll_entry.make_accural_jv_entry() + # payroll_entry.make_journal_entry(reference_date=frappe.flags.current_date, # reference_number=random_string(10)) - process_payroll.salary_slip_based_on_timesheet = 1 - process_payroll.create_salary_slips() - process_payroll.submit_salary_slips() - process_payroll.make_accural_jv_entry() - # process_payroll.make_journal_entry(reference_date=frappe.flags.current_date, + payroll_entry.salary_slip_based_on_timesheet = 1 + payroll_entry.create_salary_slips() + payroll_entry.submit_salary_slips() + payroll_entry.make_accural_jv_entry() + # payroll_entry.make_journal_entry(reference_date=frappe.flags.current_date, # reference_number=random_string(10)) if frappe.db.get_global('demo_hr_user'): diff --git a/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.json b/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.json index 3e1683d910d..953cffae218 100644 --- a/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.json +++ b/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.json @@ -176,7 +176,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-30 06:59:34.117930", + "modified": "2017-11-30 18:25:34.967999", "modified_by": "Administrator", "module": "HR", "name": "Payroll Employee Detail", diff --git a/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.py b/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.py index c52dec1df59..aeb11fd7e27 100644 --- a/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.py +++ b/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.py @@ -3,7 +3,6 @@ # For license information, please see license.txt from __future__ import unicode_literals -import frappe from frappe.model.document import Document class PayrollEmployeeDetail(Document): diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.js b/erpnext/hr/doctype/payroll_entry/payroll_entry.js index 21cc2b32c7c..4de405268c3 100644 --- a/erpnext/hr/doctype/payroll_entry/payroll_entry.js +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.js @@ -58,6 +58,23 @@ frappe.ui.form.on('Payroll Entry', { payroll_frequency: function (frm) { frm.trigger("set_start_end_dates"); + frm.set_value('employees', []); + }, + + company: function (frm) { + frm.set_value('employees', []); + }, + + department: function (frm) { + frm.set_value('employees', []); + }, + + designation: function (frm) { + frm.set_value('employees', []); + }, + + branch: function (frm) { + frm.set_value('employees', []); }, start_date: function (frm) { @@ -67,6 +84,11 @@ frappe.ui.form.on('Payroll Entry', { // reset flag in_progress = false; } + frm.set_value('employees', []); + }, + + project: function (frm) { + frm.set_value('employees', []); }, salary_slip_based_on_timesheet: function (frm) { @@ -108,12 +130,6 @@ frappe.ui.form.on('Payroll Entry', { }, }); -// Create salary slips - -cur_frm.cscript.custom_before_submit = function (doc) { - return $c('runserverobj', { 'method': 'create_salary_slips', 'docs': doc }); -}; - // Submit salary slips let submit_salary_slip = function (frm) { @@ -121,11 +137,12 @@ let submit_salary_slip = function (frm) { return $c('runserverobj', { 'method': 'submit_salary_slips', 'docs': doc }); }; -cur_frm.cscript.get_employee_details = function (doc, cdt, cdn) { - var callback = function (r, rt) { - if (r.message) +cur_frm.cscript.get_employee_details = function (doc) { + var callback = function (r) { + if (r.docs[0].employees){ cur_frm.refresh_field('employees'); - } + } + }; return $c('runserverobj', { 'method': 'fill_employee_details', 'docs': doc }, callback); } diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.json b/erpnext/hr/doctype/payroll_entry/payroll_entry.json index 6cab18d33b4..397cb13d36c 100644 --- a/erpnext/hr/doctype/payroll_entry/payroll_entry.json +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.json @@ -564,35 +564,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "data_19", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -907,7 +878,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-11-30 06:57:23.860603", + "modified": "2017-11-30 18:33:38.967104", "modified_by": "Administrator", "module": "HR", "name": "Payroll Entry", diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py index 765df9a9394..55459c7b4aa 100644 --- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py @@ -11,6 +11,10 @@ from frappe import _ from erpnext.accounts.utils import get_fiscal_year class PayrollEntry(Document): + + def on_submit(self): + self.create_salary_slips() + def get_emp_list(self): """ Returns list of active employees based on selected criteria @@ -97,15 +101,15 @@ class PayrollEntry(Document): start_date >= %s and end_date <= %s and company = %s - """, (emp[0], self.start_date, self.end_date, self.company)): + """, (emp['employee'], self.start_date, self.end_date, self.company)): ss = frappe.get_doc({ "doctype": "Salary Slip", "salary_slip_based_on_timesheet": self.salary_slip_based_on_timesheet, "payroll_frequency": self.payroll_frequency, "start_date": self.start_date, "end_date": self.end_date, - "employee": emp[0], - "employee_name": frappe.get_value("Employee", {"name":emp[0]}, "employee_name"), + "employee": emp['employee'], + "employee_name": frappe.get_value("Employee", {"name":emp['employee']}, "employee_name"), "company": self.company, "posting_date": self.posting_date }) diff --git a/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py b/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py index 2cd6dbfca38..f9d4f08da1a 100644 --- a/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py +++ b/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py @@ -1,19 +1,15 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals - import unittest - import erpnext import frappe from dateutil.relativedelta import relativedelta from erpnext.accounts.utils import get_fiscal_year, getdate, nowdate from erpnext.hr.doctype.payroll_entry.payroll_entry import get_start_end_dates, get_end_date -class TestProcessPayroll(unittest.TestCase): +class TestPayrollEntry(unittest.TestCase): def test_payroll_entry(self): - month = "11" - fiscal_year = "_Test Fiscal Year 2016" for data in frappe.get_all('Salary Component', fields = ["name"]): if not frappe.db.get_value('Salary Component Account', @@ -132,7 +128,7 @@ def get_salary_component_account(sal_comp): sc = sal_comp.append("accounts") sc.company = company sc.default_account = create_account(company) - + def create_account(company): salary_account = frappe.db.get_value("Account", "Salary - " + frappe.db.get_value('Company', company, 'abbr')) if not salary_account: @@ -158,7 +154,7 @@ def make_payroll_entry(**args): payroll_entry.create_salary_slips() payroll_entry.submit_salary_slips() if payroll_entry.get_sal_slip_list(ss_status = 1): - r = payroll_entry.make_payment_entry() + payroll_entry.make_payment_entry() return payroll_entry diff --git a/erpnext/hr/doctype/process_payroll/__init__.py b/erpnext/hr/doctype/process_payroll/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/hr/doctype/process_payroll/process_payroll.js b/erpnext/hr/doctype/process_payroll/process_payroll.js deleted file mode 100644 index a9ad4293547..00000000000 --- a/erpnext/hr/doctype/process_payroll/process_payroll.js +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -var in_progress = false; - -frappe.ui.form.on("Process Payroll", { - onload: function (frm) { - frm.doc.posting_date = frappe.datetime.nowdate(); - frm.doc.start_date = ''; - frm.doc.end_date = ''; - frm.doc.payroll_frequency = ''; - frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet); - }, - - setup: function (frm) { - frm.set_query("payment_account", function () { - var account_types = ["Bank", "Cash"]; - return { - filters: { - "account_type": ["in", account_types], - "is_group": 0, - "company": frm.doc.company - } - } - }), - frm.set_query("cost_center", function () { - return { - filters: { - "is_group": 0, - company: frm.doc.company - } - } - }), - frm.set_query("project", function () { - return { - filters: { - company: frm.doc.company - } - } - }) - }, - - refresh: function (frm) { - frm.disable_save(); - }, - - payroll_frequency: function (frm) { - frm.trigger("set_start_end_dates"); - }, - - start_date: function (frm) { - if(!in_progress && frm.doc.start_date){ - frm.trigger("set_end_date"); - }else{ - // reset flag - in_progress = false - } - }, - - salary_slip_based_on_timesheet: function (frm) { - frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet); - }, - - payment_account: function (frm) { - frm.toggle_display(['make_bank_entry'], (frm.doc.payment_account != "" && frm.doc.payment_account != "undefined")); - }, - - set_start_end_dates: function (frm) { - if (!frm.doc.salary_slip_based_on_timesheet) { - frappe.call({ - method: 'erpnext.hr.doctype.process_payroll.process_payroll.get_start_end_dates', - args: { - payroll_frequency: frm.doc.payroll_frequency, - start_date: frm.doc.posting_date - }, - callback: function (r) { - if (r.message) { - in_progress = true; - frm.set_value('start_date', r.message.start_date); - frm.set_value('end_date', r.message.end_date); - } - } - }) - } - }, - - set_end_date: function(frm){ - frappe.call({ - method: 'erpnext.hr.doctype.process_payroll.process_payroll.get_end_date', - args: { - frequency: frm.doc.payroll_frequency, - start_date: frm.doc.start_date - }, - callback: function (r) { - if (r.message) { - frm.set_value('end_date', r.message.end_date); - } - } - }) - } -}) - -cur_frm.cscript.display_activity_log = function (msg) { - if (!cur_frm.ss_html) - cur_frm.ss_html = $a(cur_frm.fields_dict['activity_log'].wrapper, 'div'); - if (msg) { - cur_frm.ss_html.innerHTML = - '

' + __("Activity Log:") + '

' + msg + '
'; - } else { - cur_frm.ss_html.innerHTML = ""; - } -} - -// Create salary slip -// ----------------------- -cur_frm.cscript.create_salary_slip = function (doc, cdt, cdn) { - cur_frm.cscript.display_activity_log(""); - var callback = function (r, rt) { - if (r.message) - cur_frm.cscript.display_activity_log(r.message); - } - return $c('runserverobj', { 'method': 'create_salary_slips', 'docs': doc }, callback); -} - -cur_frm.cscript.submit_salary_slip = function (doc, cdt, cdn) { - cur_frm.cscript.display_activity_log(""); - - frappe.confirm(__("Do you really want to Submit all Salary Slip from {0} to {1}", [doc.start_date, doc.end_date]), function () { - // clear all in locals - if (locals["Salary Slip"]) { - $.each(locals["Salary Slip"], function (name, d) { - frappe.model.remove_from_locals("Salary Slip", name); - }); - } - - var callback = function (r, rt) { - if (r.message) - cur_frm.cscript.display_activity_log(r.message); - } - - return $c('runserverobj', { 'method': 'submit_salary_slips', 'docs': doc }, callback); - }); -} - -cur_frm.cscript.make_bank_entry = function (doc, cdt, cdn) { - if (doc.company && doc.start_date && doc.end_date) { - return frappe.call({ - doc: cur_frm.doc, - method: "make_payment_entry", - callback: function (r) { - if (r.message) - var doc = frappe.model.sync(r.message)[0]; - frappe.set_route("Form", doc.doctype, doc.name); - } - }); - } else { - frappe.msgprint(__("Company, From Date and To Date is mandatory")); - } -} \ No newline at end of file diff --git a/erpnext/hr/doctype/process_payroll/process_payroll.json b/erpnext/hr/doctype/process_payroll/process_payroll.json deleted file mode 100644 index 2b847b3ea78..00000000000 --- a/erpnext/hr/doctype/process_payroll/process_payroll.json +++ /dev/null @@ -1,843 +0,0 @@ -{ - "allow_copy": 1, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2012-03-27 14:35:59", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Other", - "editable_grid": 0, - "fields": [ - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break0", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Select Employees", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break0", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, - "width": "50%" - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 1, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Today", - "fieldname": "posting_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Posting Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "depends_on": "eval:doc.salary_slip_based_on_timesheet == 0", - "fieldname": "payroll_frequency", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Payroll Frequency", - "length": 0, - "no_copy": 0, - "options": "\nMonthly\nFortnightly\nBimonthly\nWeekly\nDaily", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, - "width": "50%" - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "branch", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Branch", - "length": 0, - "no_copy": 0, - "options": "Branch", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "department", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Department", - "length": 0, - "no_copy": 0, - "options": "Department", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "designation", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Designation", - "length": 0, - "no_copy": 0, - "options": "Designation", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_8", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "salary_slip_based_on_timesheet", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Salary Slip Based on Timesheet", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "select_payroll_period", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Select Payroll Period", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "start_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Start Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_11", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "end_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "End Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_16", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Accounts", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "cost_center", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Cost Center", - "length": 0, - "no_copy": 0, - "options": "Cost Center", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_18", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "project", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Project", - "length": 0, - "no_copy": 0, - "options": "Project", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "process_payroll", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Process Payroll", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, - "width": "50%" - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Creates salary slip for above mentioned criteria.", - "fieldname": "create_salary_slip", - "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Create Salary Slip", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, - "width": "25%" - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Submit all salary slips for the above selected criteria", - "fieldname": "submit_salary_slip", - "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Submit Salary Slip", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "account", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Payment Entry", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Select Payment Account to make Bank Entry", - "fieldname": "payment_account", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Payment Account", - "length": 0, - "no_copy": 0, - "options": "Account", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "description": "Create Bank Entry for the total salary paid for the above selected criteria", - "fieldname": "make_bank_entry", - "fieldtype": "Button", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Make Bank Entry", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break2", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "activity_log", - "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Activity Log", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "hide_heading": 0, - "hide_toolbar": 1, - "icon": "fa fa-cog", - "idx": 1, - "image_view": 0, - "in_create": 0, - "in_dialog": 0, - "is_submittable": 0, - "issingle": 1, - "istable": 0, - "max_attachments": 0, - "modified": "2017-02-08 02:34:59.130475", - "modified_by": "Administrator", - "module": "HR", - "name": "Process Payroll", - "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": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/hr/doctype/process_payroll/process_payroll.py b/erpnext/hr/doctype/process_payroll/process_payroll.py deleted file mode 100644 index f8ac044c800..00000000000 --- a/erpnext/hr/doctype/process_payroll/process_payroll.py +++ /dev/null @@ -1,453 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from dateutil.relativedelta import relativedelta -from frappe.utils import cint, flt, nowdate, add_days, getdate, fmt_money, add_to_date, DATE_FORMAT -from frappe import _ -from erpnext.accounts.utils import get_fiscal_year - -from frappe.model.document import Document - -class ProcessPayroll(Document): - def get_emp_list(self): - """ - Returns list of active employees based on selected criteria - and for which salary structure exists - """ - cond = self.get_filter_condition() - cond += self.get_joining_releiving_condition() - - - condition = '' - if self.payroll_frequency: - condition = """and payroll_frequency = '%(payroll_frequency)s'""" % {"payroll_frequency": self.payroll_frequency} - - sal_struct = frappe.db.sql(""" - select - name from `tabSalary Structure` - where - docstatus != 2 and - is_active = 'Yes' - and company = %(company)s and - ifnull(salary_slip_based_on_timesheet,0) = %(salary_slip_based_on_timesheet)s - {condition}""".format(condition=condition), - {"company": self.company, "salary_slip_based_on_timesheet":self.salary_slip_based_on_timesheet}) - - if sal_struct: - cond += "and t2.parent IN %(sal_struct)s " - emp_list = frappe.db.sql(""" - select - t1.name - from - `tabEmployee` t1, `tabSalary Structure Employee` t2 - where - t1.docstatus!=2 - and t1.name = t2.employee - %s """% cond, {"sal_struct": sal_struct}) - return emp_list - - def get_filter_condition(self): - self.check_mandatory() - - cond = '' - for f in ['company', 'branch', 'department', 'designation']: - if self.get(f): - cond += " and t1." + f + " = '" + self.get(f).replace("'", "\'") + "'" - - return cond - - def get_joining_releiving_condition(self): - cond = """ - and ifnull(t1.date_of_joining, '0000-00-00') <= '%(end_date)s' - and ifnull(t1.relieving_date, '2199-12-31') >= '%(start_date)s' - """ % {"start_date": self.start_date, "end_date": self.end_date} - return cond - - def check_mandatory(self): - for fieldname in ['company', 'start_date', 'end_date']: - if not self.get(fieldname): - frappe.throw(_("Please set {0}").format(self.meta.get_label(fieldname))) - - def create_salary_slips(self): - """ - Creates salary slip for selected employees if already not created - """ - self.check_permission('write') - - emp_list = self.get_emp_list() - ss_list = [] - if emp_list: - for emp in emp_list: - if not frappe.db.sql("""select - name from `tabSalary Slip` - where - docstatus!= 2 and - employee = %s and - start_date >= %s and - end_date <= %s and - company = %s - """, (emp[0], self.start_date, self.end_date, self.company)): - ss = frappe.get_doc({ - "doctype": "Salary Slip", - "salary_slip_based_on_timesheet": self.salary_slip_based_on_timesheet, - "payroll_frequency": self.payroll_frequency, - "start_date": self.start_date, - "end_date": self.end_date, - "employee": emp[0], - "employee_name": frappe.get_value("Employee", {"name":emp[0]}, "employee_name"), - "company": self.company, - "posting_date": self.posting_date - }) - ss.insert() - ss_dict = {} - ss_dict["Employee Name"] = ss.employee_name - ss_dict["Total Pay"] = fmt_money(ss.rounded_total,currency = frappe.defaults.get_global_default("currency")) - ss_dict["Salary Slip"] = self.format_as_links(ss.name)[0] - ss_list.append(ss_dict) - return self.create_log(ss_list) - - def create_log(self, ss_list): - if not ss_list or len(ss_list) < 1: - log = "

" + _("No employee for the above selected criteria OR salary slip already created") + "

" - else: - log = frappe.render_template("templates/includes/salary_slip_log.html", - dict(ss_list=ss_list, - keys=sorted(ss_list[0].keys()), - title=_('Created Salary Slips'))) - return log - - def get_sal_slip_list(self, ss_status, as_dict=False): - """ - Returns list of salary slips based on selected criteria - """ - cond = self.get_filter_condition() - - ss_list = frappe.db.sql(""" - select t1.name, t1.salary_structure from `tabSalary Slip` t1 - where t1.docstatus = %s and t1.start_date >= %s and t1.end_date <= %s - and (t1.journal_entry is null or t1.journal_entry = "") and ifnull(salary_slip_based_on_timesheet,0) = %s %s - """ % ('%s', '%s', '%s','%s', cond), (ss_status, self.start_date, self.end_date, self.salary_slip_based_on_timesheet), as_dict=as_dict) - return ss_list - - def submit_salary_slips(self): - """ - Submit all salary slips based on selected criteria - """ - self.check_permission('write') - jv_name = "" - ss_list = self.get_sal_slip_list(ss_status=0) - submitted_ss = [] - not_submitted_ss = [] - for ss in ss_list: - ss_obj = frappe.get_doc("Salary Slip",ss[0]) - ss_dict = {} - ss_dict["Employee Name"] = ss_obj.employee_name - ss_dict["Total Pay"] = fmt_money(ss_obj.net_pay, - currency = frappe.defaults.get_global_default("currency")) - ss_dict["Salary Slip"] = self.format_as_links(ss_obj.name)[0] - - if ss_obj.net_pay<0: - not_submitted_ss.append(ss_dict) - else: - try: - ss_obj.submit() - submitted_ss.append(ss_dict) - except frappe.ValidationError: - not_submitted_ss.append(ss_dict) - if submitted_ss: - jv_name = self.make_accural_jv_entry() - - return self.create_submit_log(submitted_ss, not_submitted_ss, jv_name) - - def create_submit_log(self, submitted_ss, not_submitted_ss, jv_name): - log = '' - if not submitted_ss and not not_submitted_ss: - log = "No salary slip found to submit for the above selected criteria" - - if submitted_ss: - log = frappe.render_template("templates/includes/salary_slip_log.html", - dict(ss_list=submitted_ss, - keys=sorted(submitted_ss[0].keys()), - title=_('Submitted Salary Slips'))) - if jv_name: - log += "" + _("Accural Journal Entry Submitted") + "\ - %s" % '
''{0}'.format(jv_name) - - if not_submitted_ss: - log += frappe.render_template("templates/includes/salary_slip_log.html", - dict(ss_list=not_submitted_ss, - keys=sorted(not_submitted_ss[0].keys()), - title=_('Not Submitted Salary Slips'))) - log += """ - Possible reasons:
\ - 1. Net pay is less than 0
- 2. Company Email Address specified in employee master is not valid.
- """ - return log - - def format_as_links(self, salary_slip): - return ['{0}'.format(salary_slip)] - - def get_loan_details(self): - """ - Get loan details from submitted salary slip based on selected criteria - """ - cond = self.get_filter_condition() - return frappe.db.sql(""" select eld.employee_loan_account, - eld.interest_income_account, eld.principal_amount, eld.interest_amount, eld.total_payment - from - `tabSalary Slip` t1, `tabSalary Slip Loan` eld - where - t1.docstatus = 1 and t1.name = eld.parent and start_date >= %s and end_date <= %s %s - """ % ('%s', '%s', cond), (self.start_date, self.end_date), as_dict=True) or [] - - def get_total_salary_amount(self): - """ - Get total salary amount from submitted salary slip based on selected criteria - """ - cond = self.get_filter_condition() - totals = frappe.db.sql(""" select sum(rounded_total) as rounded_total from `tabSalary Slip` t1 - where t1.docstatus = 1 and start_date >= %s and end_date <= %s %s - """ % ('%s', '%s', cond), (self.start_date, self.end_date), as_dict=True) - return totals and totals[0] or None - - def get_salary_component_account(self, salary_component): - account = frappe.db.get_value("Salary Component Account", - {"parent": salary_component, "company": self.company}, "default_account") - - if not account: - frappe.throw(_("Please set default account in Salary Component {0}") - .format(salary_component)) - - return account - - def get_salary_components(self, component_type): - salary_slips = self.get_sal_slip_list(ss_status = 1, as_dict = True) - if salary_slips: - salary_components = frappe.db.sql("""select salary_component, amount, parentfield - from `tabSalary Detail` where parentfield = '%s' and parent in (%s)""" % - (component_type, ', '.join(['%s']*len(salary_slips))), tuple([d.name for d in salary_slips]), as_dict=True) - return salary_components - - def get_salary_component_total(self, component_type = None): - salary_components = self.get_salary_components(component_type) - if salary_components: - component_dict = {} - for item in salary_components: - component_dict[item['salary_component']] = component_dict.get(item['salary_component'], 0) + item['amount'] - account_details = self.get_account(component_dict = component_dict) - return account_details - - def get_account(self, component_dict = None): - account_dict = {} - for s, a in component_dict.items(): - account = self.get_salary_component_account(s) - account_dict[account] = account_dict.get(account, 0) + a - return account_dict - - def get_default_payroll_payable_account(self): - payroll_payable_account = frappe.db.get_value("Company", - {"company_name": self.company}, "default_payroll_payable_account") - - if not payroll_payable_account: - frappe.throw(_("Please set Default Payroll Payable Account in Company {0}") - .format(self.company)) - - return payroll_payable_account - - def make_accural_jv_entry(self): - self.check_permission('write') - earnings = self.get_salary_component_total(component_type = "earnings") or {} - deductions = self.get_salary_component_total(component_type = "deductions") or {} - default_payroll_payable_account = self.get_default_payroll_payable_account() - loan_details = self.get_loan_details() - jv_name = "" - precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency") - - if earnings or deductions: - journal_entry = frappe.new_doc('Journal Entry') - journal_entry.voucher_type = 'Journal Entry' - journal_entry.user_remark = _('Accural Journal Entry for salaries from {0} to {1}')\ - .format(self.start_date, self.end_date) - journal_entry.company = self.company - journal_entry.posting_date = nowdate() - - accounts = [] - payable_amount = 0 - - # Earnings - for acc, amount in earnings.items(): - payable_amount += flt(amount, precision) - accounts.append({ - "account": acc, - "debit_in_account_currency": flt(amount, precision), - "cost_center": self.cost_center, - "project": self.project - }) - - # Deductions - for acc, amount in deductions.items(): - payable_amount -= flt(amount, precision) - accounts.append({ - "account": acc, - "credit_in_account_currency": flt(amount, precision), - "cost_center": self.cost_center, - "project": self.project - }) - - # Employee loan - for data in loan_details: - accounts.append({ - "account": data.employee_loan_account, - "credit_in_account_currency": data.principal_amount - }) - accounts.append({ - "account": data.interest_income_account, - "credit_in_account_currency": data.interest_amount, - "cost_center": self.cost_center, - "project": self.project - }) - payable_amount -= flt(data.total_payment, precision) - - # Payable amount - accounts.append({ - "account": default_payroll_payable_account, - "credit_in_account_currency": flt(payable_amount, precision) - }) - - journal_entry.set("accounts", accounts) - journal_entry.save() - - try: - journal_entry.submit() - jv_name = journal_entry.name - self.update_salary_slip_status(jv_name = jv_name) - except Exception as e: - frappe.msgprint(e) - - return jv_name - - def make_payment_entry(self): - self.check_permission('write') - total_salary_amount = self.get_total_salary_amount() - default_payroll_payable_account = self.get_default_payroll_payable_account() - precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency") - - if total_salary_amount and total_salary_amount.rounded_total: - journal_entry = frappe.new_doc('Journal Entry') - journal_entry.voucher_type = 'Bank Entry' - journal_entry.user_remark = _('Payment of salary from {0} to {1}')\ - .format(self.start_date, self.end_date) - journal_entry.company = self.company - journal_entry.posting_date = nowdate() - - payment_amount = flt(total_salary_amount.rounded_total, precision) - - journal_entry.set("accounts", [ - { - "account": self.payment_account, - "credit_in_account_currency": payment_amount - }, - { - "account": default_payroll_payable_account, - "debit_in_account_currency": payment_amount - } - ]) - return journal_entry.as_dict() - else: - frappe.msgprint( - _("There are no submitted Salary Slips to process."), - title="Error", indicator="red" - ) - - def update_salary_slip_status(self, jv_name = None): - ss_list = self.get_sal_slip_list(ss_status=1) - for ss in ss_list: - ss_obj = frappe.get_doc("Salary Slip",ss[0]) - frappe.db.set_value("Salary Slip", ss_obj.name, "status", "Paid") - frappe.db.set_value("Salary Slip", ss_obj.name, "journal_entry", jv_name) - - def set_start_end_dates(self): - self.update(get_start_end_dates(self.payroll_frequency, - self.start_date or self.posting_date, self.company)) - -@frappe.whitelist() -def get_start_end_dates(payroll_frequency, start_date=None, company=None): - '''Returns dict of start and end dates for given payroll frequency based on start_date''' - - if payroll_frequency == "Monthly" or payroll_frequency == "Bimonthly" or payroll_frequency == "": - fiscal_year = get_fiscal_year(start_date, company=company)[0] - month = "%02d" % getdate(start_date).month - m = get_month_details(fiscal_year, month) - if payroll_frequency == "Bimonthly": - if getdate(start_date).day <= 15: - start_date = m['month_start_date'] - end_date = m['month_mid_end_date'] - else: - start_date = m['month_mid_start_date'] - end_date = m['month_end_date'] - else: - start_date = m['month_start_date'] - end_date = m['month_end_date'] - - if payroll_frequency == "Weekly": - end_date = add_days(start_date, 6) - - if payroll_frequency == "Fortnightly": - end_date = add_days(start_date, 13) - - if payroll_frequency == "Daily": - end_date = start_date - - return frappe._dict({ - 'start_date': start_date, 'end_date': end_date - }) - -def get_frequency_kwargs(frequency_name): - frequency_dict = { - 'monthly': {'months': 1}, - 'fortnightly': {'days': 14}, - 'weekly': {'days': 7}, - 'daily': {'days': 1} - } - return frequency_dict.get(frequency_name) - -@frappe.whitelist() -def get_end_date(start_date, frequency): - start_date = getdate(start_date) - frequency = frequency.lower() if frequency else 'monthly' - kwargs = get_frequency_kwargs(frequency) if frequency != 'bimonthly' else get_frequency_kwargs('monthly') - - # weekly, fortnightly and daily intervals have fixed days so no problems - end_date = add_to_date(start_date, **kwargs) - relativedelta(days=1) - if frequency != 'bimonthly': - return dict(end_date=end_date.strftime(DATE_FORMAT)) - - else: - return dict(end_date='') - -def get_month_details(year, month): - ysd = frappe.db.get_value("Fiscal Year", year, "year_start_date") - if ysd: - from dateutil.relativedelta import relativedelta - import calendar, datetime - diff_mnt = cint(month)-cint(ysd.month) - if diff_mnt<0: - diff_mnt = 12-int(ysd.month)+cint(month) - msd = ysd + relativedelta(months=diff_mnt) # month start date - month_days = cint(calendar.monthrange(cint(msd.year) ,cint(month))[1]) # days in month - mid_start = datetime.date(msd.year, cint(month), 16) # month mid start date - mid_end = datetime.date(msd.year, cint(month), 15) # month mid end date - med = datetime.date(msd.year, cint(month), month_days) # month end date - return frappe._dict({ - 'year': msd.year, - 'month_start_date': msd, - 'month_end_date': med, - 'month_mid_start_date': mid_start, - 'month_mid_end_date': mid_end, - 'month_days': month_days - }) - else: - frappe.throw(_("Fiscal Year {0} not found").format(year)) diff --git a/erpnext/hr/doctype/process_payroll/test_process_payroll.js b/erpnext/hr/doctype/process_payroll/test_process_payroll.js deleted file mode 100644 index bc611504636..00000000000 --- a/erpnext/hr/doctype/process_payroll/test_process_payroll.js +++ /dev/null @@ -1,59 +0,0 @@ -QUnit.module('hr'); - -QUnit.test("Test: Process Payroll [HR]", function (assert) { - assert.expect(5); - let done = assert.async(); - let net_pay; - - let check_amounts = (employee_name,net_amt,gross_amt) => { - frappe.run_serially([ - // Retrieving the actual amount from salary slip - () => frappe.db.get_value('Salary Slip', {'employee_name': employee_name}, 'net_pay'), - (r) => { - net_pay=r.message.net_pay; - }, - () => frappe.db.get_value('Salary Slip', {'employee_name': employee_name}, 'gross_pay'), - - // Checking if amounts are correctly calculated - (r) => { - assert.ok(net_pay==net_amt, - 'Net Pay is correctly calculated for '+employee_name); - assert.ok(r.message.gross_pay==gross_amt, - 'Gross Pay is correctly calculated for '+employee_name); - }, - ]); - }; - frappe.run_serially([ - - // Deleting the already generated Salary Slips for employees - () => frappe.set_route('List','Salary Slip'), - () => frappe.timeout(2), - () => { $('input.list-row-checkbox').click();}, - () => frappe.click_button('Delete'), - () => frappe.click_button('Yes'), - () => frappe.timeout(2), - () => assert.ok(cur_list.data.length==0,"Salary Slips successfully deleted"), - () => frappe.timeout(3), - - - // Creating Process Payroll for specific company - () => frappe.set_route('Form','Process Payroll'), - () => { - cur_frm.set_value('company','For Testing'), - frappe.timeout(1), - cur_frm.set_value('payroll_frequency','Monthly'), - cur_frm.set_value('start_date','2017-08-01'), - frappe.timeout(1), - cur_frm.set_value('end_date','2017-08-31'), - cur_frm.set_value('cost_center','Main-TC'), - frappe.timeout(1), - frappe.click_button('Create Salary Slip'); - }, - () => frappe.timeout(3), - () => check_amounts('Test Employee 1','19200','24000'), - () => frappe.timeout(3), - () => check_amounts('Test Employee 3','23040','28800'), - () => frappe.timeout(4), - () => done() - ]); -}); diff --git a/erpnext/hr/doctype/process_payroll/test_process_payroll.py b/erpnext/hr/doctype/process_payroll/test_process_payroll.py deleted file mode 100644 index 91b60b4e680..00000000000 --- a/erpnext/hr/doctype/process_payroll/test_process_payroll.py +++ /dev/null @@ -1,195 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals - -import unittest - -import erpnext -import frappe -from dateutil.relativedelta import relativedelta -from erpnext.accounts.utils import get_fiscal_year, getdate, nowdate -from erpnext.hr.doctype.process_payroll.process_payroll import get_start_end_dates, get_end_date - -class TestProcessPayroll(unittest.TestCase): - def test_process_payroll(self): - month = "11" - fiscal_year = "_Test Fiscal Year 2016" - - for data in frappe.get_all('Salary Component', fields = ["name"]): - if not frappe.db.get_value('Salary Component Account', - {'parent': data.name, 'company': erpnext.get_default_company()}, 'name'): - get_salary_component_account(data.name) - - if not frappe.db.get_value("Salary Slip", {"start_date": "2016-11-01", "end_date": "2016-11-30"}): - make_process_payroll() - - def test_get_end_date(self): - self.assertEqual(get_end_date('2017-01-01', 'monthly'), {'end_date': '2017-01-31'}) - self.assertEqual(get_end_date('2017-02-01', 'monthly'), {'end_date': '2017-02-28'}) - self.assertEqual(get_end_date('2017-02-01', 'fortnightly'), {'end_date': '2017-02-14'}) - self.assertEqual(get_end_date('2017-02-01', 'bimonthly'), {'end_date': ''}) - self.assertEqual(get_end_date('2017-01-01', 'bimonthly'), {'end_date': ''}) - self.assertEqual(get_end_date('2020-02-15', 'bimonthly'), {'end_date': ''}) - self.assertEqual(get_end_date('2017-02-15', 'monthly'), {'end_date': '2017-03-14'}) - self.assertEqual(get_end_date('2017-02-15', 'daily'), {'end_date': '2017-02-15'}) - - def test_employee_loan(self): - from erpnext.hr.doctype.salary_structure.test_salary_structure import (make_employee, - make_salary_structure) - from erpnext.hr.doctype.employee_loan.test_employee_loan import create_employee_loan - - branch = "Test Employee Branch" - employee = make_employee("test_employee@loan.com") - company = erpnext.get_default_company() - holiday_list = make_holiday("test holiday for loan") - - if not frappe.db.exists('Salary Component', 'Basic Salary'): - frappe.get_doc({ - 'doctype': 'Salary Component', - 'salary_component': 'Basic Salary', - 'salary_component_abbr': 'BS', - 'type': 'Earning', - 'accounts': [{ - 'company': company, - 'default_account': frappe.db.get_value('Account', - {'company': company, 'root_type': 'Expense', 'account_type': ''}, 'name') - }] - }).insert() - - if not frappe.db.get_value('Salary Component Account', - {'parent': 'Basic Salary', 'company': company}): - salary_component = frappe.get_doc('Salary Component', 'Basic Salary') - salary_component.append('accounts', { - 'company': company, - 'default_account': 'Salary - WP' - }) - - company_doc = frappe.get_doc('Company', company) - if not company_doc.default_payroll_payable_account: - company_doc.default_payroll_payable_account = frappe.db.get_value('Account', - {'company': company, 'root_type': 'Liability', 'account_type': ''}, 'name') - company_doc.save() - - if not frappe.db.exists('Branch', branch): - frappe.get_doc({ - 'doctype': 'Branch', - 'branch': branch - }).insert() - - employee_doc = frappe.get_doc('Employee', employee) - employee_doc.branch = branch - employee_doc.holiday_list = holiday_list - employee_doc.save() - - employee_loan = create_employee_loan(employee, - "Personal Loan", 280000, "Repay Over Number of Periods", 20) - employee_loan.repay_from_salary = 1 - employee_loan.submit() - - salary_strcture = "Test Salary Structure for Loan" - if not frappe.db.exists('Salary Structure', salary_strcture): - salary_strcture = make_salary_structure(salary_strcture, [{ - 'employee': employee, - 'from_date': '2017-01-01', - 'base': 30000 - }]) - - salary_strcture = frappe.get_doc('Salary Structure', salary_strcture) - salary_strcture.set('earnings', [{ - 'salary_component': 'Basic Salary', - 'abbr': 'BS', - 'amount_based_on_formula':1, - 'formula': 'base*.5' - }]) - salary_strcture.save() - - dates = get_start_end_dates('Monthly', nowdate()) - make_process_payroll(start_date=dates.start_date, - end_date=dates.end_date, branch=branch) - - name = frappe.db.get_value('Salary Slip', - {'posting_date': nowdate(), 'employee': employee}, 'name') - - salary_slip = frappe.get_doc('Salary Slip', name) - for row in salary_slip.loans: - if row.employee_loan == employee_loan.name: - interest_amount = (280000 * 8.4)/(12*100) - principal_amount = employee_loan.monthly_repayment_amount - interest_amount - self.assertEqual(row.interest_amount, interest_amount) - self.assertEqual(row.principal_amount, principal_amount) - self.assertEqual(row.total_payment, - interest_amount + principal_amount) - - if salary_slip.docstatus == 0: - frappe.delete_doc('Salary Slip', name) - - employee_loan.cancel() - frappe.delete_doc('Employee Loan', employee_loan.name) - -def get_salary_component_account(sal_comp): - company = erpnext.get_default_company() - sal_comp = frappe.get_doc("Salary Component", sal_comp) - sc = sal_comp.append("accounts") - sc.company = company - sc.default_account = create_account(company) - -def create_account(company): - salary_account = frappe.db.get_value("Account", "Salary - " + frappe.db.get_value('Company', company, 'abbr')) - if not salary_account: - frappe.get_doc({ - "doctype": "Account", - "account_name": "Salary", - "parent_account": "Indirect Expenses - " + frappe.db.get_value('Company', company, 'abbr'), - "company": company - }).insert() - return salary_account - -def make_process_payroll(**args): - args = frappe._dict(args) - - process_payroll = frappe.get_doc("Process Payroll", "Process Payroll") - process_payroll.company = erpnext.get_default_company() - process_payroll.start_date = args.start_date or "2016-11-01" - process_payroll.end_date = args.end_date or "2016-11-30" - process_payroll.payment_account = get_payment_account() - process_payroll.posting_date = nowdate() - process_payroll.payroll_frequency = "Monthly" - process_payroll.branch = args.branch or None - process_payroll.create_salary_slips() - process_payroll.submit_salary_slips() - if process_payroll.get_sal_slip_list(ss_status = 1): - r = process_payroll.make_payment_entry() - - return process_payroll - -def get_payment_account(): - return frappe.get_value('Account', - {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name") - -def make_holiday(holiday_list_name): - if not frappe.db.exists('Holiday List', holiday_list_name): - current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True) - dt = getdate(nowdate()) - - new_year = dt + relativedelta(month=01, day=01, year=dt.year) - republic_day = dt + relativedelta(month=01, day=26, year=dt.year) - test_holiday = dt + relativedelta(month=02, day=02, year=dt.year) - - frappe.get_doc({ - 'doctype': 'Holiday List', - 'from_date': current_fiscal_year.year_start_date, - 'to_date': current_fiscal_year.year_end_date, - 'holiday_list_name': holiday_list_name, - 'holidays': [{ - 'holiday_date': new_year, - 'description': 'New Year' - }, { - 'holiday_date': republic_day, - 'description': 'Republic Day' - }, { - 'holiday_date': test_holiday, - 'description': 'Test Holiday' - }] - }).insert() - - return holiday_list_name diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 54f4dfd13fa..1755ec0329c 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -475,3 +475,4 @@ erpnext.patches.v9_2.remove_company_from_patient erpnext.patches.v9_2.set_item_name_in_production_order erpnext.patches.v10_0.update_lft_rgt_for_employee erpnext.patches.v9_2.rename_net_weight_in_item_master +erpnext.patches.v9_2.delete_process_payroll diff --git a/erpnext/patches/v7_2/update_salary_slips.py b/erpnext/patches/v7_2/update_salary_slips.py index b7a405043e0..22bb1d82dc9 100644 --- a/erpnext/patches/v7_2/update_salary_slips.py +++ b/erpnext/patches/v7_2/update_salary_slips.py @@ -1,5 +1,5 @@ import frappe -from erpnext.hr.doctype.process_payroll.process_payroll import get_month_details +from erpnext.hr.doctype.payroll_entry.payroll_entry import get_month_details from frappe.utils import cint def execute(): diff --git a/erpnext/patches/v9_2/delete_process_payroll.py b/erpnext/patches/v9_2/delete_process_payroll.py new file mode 100644 index 00000000000..e9e1b99c06c --- /dev/null +++ b/erpnext/patches/v9_2/delete_process_payroll.py @@ -0,0 +1,4 @@ +import frappe + +def execute(): + frappe.delete_doc("DocType", "Process Payroll") diff --git a/erpnext/tests/ui/tests.txt b/erpnext/tests/ui/tests.txt index b760e980068..9040b120545 100644 --- a/erpnext/tests/ui/tests.txt +++ b/erpnext/tests/ui/tests.txt @@ -64,7 +64,6 @@ erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_receipt.js erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_transfer.js erpnext/hr/doctype/salary_structure/test_salary_structure.js erpnext/hr/doctype/salary_slip/test_salary_slip.js -erpnext/hr/doctype/process_payroll/test_process_payroll.js erpnext/hr/doctype/job_opening/test_job_opening.js erpnext/hr/doctype/job_applicant/test_job_applicant.js erpnext/hr/doctype/offer_letter/test_offer_letter.js