mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-26 16:34:46 +00:00
Merge branch 'develop' into refactor-addiional-salary
This commit is contained in:
@@ -1,66 +1,79 @@
|
||||
{
|
||||
"cards": [
|
||||
{
|
||||
"links": "[\n {\n \"label\": \"Employee\",\n \"name\": \"Employee\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employment Type\",\n \"name\": \"Employment Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Branch\",\n \"name\": \"Branch\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Department\",\n \"name\": \"Department\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Designation\",\n \"name\": \"Designation\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employee Grade\",\n \"name\": \"Employee Grade\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Group\",\n \"name\": \"Employee Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employee Health Insurance\",\n \"name\": \"Employee Health Insurance\",\n \"type\": \"doctype\"\n }\n]",
|
||||
"title": "Employee"
|
||||
"hidden": 0,
|
||||
"label": "Employee",
|
||||
"links": "[\n {\n \"label\": \"Employee\",\n \"name\": \"Employee\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employment Type\",\n \"name\": \"Employment Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Branch\",\n \"name\": \"Branch\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Department\",\n \"name\": \"Department\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Designation\",\n \"name\": \"Designation\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employee Grade\",\n \"name\": \"Employee Grade\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Group\",\n \"name\": \"Employee Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Employee Health Insurance\",\n \"name\": \"Employee Health Insurance\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Job Applicant\"\n ],\n \"label\": \"Employee Onboarding\",\n \"name\": \"Employee Onboarding\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Skill Map\",\n \"name\": \"Employee Skill Map\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Promotion\",\n \"name\": \"Employee Promotion\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Transfer\",\n \"name\": \"Employee Transfer\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Separation\",\n \"name\": \"Employee Separation\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Onboarding Template\",\n \"name\": \"Employee Onboarding Template\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Separation Template\",\n \"name\": \"Employee Separation Template\",\n \"type\": \"doctype\"\n }\n]",
|
||||
"title": "Employee Lifecycle"
|
||||
"hidden": 0,
|
||||
"label": "Employee Lifecycle",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Job Applicant\"\n ],\n \"label\": \"Employee Onboarding\",\n \"name\": \"Employee Onboarding\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Skill Map\",\n \"name\": \"Employee Skill Map\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Promotion\",\n \"name\": \"Employee Promotion\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Transfer\",\n \"name\": \"Employee Transfer\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Separation\",\n \"name\": \"Employee Separation\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Onboarding Template\",\n \"name\": \"Employee Onboarding Template\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Separation Template\",\n \"name\": \"Employee Separation Template\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"label\": \"Shift Type\",\n \"name\": \"Shift Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Shift Request\",\n \"name\": \"Shift Request\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Shift Assignment\",\n \"name\": \"Shift Assignment\",\n \"type\": \"doctype\"\n }\n]",
|
||||
"title": "Shift Management"
|
||||
"hidden": 0,
|
||||
"label": "Shift Management",
|
||||
"links": "[\n {\n \"label\": \"Shift Type\",\n \"name\": \"Shift Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Shift Request\",\n \"name\": \"Shift Request\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Shift Assignment\",\n \"name\": \"Shift Assignment\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Application\",\n \"name\": \"Leave Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Allocation\",\n \"name\": \"Leave Allocation\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Leave Type\"\n ],\n \"label\": \"Leave Policy\",\n \"name\": \"Leave Policy\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Period\",\n \"name\": \"Leave Period\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Type\",\n \"name\": \"Leave Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Holiday List\",\n \"name\": \"Holiday List\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Compensatory Leave Request\",\n \"name\": \"Compensatory Leave Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Encashment\",\n \"name\": \"Leave Encashment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Block List\",\n \"name\": \"Leave Block List\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Leave Application\"\n ],\n \"doctype\": \"Leave Application\",\n \"is_query_report\": true,\n \"label\": \"Employee Leave Balance\",\n \"name\": \"Employee Leave Balance\",\n \"type\": \"report\"\n }\n]",
|
||||
"title": "Leaves"
|
||||
"hidden": 0,
|
||||
"label": "Leaves",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Application\",\n \"name\": \"Leave Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Allocation\",\n \"name\": \"Leave Allocation\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Leave Type\"\n ],\n \"label\": \"Leave Policy\",\n \"name\": \"Leave Policy\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Period\",\n \"name\": \"Leave Period\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Type\",\n \"name\": \"Leave Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Holiday List\",\n \"name\": \"Holiday List\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Compensatory Leave Request\",\n \"name\": \"Compensatory Leave Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Leave Encashment\",\n \"name\": \"Leave Encashment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Leave Block List\",\n \"name\": \"Leave Block List\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Leave Application\"\n ],\n \"doctype\": \"Leave Application\",\n \"is_query_report\": true,\n \"label\": \"Employee Leave Balance\",\n \"name\": \"Employee Leave Balance\",\n \"type\": \"report\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"label\": \"Salary Structure\",\n \"name\": \"Salary Structure\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Salary Structure\",\n \"Employee\"\n ],\n \"label\": \"Salary Structure Assignment\",\n \"name\": \"Salary Structure Assignment\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Payroll Entry\",\n \"name\": \"Payroll Entry\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Salary Slip\",\n \"name\": \"Salary Slip\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Payroll Period\",\n \"name\": \"Payroll Period\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Salary Component\",\n \"name\": \"Salary Component\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Additional Salary\",\n \"name\": \"Additional Salary\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Retention Bonus\",\n \"name\": \"Retention Bonus\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Incentive\",\n \"name\": \"Employee Incentive\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Salary Slip\"\n ],\n \"doctype\": \"Salary Slip\",\n \"is_query_report\": true,\n \"label\": \"Salary Register\",\n \"name\": \"Salary Register\",\n \"type\": \"report\"\n }\n]",
|
||||
"title": "Payroll"
|
||||
"hidden": 0,
|
||||
"label": "Payroll",
|
||||
"links": "[\n {\n \"label\": \"Salary Structure\",\n \"name\": \"Salary Structure\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Salary Structure\",\n \"Employee\"\n ],\n \"label\": \"Salary Structure Assignment\",\n \"name\": \"Salary Structure Assignment\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Payroll Entry\",\n \"name\": \"Payroll Entry\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Salary Slip\",\n \"name\": \"Salary Slip\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Payroll Period\",\n \"name\": \"Payroll Period\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Salary Component\",\n \"name\": \"Salary Component\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Additional Salary\",\n \"name\": \"Additional Salary\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Retention Bonus\",\n \"name\": \"Retention Bonus\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Incentive\",\n \"name\": \"Employee Incentive\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Salary Slip\"\n ],\n \"doctype\": \"Salary Slip\",\n \"is_query_report\": true,\n \"label\": \"Salary Register\",\n \"name\": \"Salary Register\",\n \"type\": \"report\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"hide_count\": true,\n \"label\": \"Employee Attendance Tool\",\n \"name\": \"Employee Attendance Tool\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Attendance\",\n \"name\": \"Attendance\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Attendance Request\",\n \"name\": \"Attendance Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"hide_count\": true,\n \"label\": \"Upload Attendance\",\n \"name\": \"Upload Attendance\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"hide_count\": true,\n \"label\": \"Employee Checkin\",\n \"name\": \"Employee Checkin\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Attendance\"\n ],\n \"doctype\": \"Attendance\",\n \"is_query_report\": true,\n \"label\": \"Monthly Attendance Sheet\",\n \"name\": \"Monthly Attendance Sheet\",\n \"type\": \"report\"\n }\n]",
|
||||
"title": "Attendance"
|
||||
"hidden": 0,
|
||||
"label": "Attendance",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"hide_count\": true,\n \"label\": \"Employee Attendance Tool\",\n \"name\": \"Employee Attendance Tool\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Attendance\",\n \"name\": \"Attendance\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Attendance Request\",\n \"name\": \"Attendance Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"hide_count\": true,\n \"label\": \"Upload Attendance\",\n \"name\": \"Upload Attendance\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"hide_count\": true,\n \"label\": \"Employee Checkin\",\n \"name\": \"Employee Checkin\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Attendance\"\n ],\n \"doctype\": \"Attendance\",\n \"is_query_report\": true,\n \"label\": \"Monthly Attendance Sheet\",\n \"name\": \"Monthly Attendance Sheet\",\n \"type\": \"report\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Expense Claim\",\n \"name\": \"Expense Claim\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Advance\",\n \"name\": \"Employee Advance\",\n \"type\": \"doctype\"\n }\n]",
|
||||
"title": "Expense Claims"
|
||||
"hidden": 0,
|
||||
"label": "Expense Claims",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Expense Claim\",\n \"name\": \"Expense Claim\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Advance\",\n \"name\": \"Employee Advance\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"icon": "fa fa-cog",
|
||||
"links": "[\n {\n \"label\": \"HR Settings\",\n \"name\": \"HR Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Daily Work Summary Group\",\n \"name\": \"Daily Work Summary Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Team Updates\",\n \"name\": \"team-updates\",\n \"type\": \"page\"\n }\n]",
|
||||
"title": "Settings"
|
||||
"hidden": 0,
|
||||
"label": "Settings",
|
||||
"links": "[\n {\n \"label\": \"HR Settings\",\n \"name\": \"HR Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Daily Work Summary Group\",\n \"name\": \"Daily Work Summary Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Team Updates\",\n \"name\": \"team-updates\",\n \"type\": \"page\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"label\": \"Vehicle\",\n \"name\": \"Vehicle\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Vehicle Log\",\n \"name\": \"Vehicle Log\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Vehicle\"\n ],\n \"doctype\": \"Vehicle\",\n \"is_query_report\": true,\n \"label\": \"Vehicle Expenses\",\n \"name\": \"Vehicle Expenses\",\n \"type\": \"report\"\n }\n]",
|
||||
"title": "Fleet Management"
|
||||
"hidden": 0,
|
||||
"label": "Fleet Management",
|
||||
"links": "[\n {\n \"label\": \"Vehicle\",\n \"name\": \"Vehicle\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Vehicle Log\",\n \"name\": \"Vehicle Log\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Vehicle\"\n ],\n \"doctype\": \"Vehicle\",\n \"is_query_report\": true,\n \"label\": \"Vehicle Expenses\",\n \"name\": \"Vehicle Expenses\",\n \"type\": \"report\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"label\": \"Job Opening\",\n \"name\": \"Job Opening\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Job Applicant\",\n \"name\": \"Job Applicant\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Job Offer\",\n \"name\": \"Job Offer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Staffing Plan\",\n \"name\": \"Staffing Plan\",\n \"type\": \"doctype\"\n }\n]",
|
||||
"title": "Recruitment"
|
||||
"hidden": 0,
|
||||
"label": "Recruitment",
|
||||
"links": "[\n {\n \"label\": \"Job Opening\",\n \"name\": \"Job Opening\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Job Applicant\",\n \"name\": \"Job Applicant\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Job Offer\",\n \"name\": \"Job Offer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Staffing Plan\",\n \"name\": \"Staffing Plan\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Loan Application\",\n \"name\": \"Loan Application\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan\",\n \"name\": \"Loan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan Type\",\n \"name\": \"Loan Type\",\n \"type\": \"doctype\"\n }\n]",
|
||||
"title": "Loans"
|
||||
"hidden": 0,
|
||||
"label": "Loans",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Loan Application\",\n \"name\": \"Loan Application\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan\",\n \"name\": \"Loan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Loan Type\",\n \"name\": \"Loan Type\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"label\": \"Training Program\",\n \"name\": \"Training Program\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Training Event\",\n \"name\": \"Training Event\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Training Result\",\n \"name\": \"Training Result\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Training Feedback\",\n \"name\": \"Training Feedback\",\n \"type\": \"doctype\"\n }\n]",
|
||||
"title": "Training"
|
||||
"hidden": 0,
|
||||
"label": "Training",
|
||||
"links": "[\n {\n \"label\": \"Training Program\",\n \"name\": \"Training Program\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Training Event\",\n \"name\": \"Training Event\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Training Result\",\n \"name\": \"Training Result\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Training Feedback\",\n \"name\": \"Training Feedback\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"icon": "fa fa-list",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"doctype\": \"Employee\",\n \"is_query_report\": true,\n \"label\": \"Employee Birthday\",\n \"name\": \"Employee Birthday\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"doctype\": \"Employee\",\n \"is_query_report\": true,\n \"label\": \"Employees working on a holiday\",\n \"name\": \"Employees working on a holiday\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"doctype\": \"Employee\",\n \"is_query_report\": true,\n \"label\": \"Department Analytics\",\n \"name\": \"Department Analytics\",\n \"type\": \"report\"\n }\n]",
|
||||
"title": "Reports"
|
||||
"hidden": 0,
|
||||
"label": "Reports",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"doctype\": \"Employee\",\n \"is_query_report\": true,\n \"label\": \"Employee Birthday\",\n \"name\": \"Employee Birthday\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"doctype\": \"Employee\",\n \"is_query_report\": true,\n \"label\": \"Employees working on a holiday\",\n \"name\": \"Employees working on a holiday\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"doctype\": \"Employee\",\n \"is_query_report\": true,\n \"label\": \"Department Analytics\",\n \"name\": \"Department Analytics\",\n \"type\": \"report\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"label\": \"Appraisal\",\n \"name\": \"Appraisal\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Appraisal Template\",\n \"name\": \"Appraisal Template\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Energy Point Rule\",\n \"name\": \"Energy Point Rule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Energy Point Log\",\n \"name\": \"Energy Point Log\",\n \"type\": \"doctype\"\n }\n]",
|
||||
"title": "Performance"
|
||||
"hidden": 0,
|
||||
"label": "Performance",
|
||||
"links": "[\n {\n \"label\": \"Appraisal\",\n \"name\": \"Appraisal\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Appraisal Template\",\n \"name\": \"Appraisal Template\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Energy Point Rule\",\n \"name\": \"Energy Point Rule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Energy Point Log\",\n \"name\": \"Energy Point Log\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Tax Exemption Declaration\",\n \"name\": \"Employee Tax Exemption Declaration\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Tax Exemption Proof Submission\",\n \"name\": \"Employee Tax Exemption Proof Submission\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Benefit Application\",\n \"name\": \"Employee Benefit Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Benefit Claim\",\n \"name\": \"Employee Benefit Claim\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Tax Exemption Category\",\n \"name\": \"Employee Tax Exemption Category\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Tax Exemption Sub Category\",\n \"name\": \"Employee Tax Exemption Sub Category\",\n \"type\": \"doctype\"\n }\n]",
|
||||
"title": "Employee Tax and Benefits"
|
||||
"hidden": 0,
|
||||
"label": "Employee Tax and Benefits",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Tax Exemption Declaration\",\n \"name\": \"Employee Tax Exemption Declaration\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Tax Exemption Proof Submission\",\n \"name\": \"Employee Tax Exemption Proof Submission\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Benefit Application\",\n \"name\": \"Employee Benefit Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Benefit Claim\",\n \"name\": \"Employee Benefit Claim\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Tax Exemption Category\",\n \"name\": \"Employee Tax Exemption Category\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Employee\"\n ],\n \"label\": \"Employee Tax Exemption Sub Category\",\n \"name\": \"Employee Tax Exemption Sub Category\",\n \"type\": \"doctype\"\n }\n]"
|
||||
}
|
||||
],
|
||||
"category": "Modules",
|
||||
@@ -75,7 +88,7 @@
|
||||
"idx": 0,
|
||||
"is_standard": 1,
|
||||
"label": "HR",
|
||||
"modified": "2020-03-12 16:30:35.211246",
|
||||
"modified": "2020-04-01 11:28:50.860012",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "HR",
|
||||
@@ -85,37 +98,37 @@
|
||||
"shortcuts": [
|
||||
{
|
||||
"format": "{} Active",
|
||||
"is_query_report": 0,
|
||||
"label": "Employee",
|
||||
"link_to": "Employee",
|
||||
"stats_filter": "{\"status\":\"Active\"}",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"format": "{} Unpaid",
|
||||
"is_query_report": 0,
|
||||
"label": "Expense Claim",
|
||||
"link_to": "Expense Claim",
|
||||
"stats_filter": "{\"approval_status\":\"Draft\"}",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"format": "{} Open",
|
||||
"is_query_report": 0,
|
||||
"label": "Job Applicant",
|
||||
"link_to": "Job Applicant",
|
||||
"stats_filter": "{\n \"status\": \"Open\"\n}",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"is_query_report": 0,
|
||||
"label": "Salary Structure",
|
||||
"link_to": "Salary Structure",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"is_query_report": 0,
|
||||
"label": "Leave Application",
|
||||
"link_to": "Leave Application",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"is_query_report": 0,
|
||||
"label": "Salary Register",
|
||||
"link_to": "Salary Register",
|
||||
"type": "Report"
|
||||
}
|
||||
|
||||
@@ -87,11 +87,12 @@
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.status==\"On Leave\"",
|
||||
"depends_on": "eval:in_list([\"On Leave\", \"Half Day\"], doc.status)",
|
||||
"fieldname": "leave_type",
|
||||
"fieldtype": "Link",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Leave Type",
|
||||
"mandatory_depends_on": "eval:in_list([\"On Leave\", \"Half Day\"], doc.status)",
|
||||
"oldfieldname": "leave_type",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Leave Type"
|
||||
@@ -100,6 +101,7 @@
|
||||
"fieldname": "leave_application",
|
||||
"fieldtype": "Link",
|
||||
"label": "Leave Application",
|
||||
"no_copy": 1,
|
||||
"options": "Leave Application",
|
||||
"read_only": 1
|
||||
},
|
||||
@@ -175,7 +177,8 @@
|
||||
"icon": "fa fa-ok",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2020-02-19 14:25:32.945842",
|
||||
"links": [],
|
||||
"modified": "2020-04-11 11:40:14.319496",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Attendance",
|
||||
|
||||
@@ -7,33 +7,15 @@ import frappe
|
||||
from frappe.utils import getdate, nowdate
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import cstr, get_datetime, get_datetime_str
|
||||
from frappe.utils import update_progress_bar
|
||||
from frappe.utils import cstr, get_datetime, formatdate
|
||||
|
||||
class Attendance(Document):
|
||||
def validate_duplicate_record(self):
|
||||
res = frappe.db.sql("""select name from `tabAttendance` where employee = %s and attendance_date = %s
|
||||
and name != %s and docstatus != 2""",
|
||||
(self.employee, getdate(self.attendance_date), self.name))
|
||||
if res:
|
||||
frappe.throw(_("Attendance for employee {0} is already marked").format(self.employee))
|
||||
|
||||
def check_leave_record(self):
|
||||
leave_record = frappe.db.sql("""select leave_type, half_day, half_day_date from `tabLeave Application`
|
||||
where employee = %s and %s between from_date and to_date and status = 'Approved'
|
||||
and docstatus = 1""", (self.employee, self.attendance_date), as_dict=True)
|
||||
if leave_record:
|
||||
for d in leave_record:
|
||||
if d.half_day_date == getdate(self.attendance_date):
|
||||
self.status = 'Half Day'
|
||||
frappe.msgprint(_("Employee {0} on Half day on {1}").format(self.employee, self.attendance_date))
|
||||
else:
|
||||
self.status = 'On Leave'
|
||||
self.leave_type = d.leave_type
|
||||
frappe.msgprint(_("Employee {0} is on Leave on {1}").format(self.employee, self.attendance_date))
|
||||
|
||||
if self.status == "On Leave" and not leave_record:
|
||||
frappe.throw(_("No leave record found for employee {0} for {1}").format(self.employee, self.attendance_date))
|
||||
def validate(self):
|
||||
from erpnext.controllers.status_updater import validate_status
|
||||
validate_status(self.status, ["Present", "Absent", "On Leave", "Half Day", "Work From Home"])
|
||||
self.validate_attendance_date()
|
||||
self.validate_duplicate_record()
|
||||
self.check_leave_record()
|
||||
|
||||
def validate_attendance_date(self):
|
||||
date_of_joining = frappe.db.get_value("Employee", self.employee, "date_of_joining")
|
||||
@@ -44,19 +26,52 @@ class Attendance(Document):
|
||||
elif date_of_joining and getdate(self.attendance_date) < getdate(date_of_joining):
|
||||
frappe.throw(_("Attendance date can not be less than employee's joining date"))
|
||||
|
||||
def validate_duplicate_record(self):
|
||||
res = frappe.db.sql("""
|
||||
select name from `tabAttendance`
|
||||
where employee = %s
|
||||
and attendance_date = %s
|
||||
and name != %s
|
||||
and docstatus != 2
|
||||
""", (self.employee, getdate(self.attendance_date), self.name))
|
||||
if res:
|
||||
frappe.throw(_("Attendance for employee {0} is already marked").format(self.employee))
|
||||
|
||||
def check_leave_record(self):
|
||||
leave_record = frappe.db.sql("""
|
||||
select leave_type, half_day, half_day_date
|
||||
from `tabLeave Application`
|
||||
where employee = %s
|
||||
and %s between from_date and to_date
|
||||
and status = 'Approved'
|
||||
and docstatus = 1
|
||||
""", (self.employee, self.attendance_date), as_dict=True)
|
||||
if leave_record:
|
||||
for d in leave_record:
|
||||
self.leave_type = d.leave_type
|
||||
if d.half_day_date == getdate(self.attendance_date):
|
||||
self.status = 'Half Day'
|
||||
frappe.msgprint(_("Employee {0} on Half day on {1}")
|
||||
.format(self.employee, formatdate(self.attendance_date)))
|
||||
else:
|
||||
self.status = 'On Leave'
|
||||
frappe.msgprint(_("Employee {0} is on Leave on {1}")
|
||||
.format(self.employee, formatdate(self.attendance_date)))
|
||||
|
||||
if self.status in ("On Leave", "Half Day"):
|
||||
if not leave_record:
|
||||
frappe.msgprint(_("No leave record found for employee {0} on {1}")
|
||||
.format(self.employee, formatdate(self.attendance_date)), alert=1)
|
||||
elif self.leave_type:
|
||||
self.leave_type = None
|
||||
self.leave_application = None
|
||||
|
||||
def validate_employee(self):
|
||||
emp = frappe.db.sql("select name from `tabEmployee` where name = %s and status = 'Active'",
|
||||
self.employee)
|
||||
if not emp:
|
||||
frappe.throw(_("Employee {0} is not active or does not exist").format(self.employee))
|
||||
|
||||
def validate(self):
|
||||
from erpnext.controllers.status_updater import validate_status
|
||||
validate_status(self.status, ["Present", "Absent", "On Leave", "Half Day", "Work From Home"])
|
||||
self.validate_attendance_date()
|
||||
self.validate_duplicate_record()
|
||||
self.check_leave_record()
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_events(start, end, filters=None):
|
||||
events = []
|
||||
@@ -90,18 +105,20 @@ def add_attendance(events, start, end, conditions=None):
|
||||
if e not in events:
|
||||
events.append(e)
|
||||
|
||||
def mark_attendance(employee, attendance_date, status, shift=None):
|
||||
employee_doc = frappe.get_doc('Employee', employee)
|
||||
def mark_attendance(employee, attendance_date, status, shift=None, leave_type=None, ignore_validate=False):
|
||||
if not frappe.db.exists('Attendance', {'employee':employee, 'attendance_date':attendance_date, 'docstatus':('!=', '2')}):
|
||||
doc_dict = {
|
||||
company = frappe.db.get_value('Employee', employee, 'company')
|
||||
attendance = frappe.get_doc({
|
||||
'doctype': 'Attendance',
|
||||
'employee': employee,
|
||||
'attendance_date': attendance_date,
|
||||
'status': status,
|
||||
'company': employee_doc.company,
|
||||
'shift': shift
|
||||
}
|
||||
attendance = frappe.get_doc(doc_dict).insert()
|
||||
'company': company,
|
||||
'shift': shift,
|
||||
'leave_type': leave_type
|
||||
})
|
||||
attendance.flags.ignore_validate = ignore_validate
|
||||
attendance.insert()
|
||||
attendance.submit()
|
||||
return attendance.name
|
||||
|
||||
|
||||
@@ -55,8 +55,8 @@ frappe.ui.form.on('Employee',{
|
||||
};
|
||||
});
|
||||
},
|
||||
prefered_contact_email:function(frm){
|
||||
frm.events.update_contact(frm)
|
||||
prefered_contact_email:function(frm){
|
||||
frm.events.update_contact(frm)
|
||||
},
|
||||
personal_email:function(frm){
|
||||
frm.events.update_contact(frm)
|
||||
|
||||
@@ -259,7 +259,8 @@
|
||||
"bold": 1,
|
||||
"fieldname": "emergency_phone_number",
|
||||
"fieldtype": "Data",
|
||||
"label": "Emergency Phone"
|
||||
"label": "Emergency Phone",
|
||||
"options": "Phone"
|
||||
},
|
||||
{
|
||||
"bold": 1,
|
||||
@@ -480,7 +481,8 @@
|
||||
{
|
||||
"fieldname": "cell_number",
|
||||
"fieldtype": "Data",
|
||||
"label": "Mobile"
|
||||
"label": "Mobile",
|
||||
"options": "Phone"
|
||||
},
|
||||
{
|
||||
"fieldname": "prefered_contact_email",
|
||||
@@ -787,7 +789,7 @@
|
||||
"idx": 24,
|
||||
"image_field": "image",
|
||||
"links": [],
|
||||
"modified": "2020-01-09 04:23:55.611366",
|
||||
"modified": "2020-04-08 12:25:34.306695",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee",
|
||||
@@ -834,6 +836,5 @@
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "employee_name",
|
||||
"track_changes": 1
|
||||
}
|
||||
"title_field": "employee_name"
|
||||
}
|
||||
@@ -148,9 +148,18 @@ def create_return_through_additional_salary(doc):
|
||||
@frappe.whitelist()
|
||||
def make_return_entry(employee_name, company, employee_advance_name, return_amount, mode_of_payment, advance_account):
|
||||
return_account = get_default_bank_cash_account(company, account_type='Cash', mode_of_payment = mode_of_payment)
|
||||
|
||||
mode_of_payment_type = ''
|
||||
if mode_of_payment:
|
||||
mode_of_payment_type = frappe.get_cached_value('Mode of Payment', mode_of_payment, 'type')
|
||||
if mode_of_payment_type not in ["Cash", "Bank"]:
|
||||
# if mode of payment is General then it unset the type
|
||||
mode_of_payment_type = None
|
||||
|
||||
je = frappe.new_doc('Journal Entry')
|
||||
je.posting_date = nowdate()
|
||||
je.voucher_type = 'Bank Entry'
|
||||
# if mode of payment is Bank then voucher type is Bank Entry
|
||||
je.voucher_type = '{} Entry'.format(mode_of_payment_type) if mode_of_payment_type else 'Cash Entry'
|
||||
je.company = company
|
||||
je.remark = 'Return against Employee Advance: ' + employee_advance_name
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Employee Other Income', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "HR-INCOME-.######",
|
||||
"creation": "2020-03-18 15:04:40.767434",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"employee",
|
||||
"employee_name",
|
||||
"payroll_period",
|
||||
"column_break_3",
|
||||
"company",
|
||||
"source",
|
||||
"amount",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Employee",
|
||||
"options": "Employee",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "payroll_period",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Payroll Period",
|
||||
"options": "Payroll Period",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "source",
|
||||
"fieldtype": "Data",
|
||||
"label": "Source"
|
||||
},
|
||||
{
|
||||
"fieldname": "amount",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "employee.employee_name",
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Employee Name",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Employee Other Income",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-03-19 18:06:45.361830",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Other Income",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Employee",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, 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
|
||||
|
||||
class EmployeeOtherIncome(Document):
|
||||
pass
|
||||
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestEmployeeOtherIncome(unittest.TestCase):
|
||||
pass
|
||||
@@ -1,620 +1,180 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "HR-TAX-DEC-.YYYY.-.#####",
|
||||
"beta": 0,
|
||||
"creation": "2018-04-13 16:53:36.175504",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "HR-TAX-DEC-.YYYY.-.#####",
|
||||
"creation": "2018-04-13 16:53:36.175504",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"employee",
|
||||
"employee_name",
|
||||
"department",
|
||||
"column_break_2",
|
||||
"payroll_period",
|
||||
"company",
|
||||
"amended_from",
|
||||
"section_break_8",
|
||||
"declarations",
|
||||
"section_break_10",
|
||||
"total_declared_amount",
|
||||
"column_break_12",
|
||||
"total_exemption_amount"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 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": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Employee",
|
||||
"options": "Employee",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "employee.employee_name",
|
||||
"fetch_if_empty": 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": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Employee Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fetch_from": "employee.employee_name",
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Employee Name",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "employee.department",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "department",
|
||||
"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": "Department",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fetch_from": "employee.department",
|
||||
"fieldname": "department",
|
||||
"fieldtype": "Link",
|
||||
"label": "Department",
|
||||
"options": "Department",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "payroll_period",
|
||||
"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": "Payroll Period",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Payroll Period",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "payroll_period",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Payroll Period",
|
||||
"options": "Payroll Period",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "employee.company",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company",
|
||||
"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": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fetch_from": "employee.company",
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 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": "Employee Tax Exemption Declaration",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Employee Tax Exemption Declaration",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_8",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "section_break_8",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "declarations",
|
||||
"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": "Declarations",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Employee Tax Exemption Declaration Category",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "declarations",
|
||||
"fieldtype": "Table",
|
||||
"label": "Declarations",
|
||||
"options": "Employee Tax Exemption Declaration Category"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_10",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "section_break_10",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "total_declared_amount",
|
||||
"fieldtype": "Currency",
|
||||
"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": "Total Declared Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "total_declared_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Total Declared Amount",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_12",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_12",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "total_exemption_amount",
|
||||
"fieldtype": "Currency",
|
||||
"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": "Total Exemption Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "other_incomes_section",
|
||||
"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,
|
||||
"label": "Other Incomes",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "income_from_other_sources",
|
||||
"fieldtype": "Currency",
|
||||
"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": "Income From Other Sources",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldname": "total_exemption_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Total Exemption Amount",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-05-11 16:13:50.472670",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Tax Exemption Declaration",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-03-18 14:56:25.625717",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Tax Exemption Declaration",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Employee",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Employee",
|
||||
"share": 1,
|
||||
"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": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -8,31 +8,17 @@ from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, calculate_annual_eligible_hra_exemption
|
||||
|
||||
class DuplicateDeclarationError(frappe.ValidationError): pass
|
||||
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, \
|
||||
calculate_annual_eligible_hra_exemption, validate_duplicate_exemption_for_payroll_period
|
||||
|
||||
class EmployeeTaxExemptionDeclaration(Document):
|
||||
def validate(self):
|
||||
validate_tax_declaration(self.declarations)
|
||||
self.validate_duplicate()
|
||||
validate_duplicate_exemption_for_payroll_period(self.doctype, self.name, self.payroll_period, self.employee)
|
||||
self.set_total_declared_amount()
|
||||
self.set_total_exemption_amount()
|
||||
self.calculate_hra_exemption()
|
||||
|
||||
def validate_duplicate(self):
|
||||
duplicate = frappe.db.get_value("Employee Tax Exemption Declaration",
|
||||
filters = {
|
||||
"employee": self.employee,
|
||||
"payroll_period": self.payroll_period,
|
||||
"name": ["!=", self.name],
|
||||
"docstatus": ["!=", 2]
|
||||
}
|
||||
)
|
||||
if duplicate:
|
||||
frappe.throw(_("Duplicate Tax Declaration of {0} for period {1}")
|
||||
.format(self.employee, self.payroll_period), DuplicateDeclarationError)
|
||||
|
||||
def set_total_declared_amount(self):
|
||||
self.total_declared_amount = 0.0
|
||||
for d in self.declarations:
|
||||
|
||||
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
|
||||
import frappe, erpnext
|
||||
import unittest
|
||||
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||
from erpnext.hr.doctype.employee_tax_exemption_declaration.employee_tax_exemption_declaration import DuplicateDeclarationError
|
||||
from erpnext.hr.utils import DuplicateDeclarationError
|
||||
|
||||
class TestEmployeeTaxExemptionDeclaration(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
"total_actual_amount",
|
||||
"column_break_12",
|
||||
"exemption_amount",
|
||||
"other_incomes_section",
|
||||
"income_from_other_sources",
|
||||
"attachment_section",
|
||||
"attachments",
|
||||
"amended_from"
|
||||
@@ -111,16 +109,6 @@
|
||||
"label": "Total Exemption Amount",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "other_incomes_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Other Incomes"
|
||||
},
|
||||
{
|
||||
"fieldname": "income_from_other_sources",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Income From Other Sources"
|
||||
},
|
||||
{
|
||||
"fieldname": "attachment_section",
|
||||
"fieldtype": "Section Break"
|
||||
@@ -142,7 +130,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-03-02 19:02:15.398486",
|
||||
"modified": "2020-03-18 14:55:51.420016",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Tax Exemption Proof Submission",
|
||||
|
||||
@@ -7,7 +7,8 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, calculate_hra_exemption_for_period
|
||||
from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, \
|
||||
calculate_hra_exemption_for_period, validate_duplicate_exemption_for_payroll_period
|
||||
|
||||
class EmployeeTaxExemptionProofSubmission(Document):
|
||||
def validate(self):
|
||||
@@ -15,6 +16,7 @@ class EmployeeTaxExemptionProofSubmission(Document):
|
||||
self.set_total_actual_amount()
|
||||
self.set_total_exemption_amount()
|
||||
self.calculate_hra_exemption()
|
||||
validate_duplicate_exemption_for_payroll_period(self.doctype, self.name, self.payroll_period, self.employee)
|
||||
|
||||
def set_total_actual_amount(self):
|
||||
self.total_actual_amount = flt(self.get("house_rent_payment_amount"))
|
||||
@@ -32,4 +34,4 @@ class EmployeeTaxExemptionProofSubmission(Document):
|
||||
self.exemption_amount += hra_exemption["total_eligible_hra_exemption"]
|
||||
self.monthly_hra_exemption = hra_exemption["monthly_exemption"]
|
||||
self.monthly_house_rent = hra_exemption["monthly_house_rent"]
|
||||
self.total_eligible_hra_exemption = hra_exemption["total_eligible_hra_exemption"]
|
||||
self.total_eligible_hra_exemption = hra_exemption["total_eligible_hra_exemption"]
|
||||
|
||||
@@ -17,7 +17,7 @@ erpnext.hr.ExpenseClaimController = frappe.ui.form.Controller.extend({
|
||||
return;
|
||||
}
|
||||
return frappe.call({
|
||||
method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account",
|
||||
method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account_and_cost_center",
|
||||
args: {
|
||||
"expense_claim_type": d.expense_type,
|
||||
"company": doc.company
|
||||
@@ -25,6 +25,7 @@ erpnext.hr.ExpenseClaimController = frappe.ui.form.Controller.extend({
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
d.default_account = r.message.account;
|
||||
d.cost_center = r.message.cost_center;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe, erpnext
|
||||
from frappe import _
|
||||
from frappe.utils import get_fullname, flt, cstr
|
||||
from frappe.utils import get_fullname, flt, cstr, get_link_to_form
|
||||
from frappe.model.document import Document
|
||||
from erpnext.hr.utils import set_employee_name
|
||||
from erpnext.accounts.party import get_party_account
|
||||
@@ -192,7 +192,8 @@ class ExpenseClaim(AccountsController):
|
||||
def validate_account_details(self):
|
||||
for data in self.expenses:
|
||||
if not data.cost_center:
|
||||
frappe.throw(_("Cost center is required to book an expense claim"))
|
||||
frappe.throw(_("Row {0}: {1} is required in the expenses table to book an expense claim.")
|
||||
.format(data.idx, frappe.bold("Cost Center")))
|
||||
|
||||
if self.is_paid:
|
||||
if not self.mode_of_payment:
|
||||
@@ -308,13 +309,23 @@ def make_bank_entry(dt, dn):
|
||||
|
||||
return je.as_dict()
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_expense_claim_account_and_cost_center(expense_claim_type, company):
|
||||
data = get_expense_claim_account(expense_claim_type, company)
|
||||
cost_center = erpnext.get_default_cost_center(company)
|
||||
|
||||
return {
|
||||
"account": data.get("account"),
|
||||
"cost_center": cost_center
|
||||
}
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_expense_claim_account(expense_claim_type, company):
|
||||
account = frappe.db.get_value("Expense Claim Account",
|
||||
{"parent": expense_claim_type, "company": company}, "default_account")
|
||||
if not account:
|
||||
frappe.throw(_("Please set default account in Expense Claim Type {0}")
|
||||
.format(expense_claim_type))
|
||||
frappe.throw(_("Set the default account for the {0} {1}")
|
||||
.format(frappe.bold("Expense Claim Type"), get_link_to_form("Expense Claim Type", expense_claim_type)))
|
||||
|
||||
return {
|
||||
"account": account
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
"stop_birthday_reminders",
|
||||
"expense_approver_mandatory_in_expense_claim",
|
||||
"payroll_settings",
|
||||
"payroll_based_on",
|
||||
"max_working_hours_against_timesheet",
|
||||
"include_holidays_in_total_working_days",
|
||||
"disable_rounded_total",
|
||||
"max_working_hours_against_timesheet",
|
||||
"column_break_11",
|
||||
"daily_wages_fraction_for_half_day",
|
||||
"email_salary_slip_to_employee",
|
||||
"encrypt_salary_slips_in_emails",
|
||||
"password_policy",
|
||||
@@ -184,13 +186,27 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Role Allowed to Create Backdated Leave Application",
|
||||
"options": "Role"
|
||||
},
|
||||
{
|
||||
"default": "Leave",
|
||||
"fieldname": "payroll_based_on",
|
||||
"fieldtype": "Select",
|
||||
"label": "Calculate Working Days in Payroll based on",
|
||||
"options": "Leave\nAttendance"
|
||||
},
|
||||
{
|
||||
"default": "0.5",
|
||||
"description": "The fraction of daily wages to be paid for half-day attendance",
|
||||
"fieldname": "daily_wages_fraction_for_half_day",
|
||||
"fieldtype": "Float",
|
||||
"label": "Daily Wages Fraction for Half Day"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-cog",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2020-01-06 18:46:30.189815",
|
||||
"modified": "2020-04-13 21:20:59.382394",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "HR Settings",
|
||||
|
||||
@@ -15,6 +15,9 @@ class HRSettings(Document):
|
||||
self.set_naming_series()
|
||||
self.validate_password_policy()
|
||||
|
||||
if not self.daily_wages_fraction_for_half_day:
|
||||
self.daily_wages_fraction_for_half_day = 0.5
|
||||
|
||||
def set_naming_series(self):
|
||||
from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
|
||||
set_by_naming_series("Employee", "employee_number",
|
||||
|
||||
0
erpnext/hr/doctype/income_tax_slab/__init__.py
Normal file
0
erpnext/hr/doctype/income_tax_slab/__init__.py
Normal file
6
erpnext/hr/doctype/income_tax_slab/income_tax_slab.js
Normal file
6
erpnext/hr/doctype/income_tax_slab/income_tax_slab.js
Normal file
@@ -0,0 +1,6 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Income Tax Slab', {
|
||||
|
||||
});
|
||||
160
erpnext/hr/doctype/income_tax_slab/income_tax_slab.json
Normal file
160
erpnext/hr/doctype/income_tax_slab/income_tax_slab.json
Normal file
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "Prompt",
|
||||
"creation": "2020-03-17 16:50:35.564915",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"effective_from",
|
||||
"company",
|
||||
"column_break_3",
|
||||
"allow_tax_exemption",
|
||||
"standard_tax_exemption_amount",
|
||||
"disabled",
|
||||
"amended_from",
|
||||
"taxable_salary_slabs_section",
|
||||
"slabs",
|
||||
"taxes_and_charges_on_income_tax_section",
|
||||
"other_taxes_and_charges"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "effective_from",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Effective from",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If enabled, Tax Exemption Declaration will be considered for income tax calculation.",
|
||||
"fieldname": "allow_tax_exemption",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allow Tax Exemption"
|
||||
},
|
||||
{
|
||||
"fieldname": "taxable_salary_slabs_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Taxable Salary Slabs"
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Income Tax Slab",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "slabs",
|
||||
"fieldtype": "Table",
|
||||
"label": "Taxable Salary Slabs",
|
||||
"options": "Taxable Salary Slab",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"default": "0",
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disabled"
|
||||
},
|
||||
{
|
||||
"depends_on": "allow_tax_exemption",
|
||||
"fieldname": "standard_tax_exemption_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Standard Tax Exemption Amount",
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "taxes_and_charges_on_income_tax_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Taxes and Charges on Income Tax"
|
||||
},
|
||||
{
|
||||
"fieldname": "other_taxes_and_charges",
|
||||
"fieldtype": "Table",
|
||||
"label": "Other Taxes and Charges",
|
||||
"options": "Income Tax Slab Other Charges"
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-24 12:28:36.805904",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Income Tax Slab",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Administrator",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
10
erpnext/hr/doctype/income_tax_slab/income_tax_slab.py
Normal file
10
erpnext/hr/doctype/income_tax_slab/income_tax_slab.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, 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
|
||||
|
||||
class IncomeTaxSlab(Document):
|
||||
pass
|
||||
10
erpnext/hr/doctype/income_tax_slab/test_income_tax_slab.py
Normal file
10
erpnext/hr/doctype/income_tax_slab/test_income_tax_slab.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestIncomeTaxSlab(unittest.TestCase):
|
||||
pass
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-04-24 11:46:59.041180",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"description",
|
||||
"column_break_2",
|
||||
"percent",
|
||||
"conditions_section",
|
||||
"min_taxable_income",
|
||||
"column_break_7",
|
||||
"max_taxable_income"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "min_taxable_income",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Min Taxable Income",
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"columns": 4,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Description",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "percent",
|
||||
"fieldtype": "Percent",
|
||||
"in_list_view": 1,
|
||||
"label": "Percent",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "conditions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Conditions"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_7",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "max_taxable_income",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Max Taxable Income",
|
||||
"options": "Company:company:default_currency"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-24 13:27:43.598967",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Income Tax Slab Other Charges",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, 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
|
||||
|
||||
class IncomeTaxSlabOtherCharges(Document):
|
||||
pass
|
||||
@@ -1,385 +1,123 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 1,
|
||||
"autoname": "HR-APP-.YYYY.-.#####",
|
||||
"beta": 0,
|
||||
"creation": "2013-01-29 19:25:37",
|
||||
"custom": 0,
|
||||
"description": "Applicant for a Job",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"editable_grid": 0,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "HR-APP-.YYYY.-.#####",
|
||||
"creation": "2013-01-29 19:25:37",
|
||||
"description": "Applicant for a Job",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"email_append_to": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"applicant_name",
|
||||
"email_id",
|
||||
"status",
|
||||
"column_break_3",
|
||||
"job_title",
|
||||
"source",
|
||||
"source_name",
|
||||
"section_break_6",
|
||||
"notes",
|
||||
"cover_letter",
|
||||
"resume_attachment"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "applicant_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Applicant Name",
|
||||
"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": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"bold": 1,
|
||||
"fieldname": "applicant_name",
|
||||
"fieldtype": "Data",
|
||||
"in_global_search": 1,
|
||||
"label": "Applicant Name",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "email_id",
|
||||
"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,
|
||||
"label": "Email Address",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Email",
|
||||
"permlevel": 0,
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"bold": 1,
|
||||
"fieldname": "email_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Email Address",
|
||||
"options": "Email",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Open\nReplied\nRejected\nHold\nAccepted",
|
||||
"permlevel": 0,
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"options": "Open\nReplied\nRejected\nHold\nAccepted",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 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,
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"width": "50%"
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "job_title",
|
||||
"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": "Job Opening",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Job Opening",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "job_title",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Job Opening",
|
||||
"options": "Job Opening"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "source",
|
||||
"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": "Source",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Job Applicant Source",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "source",
|
||||
"fieldtype": "Link",
|
||||
"label": "Source",
|
||||
"options": "Job Applicant Source"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval: doc.source==\"Employee Referral\" ",
|
||||
"fieldname": "source_name",
|
||||
"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": "Source Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Employee",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"depends_on": "eval: doc.source==\"Employee Referral\" ",
|
||||
"fieldname": "source_name",
|
||||
"fieldtype": "Link",
|
||||
"label": "Source Name",
|
||||
"options": "Employee"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_6",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "cover_letter",
|
||||
"fieldtype": "Text",
|
||||
"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": "Cover Letter",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "cover_letter",
|
||||
"fieldtype": "Text",
|
||||
"label": "Cover Letter"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "resume_attachment",
|
||||
"fieldtype": "Attach",
|
||||
"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": "Resume Attachment",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldname": "resume_attachment",
|
||||
"fieldtype": "Attach",
|
||||
"label": "Resume Attachment"
|
||||
},
|
||||
{
|
||||
"fieldname": "notes",
|
||||
"fieldtype": "Data",
|
||||
"label": "Notes",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "fa fa-user",
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-07-21 16:15:43.552049",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Job Applicant",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "fa fa-user",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2020-01-13 16:19:39.113330",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Job Applicant",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "applicant_name",
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_order": "ASC",
|
||||
"title_field": "applicant_name",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
],
|
||||
"search_fields": "applicant_name",
|
||||
"sender_field": "email_id",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"subject_field": "notes",
|
||||
"title_field": "applicant_name"
|
||||
}
|
||||
@@ -9,8 +9,6 @@ import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import comma_and, validate_email_address
|
||||
|
||||
sender_field = "email_id"
|
||||
|
||||
class DuplicationError(frappe.ValidationError): pass
|
||||
|
||||
class JobApplicant(Document):
|
||||
|
||||
@@ -30,16 +30,16 @@ class LeaveAllocation(Document):
|
||||
def validate_leave_allocation_days(self):
|
||||
company = frappe.db.get_value("Employee", self.employee, "company")
|
||||
leave_period = get_leave_period(self.from_date, self.to_date, company)
|
||||
max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
|
||||
max_leaves_allowed = flt(frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed"))
|
||||
if max_leaves_allowed > 0:
|
||||
leave_allocated = 0
|
||||
if leave_period:
|
||||
leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type,
|
||||
leave_period[0].from_date, leave_period[0].to_date)
|
||||
leave_allocated += self.new_leaves_allocated
|
||||
leave_allocated += flt(self.new_leaves_allocated)
|
||||
if leave_allocated > max_leaves_allowed:
|
||||
frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")
|
||||
.format(self.leave_type, self.employee))
|
||||
.format(self.leave_type, self.employee))
|
||||
|
||||
def on_submit(self):
|
||||
self.create_leave_ledger_entry()
|
||||
|
||||
@@ -130,7 +130,7 @@ class LeaveApplication(Document):
|
||||
if self.status == "Approved":
|
||||
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
|
||||
date = dt.strftime("%Y-%m-%d")
|
||||
status = "Half Day" if date == self.half_day_date else "On Leave"
|
||||
status = "Half Day" if getdate(date) == getdate(self.half_day_date) else "On Leave"
|
||||
|
||||
attendance_name = frappe.db.exists('Attendance', dict(employee = self.employee,
|
||||
attendance_date = date, docstatus = ('!=', 2)))
|
||||
@@ -374,7 +374,8 @@ class LeaveApplication(Document):
|
||||
leaves=self.total_leave_days * -1,
|
||||
from_date=self.from_date,
|
||||
to_date=self.to_date,
|
||||
is_lwp=lwp
|
||||
is_lwp=lwp,
|
||||
holiday_list=get_holiday_list_for_employee(self.employee)
|
||||
)
|
||||
create_leave_ledger_entry(self, args, submit)
|
||||
|
||||
@@ -384,7 +385,9 @@ class LeaveApplication(Document):
|
||||
from_date=self.from_date,
|
||||
to_date=expiry_date,
|
||||
leaves=(date_diff(expiry_date, self.from_date) + 1) * -1,
|
||||
is_lwp=lwp
|
||||
is_lwp=lwp,
|
||||
holiday_list=get_holiday_list_for_employee(self.employee),
|
||||
|
||||
)
|
||||
create_leave_ledger_entry(self, args, submit)
|
||||
|
||||
@@ -410,7 +413,7 @@ def get_allocation_expiry(employee, leave_type, to_date, from_date):
|
||||
return expiry[0]['to_date'] if expiry else None
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None):
|
||||
def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None, holiday_list = None):
|
||||
number_of_days = 0
|
||||
if cint(half_day) == 1:
|
||||
if from_date == to_date:
|
||||
@@ -424,7 +427,7 @@ def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day
|
||||
number_of_days = date_diff(to_date, from_date) + 1
|
||||
|
||||
if not frappe.db.get_value("Leave Type", leave_type, "include_holiday"):
|
||||
number_of_days = flt(number_of_days) - flt(get_holidays(employee, from_date, to_date))
|
||||
number_of_days = flt(number_of_days) - flt(get_holidays(employee, from_date, to_date, holiday_list=holiday_list))
|
||||
return number_of_days
|
||||
|
||||
@frappe.whitelist()
|
||||
@@ -575,24 +578,27 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date):
|
||||
{'name': leave_entry.transaction_name}, ['half_day_date'])
|
||||
|
||||
leave_days += get_number_of_leave_days(employee, leave_type,
|
||||
leave_entry.from_date, leave_entry.to_date, half_day, half_day_date) * -1
|
||||
leave_entry.from_date, leave_entry.to_date, half_day, half_day_date, holiday_list=leave_entry.holiday_list) * -1
|
||||
|
||||
return leave_days
|
||||
|
||||
def skip_expiry_leaves(leave_entry, date):
|
||||
''' Checks whether the expired leaves coincide with the to_date of leave balance check '''
|
||||
''' Checks whether the expired leaves coincide with the to_date of leave balance check.
|
||||
This allows backdated leave entry creation for non carry forwarded allocation '''
|
||||
end_date = frappe.db.get_value("Leave Allocation", {'name': leave_entry.transaction_name}, ['to_date'])
|
||||
return True if end_date == date and not leave_entry.is_carry_forward else False
|
||||
|
||||
def get_leave_entries(employee, leave_type, from_date, to_date):
|
||||
''' Returns leave entries between from_date and to_date '''
|
||||
''' Returns leave entries between from_date and to_date. '''
|
||||
return frappe.db.sql("""
|
||||
SELECT
|
||||
employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type,
|
||||
employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type, holiday_list,
|
||||
is_carry_forward, is_expired
|
||||
FROM `tabLeave Ledger Entry`
|
||||
WHERE employee=%(employee)s AND leave_type=%(leave_type)s
|
||||
AND docstatus=1 AND leaves<0
|
||||
AND docstatus=1
|
||||
AND (leaves<0
|
||||
OR is_expired=1)
|
||||
AND (from_date between %(from_date)s AND %(to_date)s
|
||||
OR to_date between %(from_date)s AND %(to_date)s
|
||||
OR (from_date < %(from_date)s AND to_date > %(to_date)s))
|
||||
@@ -604,9 +610,10 @@ def get_leave_entries(employee, leave_type, from_date, to_date):
|
||||
}, as_dict=1)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_holidays(employee, from_date, to_date):
|
||||
def get_holidays(employee, from_date, to_date, holiday_list = None):
|
||||
'''get holidays between two dates for the given employee'''
|
||||
holiday_list = get_holiday_list_for_employee(employee)
|
||||
if not holiday_list:
|
||||
holiday_list = get_holiday_list_for_employee(employee)
|
||||
|
||||
holidays = frappe.db.sql("""select count(distinct holiday_date) from `tabHoliday` h1, `tabHoliday List` h2
|
||||
where h1.parent = h2.name and h1.holiday_date between %s and %s
|
||||
@@ -687,8 +694,7 @@ def add_leaves(events, start, end, filter_conditions=None):
|
||||
"to_date": d.to_date,
|
||||
"docstatus": d.docstatus,
|
||||
"color": d.color,
|
||||
"title": cstr(d.employee_name) + \
|
||||
(d.half_day and _(" (Half Day)") or ""),
|
||||
"title": cstr(d.employee_name) + (' ' + _('(Half Day)') if d.half_day else ''),
|
||||
}
|
||||
if e not in events:
|
||||
events.append(e)
|
||||
|
||||
@@ -8,7 +8,6 @@ from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import getdate, nowdate, flt
|
||||
from erpnext.hr.utils import set_employee_name
|
||||
from erpnext.hr.doctype.leave_application.leave_application import get_leave_balance_on
|
||||
from erpnext.hr.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
|
||||
from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
|
||||
from erpnext.hr.doctype.leave_allocation.leave_allocation import get_unused_leaves
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2019-05-09 15:47:39.760406",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
@@ -12,6 +13,7 @@
|
||||
"column_break_7",
|
||||
"from_date",
|
||||
"to_date",
|
||||
"holiday_list",
|
||||
"is_carry_forward",
|
||||
"is_expired",
|
||||
"is_lwp",
|
||||
@@ -98,11 +100,18 @@
|
||||
"fieldname": "is_lwp",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Leave Without Pay"
|
||||
},
|
||||
{
|
||||
"fieldname": "holiday_list",
|
||||
"fieldtype": "Link",
|
||||
"label": "Holiday List",
|
||||
"options": "Holiday List"
|
||||
}
|
||||
],
|
||||
"in_create": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-08-20 14:40:04.130799",
|
||||
"links": [],
|
||||
"modified": "2020-02-27 14:40:10.502605",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Leave Ledger Entry",
|
||||
|
||||
@@ -141,6 +141,7 @@ def expire_allocation(allocation, expiry_date=None):
|
||||
leaves = get_remaining_leaves(allocation)
|
||||
expiry_date = expiry_date if expiry_date else allocation.to_date
|
||||
|
||||
# allows expired leaves entry to be created/reverted
|
||||
if leaves:
|
||||
args = dict(
|
||||
leaves=flt(leaves) * -1,
|
||||
@@ -160,6 +161,8 @@ def expire_carried_forward_allocation(allocation):
|
||||
from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period
|
||||
leaves_taken = get_leaves_for_period(allocation.employee, allocation.leave_type, allocation.from_date, allocation.to_date)
|
||||
leaves = flt(allocation.leaves) + flt(leaves_taken)
|
||||
|
||||
# allow expired leaves entry to be created
|
||||
if leaves > 0:
|
||||
args = frappe._dict(
|
||||
transaction_name=allocation.name,
|
||||
|
||||
@@ -13,7 +13,7 @@ from erpnext.hr.doctype.salary_slip.test_salary_slip import get_salary_component
|
||||
make_earning_salary_component, make_deduction_salary_component
|
||||
from erpnext.hr.doctype.salary_structure.test_salary_structure import make_salary_structure
|
||||
from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry
|
||||
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import make_accrual_interest_entry_for_term_loans
|
||||
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
|
||||
|
||||
class TestPayrollEntry(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@@ -81,7 +81,7 @@ class TestPayrollEntry(unittest.TestCase):
|
||||
|
||||
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1))
|
||||
|
||||
make_accrual_interest_entry_for_term_loans(posting_date=nowdate())
|
||||
process_loan_interest_accrual_for_term_loans(posting_date=nowdate())
|
||||
|
||||
|
||||
dates = get_start_end_dates('Monthly', nowdate())
|
||||
|
||||
@@ -1,401 +1,102 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
"autoname": "Prompt",
|
||||
"beta": 0,
|
||||
"creation": "2018-04-13 15:18:53.698553",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "Prompt",
|
||||
"creation": "2018-04-13 15:18:53.698553",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"company",
|
||||
"column_break_2",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"section_break_5",
|
||||
"periods"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company",
|
||||
"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": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "start_date",
|
||||
"fieldtype": "Date",
|
||||
"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",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "start_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Start Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "end_date",
|
||||
"fieldtype": "Date",
|
||||
"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",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "end_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "End Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 1,
|
||||
"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 Periods",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 1,
|
||||
"label": "Payroll Periods"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "periods",
|
||||
"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": "Payroll Periods",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Payroll Period Date",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_7",
|
||||
"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,
|
||||
"label": "Taxable Salary Slabs",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "taxable_salary_slabs",
|
||||
"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": "Taxable Salary Slabs",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Taxable Salary Slab",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "standard_tax_exemption_amount",
|
||||
"fieldtype": "Currency",
|
||||
"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": "Standard Tax Exemption Amount",
|
||||
"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,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldname": "periods",
|
||||
"fieldtype": "Table",
|
||||
"label": "Payroll Periods",
|
||||
"options": "Payroll Period Date"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-04-26 01:45:03.160929",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Payroll Period",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-03-18 18:13:23.859980",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Payroll Period",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 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": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -45,8 +45,9 @@ class PayrollPeriod(Document):
|
||||
+ _(") for {0}").format(self.company)
|
||||
frappe.throw(msg)
|
||||
|
||||
def get_payroll_period_days(start_date, end_date, employee):
|
||||
company = frappe.db.get_value("Employee", employee, "company")
|
||||
def get_payroll_period_days(start_date, end_date, employee, company=None):
|
||||
if not company:
|
||||
company = frappe.db.get_value("Employee", employee, "company")
|
||||
payroll_period = frappe.db.sql("""
|
||||
select name, start_date, end_date
|
||||
from `tabPayroll Period`
|
||||
|
||||
@@ -1,264 +1,263 @@
|
||||
{
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:salary_component",
|
||||
"creation": "2016-06-30 15:42:43.631931",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"salary_component",
|
||||
"salary_component_abbr",
|
||||
"type",
|
||||
"description",
|
||||
"column_break_4",
|
||||
"is_payable",
|
||||
"depends_on_payment_days",
|
||||
"is_tax_applicable",
|
||||
"deduct_full_tax_on_selected_payroll_date",
|
||||
"round_to_the_nearest_integer",
|
||||
"statistical_component",
|
||||
"do_not_include_in_total",
|
||||
"disabled",
|
||||
"flexible_benefits",
|
||||
"is_flexible_benefit",
|
||||
"max_benefit_amount",
|
||||
"column_break_9",
|
||||
"pay_against_benefit_claim",
|
||||
"only_tax_impact",
|
||||
"create_separate_payment_entry_against_benefit_claim",
|
||||
"section_break_11",
|
||||
"variable_based_on_taxable_salary",
|
||||
"section_break_5",
|
||||
"accounts",
|
||||
"condition_and_formula",
|
||||
"condition",
|
||||
"amount",
|
||||
"amount_based_on_formula",
|
||||
"formula",
|
||||
"column_break_28",
|
||||
"help"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "salary_component",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Name",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "salary_component_abbr",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Abbr",
|
||||
"print_width": "120px",
|
||||
"reqd": 1,
|
||||
"width": "120px"
|
||||
},
|
||||
{
|
||||
"fieldname": "type",
|
||||
"fieldtype": "Select",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Type",
|
||||
"options": "Earning\nDeduction",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"depends_on": "eval:doc.type == \"Earning\"",
|
||||
"fieldname": "is_tax_applicable",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Tax Applicable"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "is_payable",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Payable"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "depends_on_payment_days",
|
||||
"fieldtype": "Check",
|
||||
"label": "Depends on Payment Days",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "do_not_include_in_total",
|
||||
"fieldtype": "Check",
|
||||
"label": "Do Not Include in Total"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "is_tax_applicable",
|
||||
"fieldname": "deduct_full_tax_on_selected_payroll_date",
|
||||
"fieldtype": "Check",
|
||||
"label": "Deduct Full Tax on Selected Payroll Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disabled"
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
|
||||
"fieldname": "statistical_component",
|
||||
"fieldtype": "Check",
|
||||
"label": "Statistical Component"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.type==\"Earning\" && doc.statistical_component!=1",
|
||||
"fieldname": "flexible_benefits",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Flexible Benefits"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "is_flexible_benefit",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Flexible Benefit"
|
||||
},
|
||||
{
|
||||
"depends_on": "is_flexible_benefit",
|
||||
"fieldname": "max_benefit_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Max Benefit Amount (Yearly)"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "is_flexible_benefit",
|
||||
"fieldname": "pay_against_benefit_claim",
|
||||
"fieldtype": "Check",
|
||||
"label": "Pay Against Benefit Claim"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.is_flexible_benefit == 1 & doc.create_separate_payment_entry_against_benefit_claim !=1",
|
||||
"fieldname": "only_tax_impact",
|
||||
"fieldtype": "Check",
|
||||
"label": "Only Tax Impact (Cannot Claim But Part of Taxable Income)"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.is_flexible_benefit == 1 & doc.only_tax_impact !=1",
|
||||
"fieldname": "create_separate_payment_entry_against_benefit_claim",
|
||||
"fieldtype": "Check",
|
||||
"label": "Create Separate Payment Entry Against Benefit Claim"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.type=='Deduction'",
|
||||
"fieldname": "section_break_11",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "variable_based_on_taxable_salary",
|
||||
"fieldtype": "Check",
|
||||
"label": "Variable Based On Taxable Salary"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.statistical_component != 1",
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounts"
|
||||
},
|
||||
{
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"label": "Accounts",
|
||||
"options": "Salary Component Account"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"depends_on": "eval:doc.is_flexible_benefit != 1 && doc.variable_based_on_taxable_salary != 1",
|
||||
"fieldname": "condition_and_formula",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Condition and Formula"
|
||||
},
|
||||
{
|
||||
"fieldname": "condition",
|
||||
"fieldtype": "Code",
|
||||
"label": "Condition"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "amount_based_on_formula",
|
||||
"fieldtype": "Check",
|
||||
"label": "Amount based on formula"
|
||||
},
|
||||
{
|
||||
"depends_on": "amount_based_on_formula",
|
||||
"fieldname": "formula",
|
||||
"fieldtype": "Code",
|
||||
"label": "Formula"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.amount_based_on_formula!==1",
|
||||
"fieldname": "amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Amount"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_28",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Help",
|
||||
"options": "<h3>Help</h3>\n\n<p>Notes:</p>\n\n<ol>\n<li>Use field <code>base</code> for using base salary of the Employee</li>\n<li>Use Salary Component abbreviations in conditions and formulas. <code>BS = Basic Salary</code></li>\n<li>Use field name for employee details in conditions and formulas. <code>Employment Type = employment_type</code><code>Branch = branch</code></li>\n<li>Use field name from Salary Slip in conditions and formulas. <code>Payment Days = payment_days</code><code>Leave without pay = leave_without_pay</code></li>\n<li>Direct Amount can also be entered based on Condtion. See example 3</li></ol>\n\n<h4>Examples</h4>\n<ol>\n<li>Calculating Basic Salary based on <code>base</code>\n<pre><code>Condition: base < 10000</code></pre>\n<pre><code>Formula: base * .2</code></pre></li>\n<li>Calculating HRA based on Basic Salary<code>BS</code> \n<pre><code>Condition: BS > 2000</code></pre>\n<pre><code>Formula: BS * .1</code></pre></li>\n<li>Calculating TDS based on Employment Type<code>employment_type</code> \n<pre><code>Condition: employment_type==\"Intern\"</code></pre>\n<pre><code>Amount: 1000</code></pre></li>\n</ol>"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "round_to_the_nearest_integer",
|
||||
"fieldtype": "Check",
|
||||
"label": "Round to the Nearest Integer"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-flag",
|
||||
"modified": "2019-06-05 11:34:14.231228",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Component",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Employee"
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:salary_component",
|
||||
"creation": "2016-06-30 15:42:43.631931",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"salary_component",
|
||||
"salary_component_abbr",
|
||||
"type",
|
||||
"description",
|
||||
"column_break_4",
|
||||
"depends_on_payment_days",
|
||||
"is_tax_applicable",
|
||||
"deduct_full_tax_on_selected_payroll_date",
|
||||
"variable_based_on_taxable_salary",
|
||||
"exempted_from_income_tax",
|
||||
"round_to_the_nearest_integer",
|
||||
"statistical_component",
|
||||
"do_not_include_in_total",
|
||||
"disabled",
|
||||
"flexible_benefits",
|
||||
"is_flexible_benefit",
|
||||
"max_benefit_amount",
|
||||
"column_break_9",
|
||||
"pay_against_benefit_claim",
|
||||
"only_tax_impact",
|
||||
"create_separate_payment_entry_against_benefit_claim",
|
||||
"section_break_5",
|
||||
"accounts",
|
||||
"condition_and_formula",
|
||||
"condition",
|
||||
"amount",
|
||||
"amount_based_on_formula",
|
||||
"formula",
|
||||
"column_break_28",
|
||||
"help"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "salary_component",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Name",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "salary_component_abbr",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Abbr",
|
||||
"print_width": "120px",
|
||||
"reqd": 1,
|
||||
"width": "120px"
|
||||
},
|
||||
{
|
||||
"fieldname": "type",
|
||||
"fieldtype": "Select",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Type",
|
||||
"options": "Earning\nDeduction",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"depends_on": "eval:doc.type == \"Earning\"",
|
||||
"fieldname": "is_tax_applicable",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Tax Applicable"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "depends_on_payment_days",
|
||||
"fieldtype": "Check",
|
||||
"label": "Depends on Payment Days",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "do_not_include_in_total",
|
||||
"fieldtype": "Check",
|
||||
"label": "Do Not Include in Total"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.is_tax_applicable && doc.type=='Earning'",
|
||||
"fieldname": "deduct_full_tax_on_selected_payroll_date",
|
||||
"fieldtype": "Check",
|
||||
"label": "Deduct Full Tax on Selected Payroll Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disabled"
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
|
||||
"fieldname": "statistical_component",
|
||||
"fieldtype": "Check",
|
||||
"label": "Statistical Component"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.type==\"Earning\" && doc.statistical_component!=1",
|
||||
"fieldname": "flexible_benefits",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Flexible Benefits"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "is_flexible_benefit",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Flexible Benefit"
|
||||
},
|
||||
{
|
||||
"depends_on": "is_flexible_benefit",
|
||||
"fieldname": "max_benefit_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Max Benefit Amount (Yearly)"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "is_flexible_benefit",
|
||||
"fieldname": "pay_against_benefit_claim",
|
||||
"fieldtype": "Check",
|
||||
"label": "Pay Against Benefit Claim"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.is_flexible_benefit == 1 & doc.create_separate_payment_entry_against_benefit_claim !=1",
|
||||
"fieldname": "only_tax_impact",
|
||||
"fieldtype": "Check",
|
||||
"label": "Only Tax Impact (Cannot Claim But Part of Taxable Income)"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.is_flexible_benefit == 1 & doc.only_tax_impact !=1",
|
||||
"fieldname": "create_separate_payment_entry_against_benefit_claim",
|
||||
"fieldtype": "Check",
|
||||
"label": "Create Separate Payment Entry Against Benefit Claim"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.type == \"Deduction\"",
|
||||
"fieldname": "variable_based_on_taxable_salary",
|
||||
"fieldtype": "Check",
|
||||
"label": "Variable Based On Taxable Salary"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.statistical_component != 1",
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounts"
|
||||
},
|
||||
{
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"label": "Accounts",
|
||||
"options": "Salary Component Account"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"depends_on": "eval:doc.is_flexible_benefit != 1 && doc.variable_based_on_taxable_salary != 1",
|
||||
"fieldname": "condition_and_formula",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Condition and Formula"
|
||||
},
|
||||
{
|
||||
"fieldname": "condition",
|
||||
"fieldtype": "Code",
|
||||
"label": "Condition"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "amount_based_on_formula",
|
||||
"fieldtype": "Check",
|
||||
"label": "Amount based on formula"
|
||||
},
|
||||
{
|
||||
"depends_on": "amount_based_on_formula",
|
||||
"fieldname": "formula",
|
||||
"fieldtype": "Code",
|
||||
"label": "Formula"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.amount_based_on_formula!==1",
|
||||
"fieldname": "amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Amount"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_28",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Help",
|
||||
"options": "<h3>Help</h3>\n\n<p>Notes:</p>\n\n<ol>\n<li>Use field <code>base</code> for using base salary of the Employee</li>\n<li>Use Salary Component abbreviations in conditions and formulas. <code>BS = Basic Salary</code></li>\n<li>Use field name for employee details in conditions and formulas. <code>Employment Type = employment_type</code><code>Branch = branch</code></li>\n<li>Use field name from Salary Slip in conditions and formulas. <code>Payment Days = payment_days</code><code>Leave without pay = leave_without_pay</code></li>\n<li>Direct Amount can also be entered based on Condtion. See example 3</li></ol>\n\n<h4>Examples</h4>\n<ol>\n<li>Calculating Basic Salary based on <code>base</code>\n<pre><code>Condition: base < 10000</code></pre>\n<pre><code>Formula: base * .2</code></pre></li>\n<li>Calculating HRA based on Basic Salary<code>BS</code> \n<pre><code>Condition: BS > 2000</code></pre>\n<pre><code>Formula: BS * .1</code></pre></li>\n<li>Calculating TDS based on Employment Type<code>employment_type</code> \n<pre><code>Condition: employment_type==\"Intern\"</code></pre>\n<pre><code>Amount: 1000</code></pre></li>\n</ol>"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "round_to_the_nearest_integer",
|
||||
"fieldtype": "Check",
|
||||
"label": "Round to the Nearest Integer"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.type == \"Deduction\" && !doc.variable_based_on_taxable_salary",
|
||||
"description": "If checked, the full amount will be deducted from taxable income before calculating income tax. Otherwise, it can be exempted via Employee Tax Exemption Declaration.",
|
||||
"fieldname": "exempted_from_income_tax",
|
||||
"fieldtype": "Check",
|
||||
"label": "Exempted from Income Tax"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-flag",
|
||||
"links": [],
|
||||
"modified": "2020-04-24 14:50:28.994054",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Component",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Employee"
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
@@ -3,14 +3,12 @@
|
||||
"doctype": "Salary Component",
|
||||
"salary_component": "_Test Basic Salary",
|
||||
"type": "Earning",
|
||||
"is_payable": 1,
|
||||
"is_tax_applicable": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Salary Component",
|
||||
"salary_component": "_Test Allowance",
|
||||
"type": "Earning",
|
||||
"is_payable": 1,
|
||||
"is_tax_applicable": 1
|
||||
},
|
||||
{
|
||||
@@ -27,14 +25,12 @@
|
||||
"doctype": "Salary Component",
|
||||
"salary_component": "Basic",
|
||||
"type": "Earning",
|
||||
"is_payable": 1,
|
||||
"is_tax_applicable": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Salary Component",
|
||||
"salary_component": "Leave Encashment",
|
||||
"type": "Earning",
|
||||
"is_payable": 1,
|
||||
"is_tax_applicable": 1
|
||||
}
|
||||
]
|
||||
@@ -18,6 +18,5 @@ def create_salary_component(component_name, **args):
|
||||
"doctype": "Salary Component",
|
||||
"salary_component": component_name,
|
||||
"type": args.get("type") or "Earning",
|
||||
"is_payable": args.get("is_payable") or 1,
|
||||
"is_tax_applicable": args.get("is_tax_applicable") or 1
|
||||
}).insert()
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"deduct_full_tax_on_selected_payroll_date",
|
||||
"depends_on_payment_days",
|
||||
"is_tax_applicable",
|
||||
"exempted_from_income_tax",
|
||||
"is_flexible_benefit",
|
||||
"variable_based_on_taxable_salary",
|
||||
"section_break_2",
|
||||
@@ -63,6 +64,7 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.parentfield=='earnings'",
|
||||
"fetch_from": "salary_component.is_tax_applicable",
|
||||
"fieldname": "is_tax_applicable",
|
||||
"fieldtype": "Check",
|
||||
@@ -72,6 +74,7 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.parentfield=='earnings'",
|
||||
"fetch_from": "salary_component.is_flexible_benefit",
|
||||
"fieldname": "is_flexible_benefit",
|
||||
"fieldtype": "Check",
|
||||
@@ -81,6 +84,7 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.parentfield=='deductions'",
|
||||
"fetch_from": "salary_component.variable_based_on_taxable_salary",
|
||||
"fieldname": "variable_based_on_taxable_salary",
|
||||
"fieldtype": "Check",
|
||||
@@ -194,12 +198,20 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Additional Salary ",
|
||||
"options": "Additional Salary",
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.parentfield=='deductions'",
|
||||
"fetch_from": "salary_component.exempted_from_income_tax",
|
||||
"fieldname": "exempted_from_income_tax",
|
||||
"fieldtype": "Check",
|
||||
"label": "Exempted from Income Tax",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-03-02 18:16:38.571005",
|
||||
"modified": "2020-04-24 20:00:16.475295",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Detail",
|
||||
|
||||
@@ -51,7 +51,7 @@ frappe.ui.form.on("Salary Slip", {
|
||||
},
|
||||
|
||||
end_date: function(frm) {
|
||||
frm.events.get_emp_and_leave_details(frm);
|
||||
frm.events.get_emp_and_working_day_details(frm);
|
||||
},
|
||||
|
||||
set_end_date: function(frm){
|
||||
@@ -86,7 +86,7 @@ frappe.ui.form.on("Salary Slip", {
|
||||
|
||||
salary_slip_based_on_timesheet: function(frm) {
|
||||
frm.trigger("toggle_fields");
|
||||
frm.events.get_emp_and_leave_details(frm);
|
||||
frm.events.get_emp_and_working_day_details(frm);
|
||||
},
|
||||
|
||||
payroll_frequency: function(frm) {
|
||||
@@ -95,15 +95,14 @@ frappe.ui.form.on("Salary Slip", {
|
||||
},
|
||||
|
||||
employee: function(frm) {
|
||||
frm.events.get_emp_and_leave_details(frm);
|
||||
frm.events.get_emp_and_working_day_details(frm);
|
||||
},
|
||||
|
||||
leave_without_pay: function(frm){
|
||||
if (frm.doc.employee && frm.doc.start_date && frm.doc.end_date) {
|
||||
return frappe.call({
|
||||
method: 'process_salary_based_on_leave',
|
||||
method: 'process_salary_based_on_working_days',
|
||||
doc: frm.doc,
|
||||
args: {"lwp": frm.doc.leave_without_pay},
|
||||
callback: function(r, rt) {
|
||||
frm.refresh();
|
||||
}
|
||||
@@ -115,12 +114,12 @@ frappe.ui.form.on("Salary Slip", {
|
||||
frm.toggle_display(['hourly_wages', 'timesheets'], cint(frm.doc.salary_slip_based_on_timesheet)===1);
|
||||
|
||||
frm.toggle_display(['payment_days', 'total_working_days', 'leave_without_pay'],
|
||||
frm.doc.payroll_frequency!="");
|
||||
frm.doc.payroll_frequency != "");
|
||||
},
|
||||
|
||||
get_emp_and_leave_details: function(frm) {
|
||||
get_emp_and_working_day_details: function(frm) {
|
||||
return frappe.call({
|
||||
method: 'get_emp_and_leave_details',
|
||||
method: 'get_emp_and_working_day_details',
|
||||
doc: frm.doc,
|
||||
callback: function(r, rt) {
|
||||
frm.refresh();
|
||||
|
||||
@@ -11,20 +11,20 @@
|
||||
"employee_name",
|
||||
"department",
|
||||
"designation",
|
||||
"branch",
|
||||
"column_break1",
|
||||
"company",
|
||||
"status",
|
||||
"journal_entry",
|
||||
"payroll_entry",
|
||||
"company",
|
||||
"letter_head",
|
||||
"branch",
|
||||
"status",
|
||||
"section_break_10",
|
||||
"salary_slip_based_on_timesheet",
|
||||
"payroll_frequency",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"column_break_15",
|
||||
"salary_structure",
|
||||
"payroll_frequency",
|
||||
"total_working_days",
|
||||
"leave_without_pay",
|
||||
"payment_days",
|
||||
@@ -309,6 +309,7 @@
|
||||
{
|
||||
"fieldname": "earning",
|
||||
"fieldtype": "Column Break",
|
||||
"label": "Earning",
|
||||
"oldfieldtype": "Column Break",
|
||||
"width": "50%"
|
||||
},
|
||||
@@ -323,6 +324,7 @@
|
||||
{
|
||||
"fieldname": "deduction",
|
||||
"fieldtype": "Column Break",
|
||||
"label": "Deduction",
|
||||
"oldfieldtype": "Column Break",
|
||||
"width": "50%"
|
||||
},
|
||||
@@ -372,8 +374,7 @@
|
||||
"fieldtype": "Table",
|
||||
"label": "Employee Loan",
|
||||
"options": "Salary Slip Loan",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_43",
|
||||
@@ -464,7 +465,7 @@
|
||||
"idx": 9,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2019-12-31 17:13:45.146271",
|
||||
"modified": "2020-04-14 20:02:53.159827",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Slip",
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||
import frappe, erpnext
|
||||
import datetime, math
|
||||
|
||||
from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words
|
||||
from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, formatdate
|
||||
from frappe.model.naming import make_autoname
|
||||
|
||||
from frappe import msgprint, _
|
||||
@@ -44,9 +44,9 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
if not (len(self.get("earnings")) or len(self.get("deductions"))):
|
||||
# get details from salary structure
|
||||
self.get_emp_and_leave_details()
|
||||
self.get_emp_and_working_day_details()
|
||||
else:
|
||||
self.get_leave_details(lwp = self.leave_without_pay)
|
||||
self.get_working_days_details(lwp = self.leave_without_pay)
|
||||
|
||||
self.calculate_net_pay()
|
||||
|
||||
@@ -116,7 +116,7 @@ class SalarySlip(TransactionBase):
|
||||
self.start_date = date_details.start_date
|
||||
self.end_date = date_details.end_date
|
||||
|
||||
def get_emp_and_leave_details(self):
|
||||
def get_emp_and_working_day_details(self):
|
||||
'''First time, load all the components from salary structure'''
|
||||
if self.employee:
|
||||
self.set("earnings", [])
|
||||
@@ -128,7 +128,8 @@ class SalarySlip(TransactionBase):
|
||||
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
||||
["date_of_joining", "relieving_date"])
|
||||
|
||||
self.get_leave_details(joining_date, relieving_date)
|
||||
#getin leave details
|
||||
self.get_working_days_details(joining_date, relieving_date)
|
||||
struct = self.check_sal_struct(joining_date, relieving_date)
|
||||
|
||||
if struct:
|
||||
@@ -187,10 +188,9 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
make_salary_slip(self._salary_structure_doc.name, self)
|
||||
|
||||
def get_leave_details(self, joining_date=None, relieving_date=None, lwp=None, for_preview=0):
|
||||
if not joining_date:
|
||||
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
||||
["date_of_joining", "relieving_date"])
|
||||
def get_working_days_details(self, joining_date=None, relieving_date=None, lwp=None, for_preview=0):
|
||||
payroll_based_on = frappe.db.get_value("HR Settings", None, "payroll_based_on")
|
||||
include_holidays_in_total_working_days = frappe.db.get_single_value("HR Settings", "include_holidays_in_total_working_days")
|
||||
|
||||
working_days = date_diff(self.end_date, self.start_date) + 1
|
||||
if for_preview:
|
||||
@@ -199,24 +199,42 @@ class SalarySlip(TransactionBase):
|
||||
return
|
||||
|
||||
holidays = self.get_holidays_for_employee(self.start_date, self.end_date)
|
||||
actual_lwp = self.calculate_lwp(holidays, working_days)
|
||||
if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")):
|
||||
|
||||
if not cint(include_holidays_in_total_working_days):
|
||||
working_days -= len(holidays)
|
||||
if working_days < 0:
|
||||
frappe.throw(_("There are more holidays than working days this month."))
|
||||
|
||||
if not payroll_based_on:
|
||||
frappe.throw(_("Please set Payroll based on in HR settings"))
|
||||
|
||||
if payroll_based_on == "Attendance":
|
||||
actual_lwp = self.calculate_lwp_based_on_attendance(holidays)
|
||||
else:
|
||||
actual_lwp = self.calculate_lwp_based_on_leave_application(holidays, working_days)
|
||||
|
||||
if not lwp:
|
||||
lwp = actual_lwp
|
||||
elif lwp != actual_lwp:
|
||||
frappe.msgprint(_("Leave Without Pay does not match with approved Leave Application records"))
|
||||
frappe.msgprint(_("Leave Without Pay does not match with approved {} records")
|
||||
.format(payroll_based_on))
|
||||
|
||||
self.total_working_days = working_days
|
||||
self.leave_without_pay = lwp
|
||||
self.total_working_days = working_days
|
||||
|
||||
payment_days = flt(self.get_payment_days(joining_date, relieving_date)) - flt(lwp)
|
||||
self.payment_days = payment_days > 0 and payment_days or 0
|
||||
payment_days = self.get_payment_days(joining_date,
|
||||
relieving_date, include_holidays_in_total_working_days)
|
||||
|
||||
if flt(payment_days) > flt(lwp):
|
||||
self.payment_days = flt(payment_days) - flt(lwp)
|
||||
else:
|
||||
self.payment_days = 0
|
||||
|
||||
def get_payment_days(self, joining_date, relieving_date, include_holidays_in_total_working_days):
|
||||
if not joining_date:
|
||||
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
||||
["date_of_joining", "relieving_date"])
|
||||
|
||||
def get_payment_days(self, joining_date, relieving_date):
|
||||
start_date = getdate(self.start_date)
|
||||
if joining_date:
|
||||
if getdate(self.start_date) <= joining_date <= getdate(self.end_date):
|
||||
@@ -234,9 +252,10 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
payment_days = date_diff(end_date, start_date) + 1
|
||||
|
||||
if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")):
|
||||
if not cint(include_holidays_in_total_working_days):
|
||||
holidays = self.get_holidays_for_employee(start_date, end_date)
|
||||
payment_days -= len(holidays)
|
||||
|
||||
return payment_days
|
||||
|
||||
def get_holidays_for_employee(self, start_date, end_date):
|
||||
@@ -255,27 +274,67 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
return holidays
|
||||
|
||||
def calculate_lwp(self, holidays, working_days):
|
||||
def calculate_lwp_based_on_leave_application(self, holidays, working_days):
|
||||
lwp = 0
|
||||
holidays = "','".join(holidays)
|
||||
daily_wages_fraction_for_half_day = \
|
||||
flt(frappe.db.get_value("HR Settings", None, "daily_wages_fraction_for_half_day")) or 0.5
|
||||
|
||||
for d in range(working_days):
|
||||
dt = add_days(cstr(getdate(self.start_date)), d)
|
||||
leave = frappe.db.sql("""
|
||||
SELECT t1.name,
|
||||
CASE WHEN t1.half_day_date = %(dt)s or t1.to_date = t1.from_date
|
||||
CASE WHEN (t1.half_day_date = %(dt)s or t1.to_date = t1.from_date)
|
||||
THEN t1.half_day else 0 END
|
||||
FROM `tabLeave Application` t1, `tabLeave Type` t2
|
||||
WHERE t2.name = t1.leave_type
|
||||
AND t2.is_lwp = 1
|
||||
AND t1.docstatus = 1
|
||||
AND t1.employee = %(employee)s
|
||||
AND CASE WHEN t2.include_holiday != 1 THEN %(dt)s not in ('{0}') and %(dt)s between from_date and to_date and ifnull(t1.salary_slip, '') = ''
|
||||
WHEN t2.include_holiday THEN %(dt)s between from_date and to_date and ifnull(t1.salary_slip, '') = ''
|
||||
END
|
||||
AND ifnull(t1.salary_slip, '') = ''
|
||||
AND CASE
|
||||
WHEN t2.include_holiday != 1
|
||||
THEN %(dt)s not in ('{0}') and %(dt)s between from_date and to_date
|
||||
WHEN t2.include_holiday
|
||||
THEN %(dt)s between from_date and to_date
|
||||
END
|
||||
""".format(holidays), {"employee": self.employee, "dt": dt})
|
||||
|
||||
if leave:
|
||||
lwp = cint(leave[0][1]) and (lwp + 0.5) or (lwp + 1)
|
||||
is_half_day_leave = cint(leave[0][1])
|
||||
lwp += (1 - daily_wages_fraction_for_half_day) if is_half_day_leave else 1
|
||||
|
||||
return lwp
|
||||
|
||||
def calculate_lwp_based_on_attendance(self, holidays):
|
||||
lwp = 0
|
||||
|
||||
daily_wages_fraction_for_half_day = \
|
||||
flt(frappe.db.get_value("HR Settings", None, "daily_wages_fraction_for_half_day")) or 0.5
|
||||
|
||||
lwp_leave_types = dict(frappe.get_all("Leave Type", {"is_lwp": 1}, ["name", "include_holiday"], as_list=1))
|
||||
|
||||
attendances = frappe.db.sql('''
|
||||
SELECT attendance_date, status, leave_type
|
||||
FROM `tabAttendance`
|
||||
WHERE
|
||||
status in ("Absent", "Half Day", "On leave")
|
||||
AND employee = %s
|
||||
AND docstatus = 1
|
||||
AND attendance_date between %s and %s
|
||||
''', values=(self.employee, self.start_date, self.end_date), as_dict=1)
|
||||
|
||||
for d in attendances:
|
||||
if d.status in ('Half Day', 'On Leave') and d.leave_type and d.leave_type not in lwp_leave_types:
|
||||
continue
|
||||
|
||||
if formatdate(d.attendance_date, "yyyy-mm-dd") in holidays:
|
||||
if d.status == "Absent" or \
|
||||
(d.leave_type and d.leave_type in lwp_leave_types and not lwp_leave_types[d.leave_type]):
|
||||
continue
|
||||
|
||||
lwp += (1 - daily_wages_fraction_for_half_day) if d.status == "Half Day" else 1
|
||||
|
||||
return lwp
|
||||
|
||||
def add_earning_for_hourly_wages(self, doc, salary_component, amount):
|
||||
@@ -355,13 +414,13 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
def eval_condition_and_formula(self, d, data):
|
||||
try:
|
||||
condition = d.condition.strip() if d.condition else None
|
||||
condition = d.condition.strip().replace("\n", " ") if d.condition else None
|
||||
if condition:
|
||||
if not frappe.safe_eval(condition, self.whitelisted_globals, data):
|
||||
return None
|
||||
amount = d.amount
|
||||
if d.amount_based_on_formula:
|
||||
formula = d.formula.strip() if d.formula else None
|
||||
formula = d.formula.strip().replace("\n", " ") if d.formula else None
|
||||
if formula:
|
||||
amount = flt(frappe.safe_eval(formula, self.whitelisted_globals, data), d.precision("amount"))
|
||||
if amount:
|
||||
@@ -451,7 +510,8 @@ class SalarySlip(TransactionBase):
|
||||
'is_flexible_benefit': struct_row.is_flexible_benefit,
|
||||
'variable_based_on_taxable_salary': struct_row.variable_based_on_taxable_salary,
|
||||
'deduct_full_tax_on_selected_payroll_date': struct_row.deduct_full_tax_on_selected_payroll_date,
|
||||
'additional_amount': amount if struct_row.get("is_additional_component") else 0
|
||||
'additional_amount': amount if struct_row.get("is_additional_component") else 0,
|
||||
'exempted_from_income_tax': struct_row.exempted_from_income_tax
|
||||
})
|
||||
else:
|
||||
if struct_row.get("is_additional_component"):
|
||||
@@ -483,10 +543,12 @@ class SalarySlip(TransactionBase):
|
||||
return self.calculate_variable_tax(payroll_period, tax_component)
|
||||
|
||||
def calculate_variable_tax(self, payroll_period, tax_component):
|
||||
# get Tax slab from salary structure assignment for the employee and payroll period
|
||||
tax_slab = self.get_income_tax_slabs(payroll_period)
|
||||
|
||||
# get remaining numbers of sub-period (period for which one salary is processed)
|
||||
remaining_sub_periods = get_period_factor(self.employee,
|
||||
self.start_date, self.end_date, self.payroll_frequency, payroll_period)[1]
|
||||
|
||||
# get taxable_earnings, paid_taxes for previous period
|
||||
previous_taxable_earnings = self.get_taxable_earnings_for_prev_period(payroll_period.start_date, self.start_date)
|
||||
previous_total_paid_taxes = self.get_tax_paid_in_period(payroll_period.start_date, self.start_date, tax_component)
|
||||
@@ -508,23 +570,27 @@ class SalarySlip(TransactionBase):
|
||||
unclaimed_taxable_benefits += current_taxable_earnings_for_payment_days.flexi_benefits
|
||||
|
||||
# Total exemption amount based on tax exemption declaration
|
||||
total_exemption_amount, other_incomes = self.get_total_exemption_amount_and_other_incomes(payroll_period)
|
||||
total_exemption_amount = self.get_total_exemption_amount(payroll_period, tax_slab)
|
||||
|
||||
#Employee Other Incomes
|
||||
other_incomes = self.get_income_form_other_sources(payroll_period) or 0.0
|
||||
|
||||
# Total taxable earnings including additional and other incomes
|
||||
total_taxable_earnings = previous_taxable_earnings + current_structured_taxable_earnings + future_structured_taxable_earnings \
|
||||
+ current_additional_earnings + other_incomes + unclaimed_taxable_benefits - total_exemption_amount
|
||||
|
||||
|
||||
# Total taxable earnings without additional earnings with full tax
|
||||
total_taxable_earnings_without_full_tax_addl_components = total_taxable_earnings - current_additional_earnings_with_full_tax
|
||||
|
||||
# Structured tax amount
|
||||
total_structured_tax_amount = self.calculate_tax_by_tax_slab(payroll_period, total_taxable_earnings_without_full_tax_addl_components)
|
||||
total_structured_tax_amount = self.calculate_tax_by_tax_slab(
|
||||
total_taxable_earnings_without_full_tax_addl_components, tax_slab)
|
||||
current_structured_tax_amount = (total_structured_tax_amount - previous_total_paid_taxes) / remaining_sub_periods
|
||||
|
||||
|
||||
# Total taxable earnings with additional earnings with full tax
|
||||
full_tax_on_additional_earnings = 0.0
|
||||
if current_additional_earnings_with_full_tax:
|
||||
total_tax_amount = self.calculate_tax_by_tax_slab(payroll_period, total_taxable_earnings)
|
||||
total_tax_amount = self.calculate_tax_by_tax_slab(total_taxable_earnings, tax_slab)
|
||||
full_tax_on_additional_earnings = total_tax_amount - total_structured_tax_amount
|
||||
|
||||
current_tax_amount = current_structured_tax_amount + full_tax_on_additional_earnings
|
||||
@@ -533,12 +599,30 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
return current_tax_amount
|
||||
|
||||
def get_income_tax_slabs(self, payroll_period):
|
||||
income_tax_slab, ss_assignment_name = frappe.db.get_value("Salary Structure Assignment",
|
||||
{"employee": self.employee, "salary_structure": self.salary_structure, "docstatus": 1}, ["income_tax_slab", 'name'])
|
||||
|
||||
if not income_tax_slab:
|
||||
frappe.throw(_("Income Tax Slab not set in Salary Structure Assignment: {0}").format(ss_assignment_name))
|
||||
|
||||
income_tax_slab_doc = frappe.get_doc("Income Tax Slab", income_tax_slab)
|
||||
if income_tax_slab_doc.disabled:
|
||||
frappe.throw(_("Income Tax Slab: {0} is disabled").format(income_tax_slab))
|
||||
|
||||
if getdate(income_tax_slab_doc.effective_from) > getdate(payroll_period.start_date):
|
||||
frappe.throw(_("Income Tax Slab must be effective on or before Payroll Period Start Date: {0}")
|
||||
.format(payroll_period.start_date))
|
||||
|
||||
return income_tax_slab_doc
|
||||
|
||||
|
||||
def get_taxable_earnings_for_prev_period(self, start_date, end_date):
|
||||
taxable_earnings = frappe.db.sql("""
|
||||
select sum(sd.amount)
|
||||
from
|
||||
`tabSalary Detail` sd join `tabSalary Slip` ss on sd.parent=ss.name
|
||||
where
|
||||
where
|
||||
sd.parentfield='earnings'
|
||||
and sd.is_tax_applicable=1
|
||||
and is_flexible_benefit=0
|
||||
@@ -551,7 +635,28 @@ class SalarySlip(TransactionBase):
|
||||
"from_date": start_date,
|
||||
"to_date": end_date
|
||||
})
|
||||
return flt(taxable_earnings[0][0]) if taxable_earnings else 0
|
||||
taxable_earnings = flt(taxable_earnings[0][0]) if taxable_earnings else 0
|
||||
|
||||
exempted_amount = frappe.db.sql("""
|
||||
select sum(sd.amount)
|
||||
from
|
||||
`tabSalary Detail` sd join `tabSalary Slip` ss on sd.parent=ss.name
|
||||
where
|
||||
sd.parentfield='deductions'
|
||||
and sd.exempted_from_income_tax=1
|
||||
and is_flexible_benefit=0
|
||||
and ss.docstatus=1
|
||||
and ss.employee=%(employee)s
|
||||
and ss.start_date between %(from_date)s and %(to_date)s
|
||||
and ss.end_date between %(from_date)s and %(to_date)s
|
||||
""", {
|
||||
"employee": self.employee,
|
||||
"from_date": start_date,
|
||||
"to_date": end_date
|
||||
})
|
||||
exempted_amount = flt(exempted_amount[0][0]) if exempted_amount else 0
|
||||
|
||||
return taxable_earnings - exempted_amount
|
||||
|
||||
def get_tax_paid_in_period(self, start_date, end_date, tax_component):
|
||||
# find total_tax_paid, tax paid for benefit, additional_salary
|
||||
@@ -611,6 +716,13 @@ class SalarySlip(TransactionBase):
|
||||
else:
|
||||
taxable_earnings += amount
|
||||
|
||||
for ded in self.deductions:
|
||||
if ded.exempted_from_income_tax:
|
||||
amount = ded.amount
|
||||
if based_on_payment_days:
|
||||
amount = self.get_amount_based_on_payment_days(ded, joining_date, relieving_date)[0]
|
||||
taxable_earnings -= flt(amount)
|
||||
|
||||
return frappe._dict({
|
||||
"taxable_earnings": taxable_earnings,
|
||||
"additional_income": additional_income,
|
||||
@@ -673,40 +785,63 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
return total_benefits_paid - total_benefits_claimed
|
||||
|
||||
def get_total_exemption_amount_and_other_incomes(self, payroll_period):
|
||||
total_exemption_amount, other_incomes = 0, 0
|
||||
if self.deduct_tax_for_unsubmitted_tax_exemption_proof:
|
||||
exemption_proof = frappe.db.get_value("Employee Tax Exemption Proof Submission",
|
||||
{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
|
||||
["exemption_amount", "income_from_other_sources"])
|
||||
if exemption_proof:
|
||||
total_exemption_amount, other_incomes = exemption_proof
|
||||
else:
|
||||
declaration = frappe.db.get_value("Employee Tax Exemption Declaration",
|
||||
{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
|
||||
["total_exemption_amount", "income_from_other_sources"])
|
||||
if declaration:
|
||||
total_exemption_amount, other_incomes = declaration
|
||||
def get_total_exemption_amount(self, payroll_period, tax_slab):
|
||||
total_exemption_amount = 0
|
||||
if tax_slab.allow_tax_exemption:
|
||||
if self.deduct_tax_for_unsubmitted_tax_exemption_proof:
|
||||
exemption_proof = frappe.db.get_value("Employee Tax Exemption Proof Submission",
|
||||
{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
|
||||
["exemption_amount"])
|
||||
if exemption_proof:
|
||||
total_exemption_amount = exemption_proof
|
||||
else:
|
||||
declaration = frappe.db.get_value("Employee Tax Exemption Declaration",
|
||||
{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
|
||||
["total_exemption_amount"])
|
||||
if declaration:
|
||||
total_exemption_amount = declaration
|
||||
|
||||
return total_exemption_amount, other_incomes
|
||||
total_exemption_amount += flt(tax_slab.standard_tax_exemption_amount)
|
||||
|
||||
def calculate_tax_by_tax_slab(self, payroll_period, annual_taxable_earning):
|
||||
payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period)
|
||||
annual_taxable_earning -= flt(payroll_period_obj.standard_tax_exemption_amount)
|
||||
return total_exemption_amount
|
||||
|
||||
def get_income_form_other_sources(self, payroll_period):
|
||||
return frappe.get_all("Employee Other Income",
|
||||
filters={
|
||||
"employee": self.employee,
|
||||
"payroll_period": payroll_period.name,
|
||||
"company": self.company,
|
||||
"docstatus": 1
|
||||
},
|
||||
fields="SUM(amount) as total_amount"
|
||||
)[0].total_amount
|
||||
|
||||
def calculate_tax_by_tax_slab(self, annual_taxable_earning, tax_slab):
|
||||
data = self.get_data_for_eval()
|
||||
data.update({"annual_taxable_earning": annual_taxable_earning})
|
||||
taxable_amount = 0
|
||||
for slab in payroll_period_obj.taxable_salary_slabs:
|
||||
tax_amount = 0
|
||||
for slab in tax_slab.slabs:
|
||||
if slab.condition and not self.eval_tax_slab_condition(slab.condition, data):
|
||||
continue
|
||||
if not slab.to_amount and annual_taxable_earning > slab.from_amount:
|
||||
taxable_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
|
||||
tax_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
|
||||
continue
|
||||
if annual_taxable_earning > slab.from_amount and annual_taxable_earning < slab.to_amount:
|
||||
taxable_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
|
||||
tax_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
|
||||
elif annual_taxable_earning > slab.from_amount and annual_taxable_earning > slab.to_amount:
|
||||
taxable_amount += (slab.to_amount - slab.from_amount) * slab.percent_deduction * .01
|
||||
return taxable_amount
|
||||
tax_amount += (slab.to_amount - slab.from_amount) * slab.percent_deduction * .01
|
||||
|
||||
# other taxes and charges on income tax
|
||||
for d in tax_slab.other_taxes_and_charges:
|
||||
if flt(d.min_taxable_income) and flt(d.min_taxable_income) > tax_amount:
|
||||
continue
|
||||
|
||||
if flt(d.max_taxable_income) and flt(d.max_taxable_income) < tax_amount:
|
||||
continue
|
||||
|
||||
tax_amount += tax_amount * flt(d.percent) / 100
|
||||
|
||||
return tax_amount
|
||||
|
||||
def eval_tax_slab_condition(self, condition, data):
|
||||
try:
|
||||
@@ -756,30 +891,37 @@ class SalarySlip(TransactionBase):
|
||||
d.amount = self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0]
|
||||
|
||||
def set_loan_repayment(self):
|
||||
self.set('loans', [])
|
||||
self.total_loan_repayment = 0
|
||||
self.total_interest_amount = 0
|
||||
self.total_principal_amount = 0
|
||||
|
||||
for loan in self.get_loan_details():
|
||||
if not self.get('loans'):
|
||||
for loan in self.get_loan_details():
|
||||
|
||||
amounts = calculate_amounts(loan.name, self.posting_date, "Regular Payment")
|
||||
amounts = calculate_amounts(loan.name, self.posting_date, "Regular Payment")
|
||||
|
||||
total_payment = amounts['interest_amount'] + amounts['payable_principal_amount']
|
||||
if amounts['interest_amount'] or amounts['payable_principal_amount']:
|
||||
self.append('loans', {
|
||||
'loan': loan.name,
|
||||
'total_payment': amounts['interest_amount'] + amounts['payable_principal_amount'],
|
||||
'interest_amount': amounts['interest_amount'],
|
||||
'principal_amount': amounts['payable_principal_amount'],
|
||||
'loan_account': loan.loan_account,
|
||||
'interest_income_account': loan.interest_income_account
|
||||
})
|
||||
|
||||
if total_payment:
|
||||
self.append('loans', {
|
||||
'loan': loan.name,
|
||||
'total_payment': total_payment,
|
||||
'interest_amount': amounts['interest_amount'],
|
||||
'principal_amount': amounts['payable_principal_amount'],
|
||||
'loan_account': loan.loan_account,
|
||||
'interest_income_account': loan.interest_income_account
|
||||
})
|
||||
for payment in self.get('loans'):
|
||||
amounts = calculate_amounts(payment.loan, self.posting_date, "Regular Payment")
|
||||
total_amount = amounts['interest_amount'] + amounts['payable_principal_amount']
|
||||
if payment.total_payment > total_amount:
|
||||
frappe.throw(_("""Row {0}: Paid amount {1} is greater than pending accrued amount {2}
|
||||
against loan {3}""").format(payment.idx, frappe.bold(payment.total_payment),
|
||||
frappe.bold(total_amount), frappe.bold(payment.loan)))
|
||||
|
||||
self.total_loan_repayment += total_payment
|
||||
self.total_interest_amount += amounts['interest_amount']
|
||||
self.total_principal_amount += amounts['payable_principal_amount']
|
||||
self.total_interest_amount += payment.interest_amount
|
||||
self.total_principal_amount += payment.principal_amount
|
||||
|
||||
self.total_loan_repayment += payment.total_payment
|
||||
|
||||
def get_loan_details(self):
|
||||
|
||||
@@ -855,7 +997,7 @@ class SalarySlip(TransactionBase):
|
||||
if not self.salary_slip_based_on_timesheet:
|
||||
self.get_date_details()
|
||||
self.pull_emp_details()
|
||||
self.get_leave_details(for_preview=for_preview)
|
||||
self.get_working_days_details(for_preview=for_preview)
|
||||
self.calculate_net_pay()
|
||||
|
||||
def pull_emp_details(self):
|
||||
@@ -864,8 +1006,8 @@ class SalarySlip(TransactionBase):
|
||||
self.bank_name = emp.bank_name
|
||||
self.bank_account_no = emp.bank_ac_no
|
||||
|
||||
def process_salary_based_on_leave(self, lwp=0):
|
||||
self.get_leave_details(lwp=lwp)
|
||||
def process_salary_based_on_working_days(self):
|
||||
self.get_working_days_details(lwp=self.leave_without_pay)
|
||||
self.calculate_net_pay()
|
||||
|
||||
def unlink_ref_doc_from_salary_slip(ref_no):
|
||||
|
||||
@@ -21,18 +21,105 @@ class TestSalarySlip(unittest.TestCase):
|
||||
make_earning_salary_component(setup=True, company_list=["_Test Company"])
|
||||
make_deduction_salary_component(setup=True, company_list=["_Test Company"])
|
||||
|
||||
for dt in ["Leave Application", "Leave Allocation", "Salary Slip"]:
|
||||
for dt in ["Leave Application", "Leave Allocation", "Salary Slip", "Attendance"]:
|
||||
frappe.db.sql("delete from `tab%s`" % dt)
|
||||
|
||||
self.make_holiday_list()
|
||||
|
||||
frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", "Salary Slip Test Holiday List")
|
||||
frappe.db.set_value("HR Settings", None, "email_salary_slip_to_employee", 0)
|
||||
|
||||
frappe.db.set_value('HR Settings', None, 'leave_status_notification_template', None)
|
||||
frappe.db.set_value('HR Settings', None, 'leave_approval_notification_template', None)
|
||||
|
||||
def tearDown(self):
|
||||
frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0)
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
def test_payment_days_based_on_attendance(self):
|
||||
from erpnext.hr.doctype.attendance.attendance import mark_attendance
|
||||
no_of_days = self.get_no_of_days()
|
||||
|
||||
# Payroll based on attendance
|
||||
frappe.db.set_value("HR Settings", None, "payroll_based_on", "Attendance")
|
||||
frappe.db.set_value("HR Settings", None, "daily_wages_fraction_for_half_day", 0.75)
|
||||
|
||||
emp_id = make_employee("test_for_attendance@salary.com")
|
||||
frappe.db.set_value("Employee", emp_id, {"relieving_date": None, "status": "Active"})
|
||||
|
||||
frappe.db.set_value("Leave Type", "Leave Without Pay", "include_holiday", 0)
|
||||
|
||||
month_start_date = get_first_day(nowdate())
|
||||
month_end_date = get_last_day(nowdate())
|
||||
|
||||
first_sunday = frappe.db.sql("""
|
||||
select holiday_date from `tabHoliday`
|
||||
where parent = 'Salary Slip Test Holiday List'
|
||||
and holiday_date between %s and %s
|
||||
order by holiday_date
|
||||
""", (month_start_date, month_end_date))[0][0]
|
||||
|
||||
mark_attendance(emp_id, first_sunday, 'Absent', ignore_validate=True) # invalid lwp
|
||||
mark_attendance(emp_id, add_days(first_sunday, 1), 'Absent', ignore_validate=True) # valid lwp
|
||||
mark_attendance(emp_id, add_days(first_sunday, 2), 'Half Day', leave_type='Leave Without Pay', ignore_validate=True) # valid 0.75 lwp
|
||||
mark_attendance(emp_id, add_days(first_sunday, 3), 'On Leave', leave_type='Leave Without Pay', ignore_validate=True) # valid lwp
|
||||
mark_attendance(emp_id, add_days(first_sunday, 4), 'On Leave', leave_type='Casual Leave', ignore_validate=True) # invalid lwp
|
||||
mark_attendance(emp_id, add_days(first_sunday, 7), 'On Leave', leave_type='Leave Without Pay', ignore_validate=True) # invalid lwp
|
||||
|
||||
ss = make_employee_salary_slip("test_for_attendance@salary.com", "Monthly")
|
||||
|
||||
self.assertEqual(ss.leave_without_pay, 2.25)
|
||||
|
||||
days_in_month = no_of_days[0]
|
||||
no_of_holidays = no_of_days[1]
|
||||
|
||||
self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 2.25)
|
||||
|
||||
#Gross pay calculation based on attendances
|
||||
gross_pay = 78000 - ((78000 / (days_in_month - no_of_holidays)) * flt(ss.leave_without_pay))
|
||||
|
||||
self.assertEqual(ss.gross_pay, gross_pay)
|
||||
|
||||
frappe.db.set_value("HR Settings", None, "payroll_based_on", "Leave")
|
||||
|
||||
def test_payment_days_based_on_leave_application(self):
|
||||
no_of_days = self.get_no_of_days()
|
||||
|
||||
# Payroll based on attendance
|
||||
frappe.db.set_value("HR Settings", None, "payroll_based_on", "Leave")
|
||||
|
||||
emp_id = make_employee("test_for_attendance@salary.com")
|
||||
frappe.db.set_value("Employee", emp_id, {"relieving_date": None, "status": "Active"})
|
||||
|
||||
frappe.db.set_value("Leave Type", "Leave Without Pay", "include_holiday", 0)
|
||||
|
||||
month_start_date = get_first_day(nowdate())
|
||||
month_end_date = get_last_day(nowdate())
|
||||
|
||||
first_sunday = frappe.db.sql("""
|
||||
select holiday_date from `tabHoliday`
|
||||
where parent = 'Salary Slip Test Holiday List'
|
||||
and holiday_date between %s and %s
|
||||
order by holiday_date
|
||||
""", (month_start_date, month_end_date))[0][0]
|
||||
|
||||
make_leave_application(emp_id, first_sunday, add_days(first_sunday, 3), "Leave Without Pay")
|
||||
|
||||
ss = make_employee_salary_slip("test_for_attendance@salary.com", "Monthly")
|
||||
|
||||
self.assertEqual(ss.leave_without_pay, 3)
|
||||
|
||||
days_in_month = no_of_days[0]
|
||||
no_of_holidays = no_of_days[1]
|
||||
|
||||
self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 3)
|
||||
|
||||
#Gross pay calculation based on attendances
|
||||
gross_pay = 78000 - ((78000 / (days_in_month - no_of_holidays)) * flt(ss.leave_without_pay))
|
||||
|
||||
self.assertEqual(ss.gross_pay, gross_pay)
|
||||
|
||||
frappe.db.set_value("HR Settings", None, "payroll_based_on", "Leave")
|
||||
|
||||
def test_salary_slip_with_holidays_included(self):
|
||||
no_of_days = self.get_no_of_days()
|
||||
frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 1)
|
||||
@@ -47,10 +134,7 @@ class TestSalarySlip(unittest.TestCase):
|
||||
self.assertEqual(ss.payment_days, no_of_days[0])
|
||||
self.assertEqual(ss.earnings[0].amount, 50000)
|
||||
self.assertEqual(ss.earnings[1].amount, 3000)
|
||||
self.assertEqual(ss.deductions[0].amount, 5000)
|
||||
self.assertEqual(ss.deductions[1].amount, 5000)
|
||||
self.assertEqual(ss.gross_pay, 78000)
|
||||
self.assertEqual(ss.net_pay, 68000.0)
|
||||
|
||||
def test_salary_slip_with_holidays_excluded(self):
|
||||
no_of_days = self.get_no_of_days()
|
||||
@@ -67,10 +151,7 @@ class TestSalarySlip(unittest.TestCase):
|
||||
self.assertEqual(ss.earnings[0].amount, 50000)
|
||||
self.assertEqual(ss.earnings[0].default_amount, 50000)
|
||||
self.assertEqual(ss.earnings[1].amount, 3000)
|
||||
self.assertEqual(ss.deductions[0].amount, 5000)
|
||||
self.assertEqual(ss.deductions[1].amount, 5000)
|
||||
self.assertEqual(ss.gross_pay, 78000)
|
||||
self.assertEqual(ss.net_pay, 68000.0)
|
||||
|
||||
def test_payment_days(self):
|
||||
no_of_days = self.get_no_of_days()
|
||||
@@ -80,8 +161,8 @@ class TestSalarySlip(unittest.TestCase):
|
||||
# set joinng date in the same month
|
||||
make_employee("test_employee@salary.com")
|
||||
if getdate(nowdate()).day >= 15:
|
||||
date_of_joining = getdate(add_days(nowdate(),-10))
|
||||
relieving_date = getdate(add_days(nowdate(),-10))
|
||||
date_of_joining = getdate(add_days(nowdate(),-10))
|
||||
elif getdate(nowdate()).day < 15 and getdate(nowdate()).day >= 5:
|
||||
date_of_joining = getdate(add_days(nowdate(),-3))
|
||||
relieving_date = getdate(add_days(nowdate(),-3))
|
||||
@@ -131,9 +212,7 @@ class TestSalarySlip(unittest.TestCase):
|
||||
def test_email_salary_slip(self):
|
||||
frappe.db.sql("delete from `tabEmail Queue`")
|
||||
|
||||
hr_settings = frappe.get_doc("HR Settings", "HR Settings")
|
||||
hr_settings.email_salary_slip_to_employee = 1
|
||||
hr_settings.save()
|
||||
frappe.db.set_value("HR Settings", None, "email_salary_slip_to_employee", 1)
|
||||
|
||||
make_employee("test_employee@salary.com")
|
||||
ss = make_employee_salary_slip("test_employee@salary.com", "Monthly")
|
||||
@@ -146,7 +225,7 @@ class TestSalarySlip(unittest.TestCase):
|
||||
|
||||
def test_loan_repayment_salary_slip(self):
|
||||
from erpnext.loan_management.doctype.loan.test_loan import create_loan_type, create_loan, make_loan_disbursement_entry, create_loan_accounts
|
||||
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import make_accrual_interest_entry_for_term_loans
|
||||
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
|
||||
|
||||
applicant = make_employee("test_loanemployee@salary.com", company="_Test Company")
|
||||
|
||||
@@ -166,7 +245,7 @@ class TestSalarySlip(unittest.TestCase):
|
||||
|
||||
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1))
|
||||
|
||||
make_accrual_interest_entry_for_term_loans(posting_date=nowdate())
|
||||
process_loan_interest_accrual_for_term_loans(posting_date=nowdate())
|
||||
|
||||
ss = make_employee_salary_slip("test_loanemployee@salary.com", "Monthly")
|
||||
ss.submit()
|
||||
@@ -203,8 +282,11 @@ class TestSalarySlip(unittest.TestCase):
|
||||
# as per assigned salary structure 40500 in monthly salary so 236000*5/100/12
|
||||
frappe.db.sql("""delete from `tabPayroll Period`""")
|
||||
frappe.db.sql("""delete from `tabSalary Component`""")
|
||||
|
||||
payroll_period = create_payroll_period()
|
||||
create_tax_slab(payroll_period)
|
||||
|
||||
create_tax_slab(payroll_period, allow_tax_exemption=True)
|
||||
|
||||
employee = make_employee("test_tax@salary.slip")
|
||||
delete_docs = [
|
||||
"Salary Slip",
|
||||
@@ -230,8 +312,7 @@ class TestSalarySlip(unittest.TestCase):
|
||||
payroll_period, deduct_random=False)
|
||||
tax_paid = get_tax_paid_in_period(employee)
|
||||
|
||||
# total taxable income 586000, 250000 @ 5%, 86000 @ 20% ie. 12500 + 17200
|
||||
annual_tax = 113568
|
||||
annual_tax = 113589.0
|
||||
try:
|
||||
self.assertEqual(tax_paid, annual_tax)
|
||||
except AssertionError:
|
||||
@@ -255,8 +336,7 @@ class TestSalarySlip(unittest.TestCase):
|
||||
raise
|
||||
|
||||
# Submit proof for total 120000
|
||||
data["proof-1"] = create_proof_submission(employee, payroll_period, 50000)
|
||||
data["proof-2"] = create_proof_submission(employee, payroll_period, 70000)
|
||||
data["proof"] = create_proof_submission(employee, payroll_period, 120000)
|
||||
|
||||
# Submit benefit claim for total 50000
|
||||
data["benefit-1"] = create_benefit_claim(employee, payroll_period, 15000, "Medical Allowance")
|
||||
@@ -270,7 +350,7 @@ class TestSalarySlip(unittest.TestCase):
|
||||
|
||||
# total taxable income 416000, 166000 @ 5% ie. 8300
|
||||
try:
|
||||
self.assertEqual(tax_paid, 88608)
|
||||
self.assertEqual(tax_paid, 82389.0)
|
||||
except AssertionError:
|
||||
print("\nSalary Slip - Tax calculation failed on following case\n", data, "\n")
|
||||
raise
|
||||
@@ -285,7 +365,7 @@ class TestSalarySlip(unittest.TestCase):
|
||||
# total taxable income 566000, 250000 @ 5%, 66000 @ 20%, 12500 + 13200
|
||||
tax_paid = get_tax_paid_in_period(employee)
|
||||
try:
|
||||
self.assertEqual(tax_paid, 121211)
|
||||
self.assertEqual(tax_paid, annual_tax)
|
||||
except AssertionError:
|
||||
print("\nSalary Slip - Tax calculation failed on following case\n", data, "\n")
|
||||
raise
|
||||
@@ -322,11 +402,11 @@ class TestSalarySlip(unittest.TestCase):
|
||||
|
||||
return [no_of_days_in_month[1], no_of_holidays_in_month]
|
||||
|
||||
|
||||
def make_employee_salary_slip(user, payroll_frequency, salary_structure=None):
|
||||
from erpnext.hr.doctype.salary_structure.test_salary_structure import make_salary_structure
|
||||
if not salary_structure:
|
||||
salary_structure = payroll_frequency + " Salary Structure Test for Salary Slip"
|
||||
|
||||
employee = frappe.db.get_value("Employee", {"user_id": user})
|
||||
salary_structure_doc = make_salary_structure(salary_structure, payroll_frequency, employee)
|
||||
salary_slip = frappe.db.get_value("Salary Slip", {"employee": frappe.db.get_value("Employee", {"user_id": user})})
|
||||
@@ -456,17 +536,15 @@ def make_deduction_salary_component(setup=False, test_tax=False, company_list=No
|
||||
{
|
||||
"salary_component": 'Professional Tax',
|
||||
"abbr":'PT',
|
||||
"condition": 'base > 10000',
|
||||
"formula": 'base*.1',
|
||||
"type": "Deduction",
|
||||
"amount_based_on_formula": 1
|
||||
"amount": 200,
|
||||
"exempted_from_income_tax": 1
|
||||
|
||||
},
|
||||
{
|
||||
"salary_component": 'TDS',
|
||||
"abbr":'T',
|
||||
"formula": 'base*.1',
|
||||
"type": "Deduction",
|
||||
"amount_based_on_formula": 1,
|
||||
"depends_on_payment_days": 0,
|
||||
"variable_based_on_taxable_salary": 1,
|
||||
"round_to_the_nearest_integer": 1
|
||||
@@ -477,9 +555,7 @@ def make_deduction_salary_component(setup=False, test_tax=False, company_list=No
|
||||
"salary_component": 'TDS',
|
||||
"abbr":'T',
|
||||
"condition": 'employment_type=="Intern"',
|
||||
"formula": 'base*.1',
|
||||
"type": "Deduction",
|
||||
"amount_based_on_formula": 1,
|
||||
"round_to_the_nearest_integer": 1
|
||||
})
|
||||
if setup or test_tax:
|
||||
@@ -535,29 +611,47 @@ def create_benefit_claim(employee, payroll_period, amount, component):
|
||||
}).submit()
|
||||
return claim_date
|
||||
|
||||
def create_tax_slab(payroll_period):
|
||||
data = [
|
||||
def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = False, dont_submit = False):
|
||||
if frappe.db.exists("Income Tax Slab", "Tax Slab: " + payroll_period.name):
|
||||
return
|
||||
|
||||
slabs = [
|
||||
{
|
||||
"from_amount": 250000,
|
||||
"to_amount": 500000,
|
||||
"percent_deduction": 5.2,
|
||||
"percent_deduction": 5,
|
||||
"condition": "annual_taxable_earning > 500000"
|
||||
},
|
||||
{
|
||||
"from_amount": 500001,
|
||||
"to_amount": 1000000,
|
||||
"percent_deduction": 20.8
|
||||
"percent_deduction": 20
|
||||
},
|
||||
{
|
||||
"from_amount": 1000001,
|
||||
"percent_deduction": 31.2
|
||||
"percent_deduction": 30
|
||||
}
|
||||
]
|
||||
payroll_period.taxable_salary_slabs = []
|
||||
for item in data:
|
||||
payroll_period.append("taxable_salary_slabs", item)
|
||||
payroll_period.standard_tax_exemption_amount = 52500
|
||||
payroll_period.save()
|
||||
|
||||
income_tax_slab = frappe.new_doc("Income Tax Slab")
|
||||
income_tax_slab.name = "Tax Slab: " + payroll_period.name
|
||||
income_tax_slab.effective_from = effective_date or add_days(payroll_period.start_date, -2)
|
||||
|
||||
if allow_tax_exemption:
|
||||
income_tax_slab.allow_tax_exemption = 1
|
||||
income_tax_slab.standard_tax_exemption_amount = 50000
|
||||
|
||||
for item in slabs:
|
||||
income_tax_slab.append("slabs", item)
|
||||
|
||||
income_tax_slab.append("other_taxes_and_charges", {
|
||||
"description": "cess",
|
||||
"percent": 4
|
||||
})
|
||||
|
||||
income_tax_slab.save()
|
||||
if not dont_submit:
|
||||
income_tax_slab.submit()
|
||||
|
||||
def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_period, deduct_random=True):
|
||||
deducted_dates = []
|
||||
@@ -595,3 +689,17 @@ def create_additional_salary(employee, payroll_period, amount):
|
||||
"type": "Earning"
|
||||
}).submit()
|
||||
return salary_date
|
||||
|
||||
def make_leave_application(employee, from_date, to_date, leave_type, company=None):
|
||||
leave_application = frappe.get_doc(dict(
|
||||
doctype = 'Leave Application',
|
||||
employee = employee,
|
||||
leave_type = leave_type,
|
||||
from_date = from_date,
|
||||
to_date = to_date,
|
||||
company = company or erpnext.get_default_company() or "_Test Company",
|
||||
docstatus = 1,
|
||||
status = "Approved",
|
||||
leave_approver = 'test@example.com'
|
||||
))
|
||||
leave_application.submit()
|
||||
@@ -82,6 +82,7 @@ frappe.ui.form.on('Salary Structure', {
|
||||
{fieldname:"employee", fieldtype: "Link", options: "Employee", label: __("Employee")},
|
||||
{fieldname:'base_variable', fieldtype:'Section Break'},
|
||||
{fieldname:'from_date', fieldtype:'Date', label: __('From Date'), "reqd": 1},
|
||||
{fieldname:'income_tax_slab', fieldtype:'Link', label: __('Income Tax Slab'), options: 'Income Tax Slab'},
|
||||
{fieldname:'base_col_br', fieldtype:'Column Break'},
|
||||
{fieldname:'base', fieldtype:'Currency', label: __('Base')},
|
||||
{fieldname:'variable', fieldtype:'Currency', label: __('Variable')}
|
||||
|
||||
@@ -16,6 +16,7 @@ class SalaryStructure(Document):
|
||||
self.validate_amount()
|
||||
self.strip_condition_and_formula_fields()
|
||||
self.validate_max_benefits_with_flexi()
|
||||
self.validate_component_based_on_tax_slab()
|
||||
|
||||
def set_missing_values(self):
|
||||
overwritten_fields = ["depends_on_payment_days", "variable_based_on_taxable_salary", "is_tax_applicable", "is_flexible_benefit"]
|
||||
@@ -34,6 +35,12 @@ class SalaryStructure(Document):
|
||||
for fieldname in overwritten_fields_if_missing:
|
||||
d.set(fieldname, component_default_value.get(fieldname))
|
||||
|
||||
def validate_component_based_on_tax_slab(self):
|
||||
for row in self.deductions:
|
||||
if row.variable_based_on_taxable_salary and (row.amount or row.formula):
|
||||
frappe.throw(_("Row #{0}: Cannot set amount or formula for Salary Component {1} with Variable Based On Taxable Salary")
|
||||
.format(row.idx, row.salary_component))
|
||||
|
||||
def validate_amount(self):
|
||||
if flt(self.net_pay) < 0 and self.salary_slip_based_on_timesheet:
|
||||
frappe.throw(_("Net pay cannot be negative"))
|
||||
@@ -82,21 +89,23 @@ class SalaryStructure(Document):
|
||||
|
||||
@frappe.whitelist()
|
||||
def assign_salary_structure(self, company=None, grade=None, department=None, designation=None,employee=None,
|
||||
from_date=None, base=None,variable=None):
|
||||
from_date=None, base=None, variable=None, income_tax_slab=None):
|
||||
employees = self.get_employees(company= company, grade= grade,department= department,designation= designation,name=employee)
|
||||
|
||||
if employees:
|
||||
if len(employees) > 20:
|
||||
frappe.enqueue(assign_salary_structure_for_employees, timeout=600,
|
||||
employees=employees, salary_structure=self,from_date=from_date, base=base,variable=variable)
|
||||
employees=employees, salary_structure=self,from_date=from_date,
|
||||
base=base, variable=variable, income_tax_slab=income_tax_slab)
|
||||
else:
|
||||
assign_salary_structure_for_employees(employees, self, from_date=from_date, base=base,variable=variable)
|
||||
assign_salary_structure_for_employees(employees, self, from_date=from_date,
|
||||
base=base, variable=variable, income_tax_slab=income_tax_slab)
|
||||
else:
|
||||
frappe.msgprint(_("No Employee Found"))
|
||||
|
||||
|
||||
|
||||
def assign_salary_structure_for_employees(employees, salary_structure, from_date=None, base=None,variable=None):
|
||||
def assign_salary_structure_for_employees(employees, salary_structure, from_date=None, base=None, variable=None, income_tax_slab=None):
|
||||
salary_structures_assignments = []
|
||||
existing_assignments_for = get_existing_assignments(employees, salary_structure, from_date)
|
||||
count=0
|
||||
@@ -105,7 +114,8 @@ def assign_salary_structure_for_employees(employees, salary_structure, from_date
|
||||
continue
|
||||
count +=1
|
||||
|
||||
salary_structures_assignment = create_salary_structures_assignment(employee, salary_structure, from_date, base, variable)
|
||||
salary_structures_assignment = create_salary_structures_assignment(employee,
|
||||
salary_structure, from_date, base, variable, income_tax_slab)
|
||||
salary_structures_assignments.append(salary_structures_assignment)
|
||||
frappe.publish_progress(count*100/len(set(employees) - set(existing_assignments_for)), title = _("Assigning Structures..."))
|
||||
|
||||
@@ -113,7 +123,7 @@ def assign_salary_structure_for_employees(employees, salary_structure, from_date
|
||||
frappe.msgprint(_("Structures have been assigned successfully"))
|
||||
|
||||
|
||||
def create_salary_structures_assignment(employee, salary_structure, from_date, base, variable):
|
||||
def create_salary_structures_assignment(employee, salary_structure, from_date, base, variable, income_tax_slab=None):
|
||||
assignment = frappe.new_doc("Salary Structure Assignment")
|
||||
assignment.employee = employee
|
||||
assignment.salary_structure = salary_structure.name
|
||||
@@ -121,6 +131,7 @@ def create_salary_structures_assignment(employee, salary_structure, from_date, b
|
||||
assignment.from_date = from_date
|
||||
assignment.base = base
|
||||
assignment.variable = variable
|
||||
assignment.income_tax_slab = income_tax_slab
|
||||
assignment.save(ignore_permissions = True)
|
||||
assignment.submit()
|
||||
return assignment.name
|
||||
|
||||
@@ -9,8 +9,9 @@ from frappe.utils.make_random import get_random
|
||||
from frappe.utils import nowdate, add_days, add_years, getdate, add_months
|
||||
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
|
||||
from erpnext.hr.doctype.salary_slip.test_salary_slip import make_earning_salary_component,\
|
||||
make_deduction_salary_component, make_employee_salary_slip
|
||||
make_deduction_salary_component, make_employee_salary_slip, create_tax_slab
|
||||
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||
from erpnext.hr.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration import create_payroll_period
|
||||
|
||||
|
||||
test_dependencies = ["Fiscal Year"]
|
||||
@@ -70,10 +71,8 @@ class TestSalaryStructure(unittest.TestCase):
|
||||
self.assertEqual(sal_slip.get("earnings")[1].amount, 3000)
|
||||
self.assertEqual(sal_slip.get("earnings")[2].amount, 25000)
|
||||
self.assertEqual(sal_slip.get("gross_pay"), 78000)
|
||||
self.assertEqual(sal_slip.get("deductions")[0].amount, 5000)
|
||||
self.assertEqual(sal_slip.get("deductions")[1].amount, 5000)
|
||||
self.assertEqual(sal_slip.get("total_deduction"), 10000)
|
||||
self.assertEqual(sal_slip.get("net_pay"), 68000)
|
||||
self.assertEqual(sal_slip.get("deductions")[0].amount, 200)
|
||||
self.assertEqual(sal_slip.get("net_pay"), 78000 - sal_slip.get("total_deduction"))
|
||||
|
||||
def test_whitespaces_in_formula_conditions_fields(self):
|
||||
salary_structure = make_salary_structure("Salary Structure Sample", "Monthly", dont_submit=True)
|
||||
@@ -112,6 +111,7 @@ def make_salary_structure(salary_structure, payroll_frequency, employee=None, do
|
||||
test_tax=False, company=None):
|
||||
if test_tax:
|
||||
frappe.db.sql("""delete from `tabSalary Structure` where name=%s""",(salary_structure))
|
||||
|
||||
if not frappe.db.exists('Salary Structure', salary_structure):
|
||||
details = {
|
||||
"doctype": "Salary Structure",
|
||||
@@ -124,7 +124,8 @@ def make_salary_structure(salary_structure, payroll_frequency, employee=None, do
|
||||
}
|
||||
if other_details and isinstance(other_details, dict):
|
||||
details.update(other_details)
|
||||
salary_structure_doc = frappe.get_doc(details).insert()
|
||||
salary_structure_doc = frappe.get_doc(details)
|
||||
salary_structure_doc.insert()
|
||||
if not dont_submit:
|
||||
salary_structure_doc.submit()
|
||||
else:
|
||||
@@ -139,13 +140,18 @@ def make_salary_structure(salary_structure, payroll_frequency, employee=None, do
|
||||
def create_salary_structure_assignment(employee, salary_structure, from_date=None, company=None):
|
||||
if frappe.db.exists("Salary Structure Assignment", {"employee": employee}):
|
||||
frappe.db.sql("""delete from `tabSalary Structure Assignment` where employee=%s""",(employee))
|
||||
|
||||
payroll_period = create_payroll_period()
|
||||
create_tax_slab(payroll_period, allow_tax_exemption=True)
|
||||
|
||||
salary_structure_assignment = frappe.new_doc("Salary Structure Assignment")
|
||||
salary_structure_assignment.employee = employee
|
||||
salary_structure_assignment.base = 50000
|
||||
salary_structure_assignment.variable = 5000
|
||||
salary_structure_assignment.from_date = from_date or add_months(nowdate(), -1)
|
||||
salary_structure_assignment.from_date = from_date or add_days(nowdate(), -1)
|
||||
salary_structure_assignment.salary_structure = salary_structure
|
||||
salary_structure_assignment.company = company or erpnext.get_default_company()
|
||||
salary_structure_assignment.save(ignore_permissions=True)
|
||||
salary_structure_assignment.income_tax_slab = "Tax Slab: _Test Payroll Period"
|
||||
salary_structure_assignment.submit()
|
||||
return salary_structure_assignment
|
||||
|
||||
@@ -20,6 +20,16 @@ frappe.ui.form.on('Salary Structure Assignment', {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frm.set_query("income_tax_slab", function() {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
docstatus: 1,
|
||||
disabled: 0
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
employee: function(frm) {
|
||||
if(frm.doc.employee){
|
||||
|
||||
@@ -10,11 +10,12 @@
|
||||
"employee",
|
||||
"employee_name",
|
||||
"department",
|
||||
"designation",
|
||||
"company",
|
||||
"column_break_6",
|
||||
"designation",
|
||||
"salary_structure",
|
||||
"from_date",
|
||||
"company",
|
||||
"income_tax_slab",
|
||||
"section_break_7",
|
||||
"base",
|
||||
"column_break_9",
|
||||
@@ -113,11 +114,17 @@
|
||||
"options": "Salary Structure Assignment",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "income_tax_slab",
|
||||
"fieldtype": "Link",
|
||||
"label": "Income Tax Slab",
|
||||
"options": "Income Tax Slab"
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2019-12-31 16:35:34.415099",
|
||||
"modified": "2020-04-25 18:24:23.617088",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Structure Assignment",
|
||||
|
||||
@@ -9,6 +9,8 @@ from frappe.utils import cstr, add_days, date_diff, getdate
|
||||
from frappe import _
|
||||
from frappe.utils.csvutils import UnicodeWriter
|
||||
from frappe.model.document import Document
|
||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||
from erpnext.hr.utils import get_holidays_for_employee
|
||||
|
||||
class UploadAttendance(Document):
|
||||
pass
|
||||
@@ -48,6 +50,7 @@ def add_data(w, args):
|
||||
def get_data(args):
|
||||
dates = get_dates(args)
|
||||
employees = get_active_employees()
|
||||
holidays = get_holidays_for_employees([employee.name for employee in employees], args["from_date"], args["to_date"])
|
||||
existing_attendance_records = get_existing_attendance_records(args)
|
||||
data = []
|
||||
for date in dates:
|
||||
@@ -63,6 +66,9 @@ def get_data(args):
|
||||
and getdate(employee.date_of_joining) <= getdate(date) \
|
||||
and getdate(employee.relieving_date) >= getdate(date):
|
||||
existing_attendance = existing_attendance_records[tuple([getdate(date), employee.name])]
|
||||
|
||||
employee_holiday_list = get_holiday_list_for_employee(employee.name)
|
||||
|
||||
row = [
|
||||
existing_attendance and existing_attendance.name or "",
|
||||
employee.name, employee.employee_name, date,
|
||||
@@ -70,9 +76,22 @@ def get_data(args):
|
||||
existing_attendance and existing_attendance.leave_type or "", employee.company,
|
||||
existing_attendance and existing_attendance.naming_series or get_naming_series(),
|
||||
]
|
||||
if date in holidays[employee_holiday_list]:
|
||||
row[4] = "Holiday"
|
||||
data.append(row)
|
||||
|
||||
return data
|
||||
|
||||
def get_holidays_for_employees(employees, from_date, to_date):
|
||||
holidays = {}
|
||||
for employee in employees:
|
||||
holiday_list = get_holiday_list_for_employee(employee)
|
||||
holiday = get_holidays_for_employee(employee, getdate(from_date), getdate(to_date))
|
||||
if holiday_list not in holidays:
|
||||
holidays[holiday_list] = holiday
|
||||
|
||||
return holidays
|
||||
|
||||
def writedata(w, data):
|
||||
for row in data:
|
||||
w.writerow(row)
|
||||
@@ -123,6 +142,11 @@ def upload():
|
||||
frappe.enqueue(import_attendances, rows=rows, now=True if len(rows) < 200 else False)
|
||||
|
||||
def import_attendances(rows):
|
||||
|
||||
def remove_holidays(rows):
|
||||
rows = [ row for row in rows if row[4] != "Holiday"]
|
||||
return
|
||||
|
||||
from frappe.modules import scrub
|
||||
|
||||
rows = list(filter(lambda x: x and any(x), rows))
|
||||
@@ -133,6 +157,8 @@ def import_attendances(rows):
|
||||
ret = []
|
||||
error = False
|
||||
|
||||
rows = remove_holidays(rows)
|
||||
|
||||
from frappe.utils.csvutils import check_record, import_doc
|
||||
|
||||
for i, row in enumerate(rows):
|
||||
|
||||
@@ -1,85 +1,186 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
from erpnext.hr.doctype.leave_application.leave_application \
|
||||
import get_leave_balance_on, get_leaves_for_period
|
||||
|
||||
from erpnext.hr.report.employee_leave_balance_summary.employee_leave_balance_summary \
|
||||
import get_department_leave_approver_map
|
||||
from frappe import _
|
||||
from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period, get_leave_balance_on, get_leave_allocation_records
|
||||
|
||||
def execute(filters=None):
|
||||
leave_types = frappe.db.sql_list("select name from `tabLeave Type` order by name asc")
|
||||
if filters.to_date <= filters.from_date:
|
||||
frappe.throw(_('From date can not be greater than than To date'))
|
||||
|
||||
columns = get_columns(leave_types)
|
||||
data = get_data(filters, leave_types)
|
||||
columns = get_columns()
|
||||
data = get_data(filters)
|
||||
|
||||
return columns, data
|
||||
|
||||
def get_columns(leave_types):
|
||||
columns = [
|
||||
_("Employee") + ":Link.Employee:150",
|
||||
_("Employee Name") + "::200",
|
||||
_("Department") +"::150"
|
||||
]
|
||||
|
||||
for leave_type in leave_types:
|
||||
columns.append(_(leave_type) + " " + _("Opening") + ":Float:160")
|
||||
columns.append(_(leave_type) + " " + _("Taken") + ":Float:160")
|
||||
columns.append(_(leave_type) + " " + _("Balance") + ":Float:160")
|
||||
def get_columns():
|
||||
columns = [{
|
||||
'label': _('Leave Type'),
|
||||
'fieldtype': 'Link',
|
||||
'fieldname': 'leave_type',
|
||||
'width': 200,
|
||||
'options': 'Leave Type'
|
||||
}, {
|
||||
'label': _('Employee'),
|
||||
'fieldtype': 'Link',
|
||||
'fieldname': 'employee',
|
||||
'width': 100,
|
||||
'options': 'Employee'
|
||||
}, {
|
||||
'label': _('Employee Name'),
|
||||
'fieldtype': 'Data',
|
||||
'fieldname': 'employee_name',
|
||||
'width': 100,
|
||||
}, {
|
||||
'label': _('Opening Balance'),
|
||||
'fieldtype': 'float',
|
||||
'fieldname': 'opening_balance',
|
||||
'width': 130,
|
||||
}, {
|
||||
'label': _('Leaves Allocated'),
|
||||
'fieldtype': 'float',
|
||||
'fieldname': 'leaves_allocated',
|
||||
'width': 130,
|
||||
}, {
|
||||
'label': _('Leaves Taken'),
|
||||
'fieldtype': 'float',
|
||||
'fieldname': 'leaves_taken',
|
||||
'width': 130,
|
||||
}, {
|
||||
'label': _('Leaves Expired'),
|
||||
'fieldtype': 'float',
|
||||
'fieldname': 'leaves_expired',
|
||||
'width': 130,
|
||||
}, {
|
||||
'label': _('Closing Balance'),
|
||||
'fieldtype': 'float',
|
||||
'fieldname': 'closing_balance',
|
||||
'width': 130,
|
||||
}]
|
||||
|
||||
return columns
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions = {
|
||||
"status": "Active",
|
||||
"company": filters.company,
|
||||
}
|
||||
if filters.get("department"):
|
||||
conditions.update({"department": filters.get("department")})
|
||||
if filters.get("employee"):
|
||||
conditions.update({"employee": filters.get("employee")})
|
||||
def get_data(filters):
|
||||
leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC")
|
||||
|
||||
return conditions
|
||||
|
||||
def get_data(filters, leave_types):
|
||||
user = frappe.session.user
|
||||
conditions = get_conditions(filters)
|
||||
|
||||
if filters.to_date <= filters.from_date:
|
||||
frappe.throw(_("From date can not be greater than than To date"))
|
||||
|
||||
active_employees = frappe.get_all("Employee",
|
||||
filters=conditions,
|
||||
fields=["name", "employee_name", "department", "user_id", "leave_approver"])
|
||||
|
||||
user = frappe.session.user
|
||||
department_approver_map = get_department_leave_approver_map(filters.get('department'))
|
||||
|
||||
active_employees = frappe.get_list('Employee',
|
||||
filters=conditions,
|
||||
fields=['name', 'employee_name', 'department', 'user_id', 'leave_approver'])
|
||||
|
||||
data = []
|
||||
for employee in active_employees:
|
||||
leave_approvers = department_approver_map.get(employee.department_name, [])
|
||||
if employee.leave_approver:
|
||||
leave_approvers.append(employee.leave_approver)
|
||||
|
||||
if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) or ("HR Manager" in frappe.get_roles(user)):
|
||||
row = [employee.name, employee.employee_name, employee.department]
|
||||
for leave_type in leave_types:
|
||||
if len(active_employees) > 1:
|
||||
data.append({
|
||||
'leave_type': leave_type
|
||||
})
|
||||
else:
|
||||
row = frappe._dict({
|
||||
'leave_type': leave_type
|
||||
})
|
||||
|
||||
for employee in active_employees:
|
||||
|
||||
leave_approvers = department_approver_map.get(employee.department_name, []).append(employee.leave_approver)
|
||||
|
||||
if (leave_approvers and len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) \
|
||||
or ("HR Manager" in frappe.get_roles(user)):
|
||||
if len(active_employees) > 1:
|
||||
row = frappe._dict()
|
||||
row.employee = employee.name,
|
||||
row.employee_name = employee.employee_name
|
||||
|
||||
for leave_type in leave_types:
|
||||
# leaves taken
|
||||
leaves_taken = get_leaves_for_period(employee.name, leave_type,
|
||||
filters.from_date, filters.to_date) * -1
|
||||
|
||||
# opening balance
|
||||
new_allocation, expired_leaves = get_allocated_and_expired_leaves(filters.from_date, filters.to_date, employee.name, leave_type)
|
||||
|
||||
|
||||
opening = get_leave_balance_on(employee.name, leave_type, filters.from_date)
|
||||
closing = get_leave_balance_on(employee.name, leave_type, filters.to_date)
|
||||
|
||||
# closing balance
|
||||
closing = max(opening - leaves_taken, 0)
|
||||
row.leaves_allocated = new_allocation
|
||||
row.leaves_expired = expired_leaves - leaves_taken if expired_leaves - leaves_taken > 0 else 0
|
||||
row.opening_balance = opening
|
||||
row.leaves_taken = leaves_taken
|
||||
row.closing_balance = closing
|
||||
row.indent = 1
|
||||
data.append(row)
|
||||
new_leaves_allocated = 0
|
||||
|
||||
row += [opening, leaves_taken, closing]
|
||||
|
||||
data.append(row)
|
||||
return data
|
||||
|
||||
return data
|
||||
def get_conditions(filters):
|
||||
conditions={
|
||||
'status': 'Active',
|
||||
}
|
||||
if filters.get('employee'):
|
||||
conditions['name'] = filters.get('employee')
|
||||
|
||||
if filters.get('employee'):
|
||||
conditions['name'] = filters.get('employee')
|
||||
|
||||
return conditions
|
||||
|
||||
def get_department_leave_approver_map(department=None):
|
||||
conditions=''
|
||||
if department:
|
||||
conditions="and (department_name = '%(department)s' or parent_department = '%(department)s')"%{'department': department}
|
||||
|
||||
# get current department and all its child
|
||||
department_list = frappe.db.sql_list(""" SELECT name FROM `tabDepartment` WHERE disabled=0 {0}""".format(conditions)) #nosec
|
||||
|
||||
# retrieve approvers list from current department and from its subsequent child departments
|
||||
approver_list = frappe.get_all('Department Approver', filters={
|
||||
'parentfield': 'leave_approvers',
|
||||
'parent': ('in', department_list)
|
||||
}, fields=['parent', 'approver'], as_list=1)
|
||||
|
||||
approvers = {}
|
||||
|
||||
for k, v in approver_list:
|
||||
approvers.setdefault(k, []).append(v)
|
||||
|
||||
return approvers
|
||||
|
||||
def get_allocated_and_expired_leaves(from_date, to_date, employee, leave_type):
|
||||
|
||||
from frappe.utils import getdate
|
||||
|
||||
new_allocation = 0
|
||||
expired_leaves = 0
|
||||
|
||||
records= frappe.db.sql("""
|
||||
SELECT
|
||||
employee, leave_type, from_date, to_date, leaves, transaction_name,
|
||||
is_carry_forward, is_expired
|
||||
FROM `tabLeave Ledger Entry`
|
||||
WHERE employee=%(employee)s AND leave_type=%(leave_type)s
|
||||
AND docstatus=1 AND leaves>0
|
||||
AND (from_date between %(from_date)s AND %(to_date)s
|
||||
OR to_date between %(from_date)s AND %(to_date)s
|
||||
OR (from_date < %(from_date)s AND to_date > %(to_date)s))
|
||||
""", {
|
||||
"from_date": from_date,
|
||||
"to_date": to_date,
|
||||
"employee": employee,
|
||||
"leave_type": leave_type
|
||||
}, as_dict=1)
|
||||
|
||||
for record in records:
|
||||
if record.to_date <= getdate(to_date):
|
||||
expired_leaves += record.leaves
|
||||
|
||||
if record.from_date >= getdate(from_date):
|
||||
new_allocation += record.leaves
|
||||
|
||||
return new_allocation, expired_leaves
|
||||
|
||||
@@ -5,18 +5,11 @@
|
||||
frappe.query_reports['Employee Leave Balance Summary'] = {
|
||||
filters: [
|
||||
{
|
||||
fieldname:'from_date',
|
||||
label: __('From Date'),
|
||||
fieldname:'date',
|
||||
label: __('Date'),
|
||||
fieldtype: 'Date',
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_default('year_start_date')
|
||||
},
|
||||
{
|
||||
fieldname:'to_date',
|
||||
label: __('To Date'),
|
||||
fieldtype: 'Date',
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_default('year_end_date')
|
||||
default: frappe.datetime.now_date()
|
||||
},
|
||||
{
|
||||
fieldname:'company',
|
||||
|
||||
@@ -1,130 +1,75 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
# 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 frappe.utils import flt
|
||||
from frappe import _
|
||||
from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period, get_leave_balance_on
|
||||
from frappe.utils import flt
|
||||
from erpnext.hr.doctype.leave_application.leave_application \
|
||||
import get_leave_balance_on, get_leaves_for_period
|
||||
|
||||
from erpnext.hr.report.employee_leave_balance.employee_leave_balance \
|
||||
import get_department_leave_approver_map
|
||||
|
||||
def execute(filters=None):
|
||||
if filters.to_date <= filters.from_date:
|
||||
frappe.throw(_('From date can not be greater than than To date'))
|
||||
leave_types = frappe.db.sql_list("select name from `tabLeave Type` order by name asc")
|
||||
|
||||
columns = get_columns()
|
||||
data = get_data(filters)
|
||||
columns = get_columns(leave_types)
|
||||
data = get_data(filters, leave_types)
|
||||
|
||||
return columns, data
|
||||
|
||||
def get_columns():
|
||||
columns = [{
|
||||
'label': _('Leave Type'),
|
||||
'fieldtype': 'Link',
|
||||
'fieldname': 'leave_type',
|
||||
'width': 300,
|
||||
'options': 'Leave Type'
|
||||
}, {
|
||||
'label': _('Employee'),
|
||||
'fieldtype': 'Link',
|
||||
'fieldname': 'employee',
|
||||
'width': 100,
|
||||
'options': 'Employee'
|
||||
}, {
|
||||
'label': _('Employee Name'),
|
||||
'fieldtype': 'Data',
|
||||
'fieldname': 'employee_name',
|
||||
'width': 100,
|
||||
}, {
|
||||
'label': _('Opening Balance'),
|
||||
'fieldtype': 'float',
|
||||
'fieldname': 'opening_balance',
|
||||
'width': 160,
|
||||
}, {
|
||||
'label': _('Leaves Taken'),
|
||||
'fieldtype': 'float',
|
||||
'fieldname': 'leaves_taken',
|
||||
'width': 160,
|
||||
}, {
|
||||
'label': _('Closing Balance'),
|
||||
'fieldtype': 'float',
|
||||
'fieldname': 'closing_balance',
|
||||
'width': 160,
|
||||
}]
|
||||
def get_columns(leave_types):
|
||||
columns = [
|
||||
_("Employee") + ":Link.Employee:150",
|
||||
_("Employee Name") + "::200",
|
||||
_("Department") +"::150"
|
||||
]
|
||||
|
||||
for leave_type in leave_types:
|
||||
columns.append(_(leave_type) + ":Float:160")
|
||||
|
||||
return columns
|
||||
|
||||
def get_data(filters):
|
||||
leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC")
|
||||
|
||||
conditions = get_conditions(filters)
|
||||
|
||||
user = frappe.session.user
|
||||
department_approver_map = get_department_leave_approver_map(filters.get('department'))
|
||||
|
||||
active_employees = frappe.get_list('Employee',
|
||||
filters=conditions,
|
||||
fields=['name', 'employee_name', 'department', 'user_id', 'leave_approver'])
|
||||
|
||||
data = []
|
||||
|
||||
for leave_type in leave_types:
|
||||
data.append({
|
||||
'leave_type': leave_type
|
||||
})
|
||||
for employee in active_employees:
|
||||
|
||||
leave_approvers = department_approver_map.get(employee.department_name, []).append(employee.leave_approver)
|
||||
|
||||
if (leave_approvers and len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) \
|
||||
or ("HR Manager" in frappe.get_roles(user)):
|
||||
row = frappe._dict({
|
||||
'employee': employee.name,
|
||||
'employee_name': employee.employee_name
|
||||
})
|
||||
|
||||
leaves_taken = get_leaves_for_period(employee.name, leave_type,
|
||||
filters.from_date, filters.to_date) * -1
|
||||
|
||||
opening = get_leave_balance_on(employee.name, leave_type, filters.from_date)
|
||||
closing = get_leave_balance_on(employee.name, leave_type, filters.to_date)
|
||||
|
||||
row.opening_balance = opening
|
||||
row.leaves_taken = leaves_taken
|
||||
row.closing_balance = closing
|
||||
row.indent = 1
|
||||
data.append(row)
|
||||
|
||||
return data
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions={
|
||||
'status': 'Active',
|
||||
conditions = {
|
||||
"status": "Active",
|
||||
"company": filters.company,
|
||||
}
|
||||
if filters.get('employee'):
|
||||
conditions['name'] = filters.get('employee')
|
||||
|
||||
if filters.get('employee'):
|
||||
conditions['name'] = filters.get('employee')
|
||||
if filters.get("department"):
|
||||
conditions.update({"department": filters.get("department")})
|
||||
if filters.get("employee"):
|
||||
conditions.update({"employee": filters.get("employee")})
|
||||
|
||||
return conditions
|
||||
|
||||
def get_department_leave_approver_map(department=None):
|
||||
conditions=''
|
||||
if department:
|
||||
conditions="and (department_name = '%(department)s' or parent_department = '%(department)s')"%{'department': department}
|
||||
def get_data(filters, leave_types):
|
||||
user = frappe.session.user
|
||||
conditions = get_conditions(filters)
|
||||
|
||||
# get current department and all its child
|
||||
department_list = frappe.db.sql_list(""" SELECT name FROM `tabDepartment` WHERE disabled=0 {0}""".format(conditions)) #nosec
|
||||
active_employees = frappe.get_all("Employee",
|
||||
filters=conditions,
|
||||
fields=["name", "employee_name", "department", "user_id", "leave_approver"])
|
||||
|
||||
# retrieve approvers list from current department and from its subsequent child departments
|
||||
approver_list = frappe.get_all('Department Approver', filters={
|
||||
'parentfield': 'leave_approvers',
|
||||
'parent': ('in', department_list)
|
||||
}, fields=['parent', 'approver'], as_list=1)
|
||||
department_approver_map = get_department_leave_approver_map(filters.get('department'))
|
||||
|
||||
approvers = {}
|
||||
data = []
|
||||
for employee in active_employees:
|
||||
leave_approvers = department_approver_map.get(employee.department_name, [])
|
||||
if employee.leave_approver:
|
||||
leave_approvers.append(employee.leave_approver)
|
||||
|
||||
for k, v in approver_list:
|
||||
approvers.setdefault(k, []).append(v)
|
||||
if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) or ("HR Manager" in frappe.get_roles(user)):
|
||||
row = [employee.name, employee.employee_name, employee.department]
|
||||
|
||||
return approvers
|
||||
for leave_type in leave_types:
|
||||
|
||||
# opening balance
|
||||
opening = get_leave_balance_on(employee.name, leave_type, filters.date)
|
||||
|
||||
|
||||
row += [opening]
|
||||
|
||||
data.append(row)
|
||||
|
||||
return data
|
||||
@@ -9,6 +9,8 @@ from frappe.model.document import Document
|
||||
from frappe.desk.form import assign_to
|
||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||
|
||||
class DuplicateDeclarationError(frappe.ValidationError): pass
|
||||
|
||||
class EmployeeBoardingController(Document):
|
||||
'''
|
||||
Create the project and the task for the boarding process
|
||||
@@ -226,6 +228,17 @@ def get_employee_leave_policy(employee):
|
||||
else:
|
||||
frappe.throw(_("Please set leave policy for employee {0} in Employee / Grade record").format(employee))
|
||||
|
||||
def validate_duplicate_exemption_for_payroll_period(doctype, docname, payroll_period, employee):
|
||||
existing_record = frappe.db.exists(doctype, {
|
||||
"payroll_period": payroll_period,
|
||||
"employee": employee,
|
||||
'docstatus': ['<', 2],
|
||||
'name': ['!=', docname]
|
||||
})
|
||||
if existing_record:
|
||||
frappe.throw(_("{0} already exists for employee {1} and period {2}")
|
||||
.format(doctype, employee, payroll_period), DuplicateDeclarationError)
|
||||
|
||||
def validate_tax_declaration(declarations):
|
||||
subcategories = []
|
||||
for d in declarations:
|
||||
|
||||
Reference in New Issue
Block a user