diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json index 48d5ed2ca9..2954f72fdc 100644 --- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json +++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json @@ -618,7 +618,7 @@ "label": "Reference Type", "length": 0, "no_copy": 0, - "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nEmployee Loan", + "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nEmployee Loan\nPayroll Entry", "permlevel": 0, "precision": "", "print_hide": 0, @@ -827,7 +827,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-30 08:44:54.295493", + "modified": "2017-12-06 19:54:19.851534", "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry Account", diff --git a/erpnext/demo/user/hr.py b/erpnext/demo/user/hr.py index 1570df5963..504478a241 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/process_payroll/__init__.py b/erpnext/hr/doctype/payroll_employee_detail/__init__.py similarity index 100% rename from erpnext/hr/doctype/process_payroll/__init__.py rename to erpnext/hr/doctype/payroll_employee_detail/__init__.py diff --git a/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.json b/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.json new file mode 100644 index 0000000000..953cffae21 --- /dev/null +++ b/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.json @@ -0,0 +1,194 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2017-11-30 06:07:33.477781", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "employee", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Employee", + "length": 0, + "no_copy": 0, + "options": "Employee", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "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, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "employee_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Employee Name", + "length": 0, + "no_copy": 0, + "options": "employee.employee_name", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "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, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "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, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "department", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Department", + "length": 0, + "no_copy": 0, + "options": "employee.department", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "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, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "designation", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Designation", + "length": 0, + "no_copy": 0, + "options": "employee.designation", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2017-11-30 18:25:34.967999", + "modified_by": "Administrator", + "module": "HR", + "name": "Payroll Employee Detail", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 1, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.py b/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.py new file mode 100644 index 0000000000..aeb11fd7e2 --- /dev/null +++ b/erpnext/hr/doctype/payroll_employee_detail/payroll_employee_detail.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +from frappe.model.document import Document + +class PayrollEmployeeDetail(Document): + pass diff --git a/erpnext/hr/doctype/payroll_entry/__init__.py b/erpnext/hr/doctype/payroll_entry/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.js b/erpnext/hr/doctype/payroll_entry/payroll_entry.js new file mode 100644 index 0000000000..a26283d9a6 --- /dev/null +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.js @@ -0,0 +1,164 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +var in_progress = false; + +frappe.ui.form.on('Payroll Entry', { + onload: function (frm) { + frm.doc.posting_date = frappe.datetime.nowdate(); + frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet); + }, + + refresh: function(frm) { + if (frm.doc.docstatus==1) { + if(frm.doc.payment_account) { + frm.add_custom_button("Make Bank Entry", function() { + make_bank_entry(frm); + }); + } + + frm.add_custom_button("Submit Salary Slip", function() { + submit_salary_slip(frm); + }); + + frm.add_custom_button("View Salary Slip", function() { + frappe.set_route('List', 'Salary Slip', + {posting_date: frm.doc.posting_date}); + }); + } + }, + + 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 + } + }; + }); + }, + + 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) { + if(!in_progress && frm.doc.start_date){ + frm.trigger("set_end_date"); + }else{ + // reset flag + in_progress = false; + } + frm.set_value('employees', []); + }, + + project: function (frm) { + frm.set_value('employees', []); + }, + + salary_slip_based_on_timesheet: function (frm) { + frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet); + }, + + set_start_end_dates: function (frm) { + if (!frm.doc.salary_slip_based_on_timesheet) { + frappe.call({ + method: 'erpnext.hr.doctype.payroll_entry.payroll_entry.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.payroll_entry.payroll_entry.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); + } + } + }); + }, +}); + +// Submit salary slips + +let submit_salary_slip = function (frm) { + var doc = frm.doc; + return $c('runserverobj', { 'method': 'submit_salary_slips', 'docs': doc }); +}; + +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); +}; + +let make_bank_entry = function (frm) { + var doc = frm.doc; + 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")); + } +}; diff --git a/erpnext/hr/doctype/process_payroll/process_payroll.json b/erpnext/hr/doctype/payroll_entry/payroll_entry.json similarity index 84% rename from erpnext/hr/doctype/process_payroll/process_payroll.json rename to erpnext/hr/doctype/payroll_entry/payroll_entry.json index 2b847b3ea7..5cd1e53a6d 100644 --- a/erpnext/hr/doctype/process_payroll/process_payroll.json +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.json @@ -1,16 +1,20 @@ { "allow_copy": 1, + "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, + "autoname": "Payroll .####", "beta": 0, - "creation": "2012-03-27 14:35:59", + "creation": "2017-10-23 15:22:29.291323", "custom": 0, "docstatus": 0, "doctype": "DocType", "document_type": "Other", "editable_grid": 0, + "engine": "InnoDB", "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -20,12 +24,15 @@ "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, "label": "Select Employees", "length": 0, "no_copy": 0, "permlevel": 0, + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -37,6 +44,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -46,11 +54,14 @@ "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, @@ -63,6 +74,7 @@ "width": "50%" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -73,6 +85,8 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 0, "label": "Company", @@ -80,6 +94,7 @@ "no_copy": 0, "options": "Company", "permlevel": 0, + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -91,6 +106,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,6 +117,8 @@ "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, "label": "Posting Date", @@ -119,6 +137,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -130,6 +149,8 @@ "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, "label": "Payroll Frequency", @@ -149,6 +170,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -158,11 +180,14 @@ "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, @@ -175,6 +200,7 @@ "width": "50%" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -184,6 +210,8 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 0, "label": "Branch", @@ -191,6 +219,7 @@ "no_copy": 0, "options": "Branch", "permlevel": 0, + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -202,6 +231,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -211,6 +241,8 @@ "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, "label": "Department", @@ -218,6 +250,7 @@ "no_copy": 0, "options": "Department", "permlevel": 0, + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -229,6 +262,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -238,6 +272,8 @@ "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, "label": "Designation", @@ -245,6 +281,7 @@ "no_copy": 0, "options": "Designation", "permlevel": 0, + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -256,6 +293,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -265,6 +303,8 @@ "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, @@ -282,20 +322,115 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fieldname": "get_employee_details", + "fieldtype": "Button", + "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, + "label": "Get Employee Details", + "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, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "employees", + "fieldtype": "Table", + "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, + "label": "Employees", + "length": 0, + "no_copy": 0, + "options": "Payroll Employee Detail", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "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, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_12", + "fieldtype": "Section Break", + "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, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0", "fieldname": "salary_slip_based_on_timesheet", "fieldtype": "Check", "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, "label": "Salary Slip Based on Timesheet", "length": 0, "no_copy": 0, + "options": "", "permlevel": 0, "precision": "", "print_hide": 0, @@ -309,6 +444,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -318,6 +454,8 @@ "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, "label": "Select Payroll Period", @@ -336,6 +474,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -346,6 +485,8 @@ "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, "label": "Start Date", @@ -358,12 +499,13 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -373,6 +515,8 @@ "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, @@ -390,6 +534,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -400,6 +545,8 @@ "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, "label": "End Date", @@ -412,12 +559,13 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -427,6 +575,8 @@ "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, "label": "Accounts", @@ -445,6 +595,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -454,6 +605,8 @@ "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, "label": "Cost Center", @@ -473,6 +626,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -482,6 +636,8 @@ "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, @@ -499,6 +655,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -508,6 +665,8 @@ "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, "label": "Project", @@ -527,18 +686,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "process_payroll", - "fieldtype": "Section Break", + "fieldname": "column_break2", + "fieldtype": "Column Break", "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, - "label": "Process Payroll", "length": 0, "no_copy": 0, "permlevel": 0, @@ -551,115 +712,11 @@ "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_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -669,6 +726,8 @@ "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, "label": "Payment Entry", @@ -687,7 +746,8 @@ "unique": 0 }, { - "allow_on_submit": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, @@ -697,6 +757,8 @@ "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, "label": "Payment Account", @@ -716,34 +778,7 @@ "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_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -753,11 +788,14 @@ "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, @@ -769,6 +807,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -778,12 +817,15 @@ "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, "label": "Activity Log", "length": 0, "no_copy": 0, "permlevel": 0, + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -793,31 +835,62 @@ "search_index": 0, "set_only_once": 0, "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amended_from", + "fieldtype": "Link", + "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, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Payroll Entry", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, - "hide_toolbar": 1, + "hide_toolbar": 0, "icon": "fa fa-cog", - "idx": 1, + "idx": 0, "image_view": 0, "in_create": 0, - "in_dialog": 0, - "is_submittable": 0, - "issingle": 1, + "is_submittable": 1, + "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-02-08 02:34:59.130475", + "modified": "2017-12-06 19:47:03.235021", "modified_by": "Administrator", "module": "HR", - "name": "Process Payroll", + "name": "Payroll Entry", + "name_case": "", "owner": "Administrator", "permissions": [ { "amend": 0, "apply_user_permissions": 0, - "cancel": 0, + "cancel": 1, "create": 1, - "delete": 0, + "delete": 1, "email": 0, "export": 0, "if_owner": 0, @@ -829,13 +902,14 @@ "role": "HR Manager", "set_user_permissions": 0, "share": 1, - "submit": 0, + "submit": 1, "write": 1 } ], "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 0, diff --git a/erpnext/hr/doctype/process_payroll/process_payroll.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py similarity index 84% rename from erpnext/hr/doctype/process_payroll/process_payroll.py rename to erpnext/hr/doctype/payroll_entry/payroll_entry.py index f8ac044c80..db423399dc 100644 --- a/erpnext/hr/doctype/process_payroll/process_payroll.py +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py @@ -1,16 +1,20 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt from __future__ import unicode_literals import frappe +from frappe.model.document import Document 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 PayrollEntry(Document): + + def on_submit(self): + self.create_salary_slips() -class ProcessPayroll(Document): def get_emp_list(self): """ Returns list of active employees based on selected criteria @@ -22,7 +26,7 @@ class ProcessPayroll(Document): condition = '' if self.payroll_frequency: - condition = """and payroll_frequency = '%(payroll_frequency)s'""" % {"payroll_frequency": self.payroll_frequency} + condition = """and payroll_frequency = '%(payroll_frequency)s'"""% {"payroll_frequency": self.payroll_frequency} sal_struct = frappe.db.sql(""" select @@ -39,15 +43,24 @@ class ProcessPayroll(Document): cond += "and t2.parent IN %(sal_struct)s " emp_list = frappe.db.sql(""" select - t1.name + t1.name as employee, t1.employee_name, t1.department, t1.designation from `tabEmployee` t1, `tabSalary Structure Employee` t2 where t1.docstatus!=2 and t1.name = t2.employee - %s """% cond, {"sal_struct": sal_struct}) + %s """% cond, {"sal_struct": sal_struct}, as_dict=True) return emp_list + def fill_employee_details(self): + self.set('employees', []) + employees = self.get_emp_list() + if not employees: + frappe.throw(_("No employees for the mentioned criteria")) + + for d in employees: + self.append('employees', d) + def get_filter_condition(self): self.check_mandatory() @@ -75,7 +88,7 @@ class ProcessPayroll(Document): Creates salary slip for selected employees if already not created """ self.check_permission('write') - + self.created = 1; emp_list = self.get_emp_list() ss_list = [] if emp_list: @@ -88,15 +101,15 @@ class ProcessPayroll(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 }) @@ -104,19 +117,9 @@ class ProcessPayroll(Document): 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_dict["Salary Slip"] = 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 + return create_log(ss_list) def get_sal_slip_list(self, ss_status, as_dict=False): """ @@ -136,6 +139,9 @@ class ProcessPayroll(Document): Submit all salary slips based on selected criteria """ self.check_permission('write') + + # self.create_salary_slips() + jv_name = "" ss_list = self.get_sal_slip_list(ss_status=0) submitted_ss = [] @@ -145,50 +151,24 @@ class ProcessPayroll(Document): 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] - + currency = frappe.defaults.get_global_default("currency")) + ss_dict["Salary Slip"] = 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() + jv_name = self.make_accural_jv_entry() + frappe.msgprint(_("Salary Slip submitted for period from {0} to {1}") + .format(ss_obj.start_date, ss_obj.end_date)) - 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)] + return create_submit_log(submitted_ss, not_submitted_ss, jv_name) def get_loan_details(self): """ @@ -246,7 +226,7 @@ class ProcessPayroll(Document): 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") @@ -255,7 +235,7 @@ class ProcessPayroll(Document): frappe.throw(_("Please set Default Payroll Payable Account in Company {0}") .format(self.company)) - return payroll_payable_account + return payroll_payable_account def make_accural_jv_entry(self): self.check_permission('write') @@ -352,7 +332,9 @@ class ProcessPayroll(Document): }, { "account": default_payroll_payable_account, - "debit_in_account_currency": payment_amount + "debit_in_account_currency": payment_amount, + "reference_type": self.doctype, + "reference_name": self.name } ]) return journal_entry.as_dict() @@ -370,7 +352,7 @@ class ProcessPayroll(Document): 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.update(get_start_end_dates(self.payroll_frequency, self.start_date or self.posting_date, self.company)) @frappe.whitelist() @@ -431,7 +413,6 @@ def get_end_date(start_date, frequency): 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: @@ -451,3 +432,23 @@ def get_month_details(year, month): }) else: frappe.throw(_("Fiscal Year {0} not found").format(year)) + +@frappe.whitelist() +def create_log(ss_list): + if not ss_list or len(ss_list) < 1: + frappe.throw(_("No employee for the above selected criteria OR salary slip already created")) + return ss_list + +def format_as_links(salary_slip): + return ['{0}'.format(salary_slip)] + +def create_submit_log(submitted_ss, not_submitted_ss, jv_name): + + if not submitted_ss and not not_submitted_ss: + frappe.msgprint("No salary slip found to submit for the above selected criteria OR salary slip already submitted") + + if not_submitted_ss: + frappe.msgprint("Could not submit any Salary Slip
\ + Possible reasons:
\ + 1. Net pay is less than 0.
\ + 2. Company Email Address specified in employee master is not valid.
") \ No newline at end of file diff --git a/erpnext/hr/doctype/payroll_entry/test_payroll_entry.js b/erpnext/hr/doctype/payroll_entry/test_payroll_entry.js new file mode 100644 index 0000000000..5eee3fdc25 --- /dev/null +++ b/erpnext/hr/doctype/payroll_entry/test_payroll_entry.js @@ -0,0 +1,49 @@ +QUnit.module('HR'); + +QUnit.test("test: Payroll Entry", function (assert) { + assert.expect(5); + let done = assert.async(); + + frappe.run_serially([ + () => { + return frappe.tests.make('Payroll Entry', [ + {company: 'For Testing'}, + {posting_date: frappe.datetime.add_days(frappe.datetime.nowdate(), 0)}, + {payroll_frequency: 'Monthly'}, + {cost_center: 'Main - '+frappe.get_abbr(frappe.defaults.get_default("Company"))} + ]); + }, + + () => frappe.timeout(1), + () => { + assert.equal(cur_frm.doc.company, 'For Testing'); + assert.equal(cur_frm.doc.posting_date, frappe.datetime.add_days(frappe.datetime.nowdate(), 0)); + assert.equal(cur_frm.doc.cost_center, 'Main - FT'); + }, + + () => frappe.click_button('Submit'), + () => frappe.timeout(1), + () => frappe.click_button('Yes'), + () => frappe.timeout(2), + + () => frappe.click_button('View Salary Slip'), + () => frappe.timeout(2), + () => assert.equal(cur_list.data[0].docstatus, 0), + + () => frappe.set_route('Form', 'Payroll Entry', 'Payroll 0001'), + () => frappe.timeout(2), + () => frappe.click_button('Submit Salary Slip'), + () => frappe.timeout(3), + + () => frappe.click_button('Close'), + () => frappe.timeout(1), + + () => frappe.click_button('View Salary Slip'), + () => frappe.timeout(2), + () => { + assert.ok(cur_list.data[0].docstatus == 1, "Salary slip submitted"); + }, + + () => done() + ]); +}); diff --git a/erpnext/hr/doctype/process_payroll/test_process_payroll.py b/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py similarity index 86% rename from erpnext/hr/doctype/process_payroll/test_process_payroll.py rename to erpnext/hr/doctype/payroll_entry/test_payroll_entry.py index 91b60b4e68..21b0d58a22 100644 --- a/erpnext/hr/doctype/process_payroll/test_process_payroll.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.process_payroll.process_payroll import get_start_end_dates, get_end_date +from erpnext.hr.doctype.payroll_entry.payroll_entry 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" +class TestPayrollEntry(unittest.TestCase): + def test_payroll_entry(self): # pylint: disable=no-self-use for data in frappe.get_all('Salary Component', fields = ["name"]): if not frappe.db.get_value('Salary Component Account', @@ -21,7 +17,7 @@ class TestProcessPayroll(unittest.TestCase): 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() + make_payroll_entry() def test_get_end_date(self): self.assertEqual(get_end_date('2017-01-01', 'monthly'), {'end_date': '2017-01-31'}) @@ -104,7 +100,7 @@ class TestProcessPayroll(unittest.TestCase): salary_strcture.save() dates = get_start_end_dates('Monthly', nowdate()) - make_process_payroll(start_date=dates.start_date, + make_payroll_entry(start_date=dates.start_date, end_date=dates.end_date, branch=branch) name = frappe.db.get_value('Salary Slip', @@ -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: @@ -144,23 +140,23 @@ def create_account(company): }).insert() return salary_account -def make_process_payroll(**args): +def make_payroll_entry(**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() + payroll_entry = frappe.new_doc("Payroll Entry") + payroll_entry.company = erpnext.get_default_company() + payroll_entry.start_date = args.start_date or "2016-11-01" + payroll_entry.end_date = args.end_date or "2016-11-30" + payroll_entry.payment_account = get_payment_account() + payroll_entry.posting_date = nowdate() + payroll_entry.payroll_frequency = "Monthly" + payroll_entry.branch = args.branch or None + payroll_entry.create_salary_slips() + payroll_entry.submit_salary_slips() + if payroll_entry.get_sal_slip_list(ss_status = 1): + payroll_entry.make_payment_entry() - return process_payroll + return payroll_entry def get_payment_account(): return frappe.get_value('Account', diff --git a/erpnext/hr/doctype/payroll_entry/test_set_salary_components.js b/erpnext/hr/doctype/payroll_entry/test_set_salary_components.js new file mode 100644 index 0000000000..8ff55151f6 --- /dev/null +++ b/erpnext/hr/doctype/payroll_entry/test_set_salary_components.js @@ -0,0 +1,61 @@ +QUnit.module('HR'); + +QUnit.test("test: Set Salary Components", function (assert) { + assert.expect(5); + let done = assert.async(); + + frappe.run_serially([ + () => frappe.set_route('Form', 'Salary Component', 'Leave Encashment'), + () => { + var row = frappe.model.add_child(cur_frm.doc, "Salary Component Account", "accounts"); + row.company = 'For Testing'; + row.default_account = 'Salary - FT'; + }, + + () => cur_frm.save(), + () => frappe.timeout(2), + () => assert.equal(cur_frm.doc.accounts[0].default_account, 'Salary - FT'), + + () => frappe.set_route('Form', 'Salary Component', 'Basic'), + () => { + var row = frappe.model.add_child(cur_frm.doc, "Salary Component Account", "accounts"); + row.company = 'For Testing'; + row.default_account = 'Salary - FT'; + }, + + () => cur_frm.save(), + () => frappe.timeout(2), + () => assert.equal(cur_frm.doc.accounts[0].default_account, 'Salary - FT'), + + () => frappe.set_route('Form', 'Salary Component', 'Income Tax'), + () => { + var row = frappe.model.add_child(cur_frm.doc, "Salary Component Account", "accounts"); + row.company = 'For Testing'; + row.default_account = 'Salary - FT'; + }, + + () => cur_frm.save(), + () => frappe.timeout(2), + () => assert.equal(cur_frm.doc.accounts[0].default_account, 'Salary - FT'), + + () => frappe.set_route('Form', 'Salary Component', 'Arrear'), + () => { + var row = frappe.model.add_child(cur_frm.doc, "Salary Component Account", "accounts"); + row.company = 'For Testing'; + row.default_account = 'Salary - FT'; + }, + + () => cur_frm.save(), + () => frappe.timeout(2), + () => assert.equal(cur_frm.doc.accounts[0].default_account, 'Salary - FT'), + + () => frappe.set_route('Form', 'Company', 'For Testing'), + () => cur_frm.set_value('default_payroll_payable_account', 'Payroll Payable - FT'), + () => cur_frm.save(), + () => frappe.timeout(2), + () => assert.equal(cur_frm.doc.default_payroll_payable_account, 'Payroll Payable - FT'), + + () => done() + + ]); +}); 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 a9ad429354..0000000000 --- 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/test_process_payroll.js b/erpnext/hr/doctype/process_payroll/test_process_payroll.js deleted file mode 100644 index bc61150463..0000000000 --- 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/salary_slip/salary_slip.js b/erpnext/hr/doctype/salary_slip/salary_slip.js index 4679cbdda9..840387ce2b 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.js +++ b/erpnext/hr/doctype/salary_slip/salary_slip.js @@ -37,7 +37,7 @@ frappe.ui.form.on("Salary Slip", { set_end_date: function(frm){ frappe.call({ - method: 'erpnext.hr.doctype.process_payroll.process_payroll.get_end_date', + method: 'erpnext.hr.doctype.payroll_entry.payroll_entry.get_end_date', args: { frequency: frm.doc.payroll_frequency, start_date: frm.doc.start_date diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index ea5f35b04a..656a4ace15 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -8,7 +8,7 @@ from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, from frappe.model.naming import make_autoname from frappe import msgprint, _ -from erpnext.hr.doctype.process_payroll.process_payroll import get_start_end_dates +from erpnext.hr.doctype.payroll_entry.payroll_entry import get_start_end_dates from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee from erpnext.utilities.transaction_base import TransactionBase from frappe.utils.background_jobs import enqueue diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py index f136cb532a..0b240f0095 100644 --- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py @@ -9,8 +9,8 @@ import calendar from erpnext.accounts.utils import get_fiscal_year from frappe.utils import getdate, nowdate, add_days, add_months, flt from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip -from erpnext.hr.doctype.process_payroll.test_process_payroll import get_salary_component_account -from erpnext.hr.doctype.process_payroll.process_payroll import get_month_details +from erpnext.hr.doctype.payroll_entry.test_payroll_entry import get_salary_component_account +from erpnext.hr.doctype.payroll_entry.payroll_entry import get_month_details class TestSalarySlip(unittest.TestCase): def setUp(self): diff --git a/erpnext/patches.txt b/erpnext/patches.txt index cf97030e83..f6988ab3cf 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -476,5 +476,6 @@ 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 erpnext.patches.v10_0.add_agriculture_domain erpnext.patches.v10_0.add_non_profit_domain diff --git a/erpnext/patches/v7_2/update_salary_slips.py b/erpnext/patches/v7_2/update_salary_slips.py index b7a405043e..22bb1d82dc 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 0000000000..e9e1b99c06 --- /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/stock/doctype/item_price/item_price.json b/erpnext/stock/doctype/item_price/item_price.json index fee229f761..fdc2df2f10 100644 --- a/erpnext/stock/doctype/item_price/item_price.json +++ b/erpnext/stock/doctype/item_price/item_price.json @@ -1,5 +1,6 @@ { - "allow_copy": 0, + "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, "autoname": "ITEM-PRICE-.#####", @@ -14,6 +15,7 @@ "engine": "InnoDB", "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -43,6 +45,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -72,6 +75,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -100,6 +104,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -128,6 +133,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -156,6 +162,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -165,7 +172,8 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, + "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "", @@ -184,6 +192,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 1, "collapsible": 0, @@ -213,6 +222,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -244,6 +254,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -275,6 +286,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -302,6 +314,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -330,6 +343,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -357,19 +371,19 @@ "set_only_once": 0, "unique": 0 } - ], + ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "icon": "fa fa-flag", "idx": 1, "image_view": 0, "in_create": 0, - "in_dialog": 0, - "is_submittable": 0, + "is_submittable": 0, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-09-28 03:56:20.814993", + "modified": "2017-12-01 13:03:53.397382", "modified_by": "Administrator", "module": "Stock", "name": "Item Price", diff --git a/erpnext/tests/ui/tests.txt b/erpnext/tests/ui/tests.txt index 6a0399c824..d02cae157c 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 @@ -140,7 +139,8 @@ erpnext/stock/doctype/delivery_note/test_delivery_note_with_margin.js erpnext/selling/doctype/sales_order/tests/test_sales_order_with_margin.js erpnext/selling/doctype/quotation/tests/test_quotation_with_margin.js erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_margin.js -erpnext/stock/doctype/price_list/test_price_list_uom.js +erpnext/hr/doctype/payroll_entry/test_set_salary_components.js +erpnext/hr/doctype/payroll_entry/test_payroll_entry.js erpnext/agriculture/doctype/land_unit/test_land_unit.js erpnext/agriculture/doctype/fertilizer/test_fertilizer.js erpnext/agriculture/doctype/water_analysis/test_water_analysis.js @@ -154,4 +154,4 @@ erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.js erpnext/non_profit/doctype/volunteer/test_volunteer.js erpnext/non_profit/doctype/donor_type/test_donor_type.js erpnext/non_profit/doctype/donor/test_donor.js -erpnext/non_profit/doctype/grant_application/test_grant_application.js +erpnext/non_profit/doctype/grant_application/test_grant_application.js \ No newline at end of file