mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-26 08:24:47 +00:00
Merge branch 'develop' into request_to_quatation_fix
This commit is contained in:
@@ -119,7 +119,7 @@ class SalarySlip(TransactionBase):
|
|||||||
if not self.salary_slip_based_on_timesheet:
|
if not self.salary_slip_based_on_timesheet:
|
||||||
self.get_date_details()
|
self.get_date_details()
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
|
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
||||||
["date_of_joining", "relieving_date"])
|
["date_of_joining", "relieving_date"])
|
||||||
|
|
||||||
self.get_leave_details(joining_date, relieving_date)
|
self.get_leave_details(joining_date, relieving_date)
|
||||||
@@ -183,7 +183,7 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
def get_leave_details(self, joining_date=None, relieving_date=None, lwp=None, for_preview=0):
|
def get_leave_details(self, joining_date=None, relieving_date=None, lwp=None, for_preview=0):
|
||||||
if not joining_date:
|
if not joining_date:
|
||||||
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
|
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
||||||
["date_of_joining", "relieving_date"])
|
["date_of_joining", "relieving_date"])
|
||||||
|
|
||||||
working_days = date_diff(self.end_date, self.start_date) + 1
|
working_days = date_diff(self.end_date, self.start_date) + 1
|
||||||
@@ -300,9 +300,6 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
self.rounded_total = rounded(self.net_pay)
|
self.rounded_total = rounded(self.net_pay)
|
||||||
|
|
||||||
if self.net_pay < 0:
|
|
||||||
frappe.throw(_("Net Pay cannnot be negative"))
|
|
||||||
|
|
||||||
def calculate_component_amounts(self):
|
def calculate_component_amounts(self):
|
||||||
if not getattr(self, '_salary_structure_doc', None):
|
if not getattr(self, '_salary_structure_doc', None):
|
||||||
self._salary_structure_doc = frappe.get_doc('Salary Structure', self.salary_structure)
|
self._salary_structure_doc = frappe.get_doc('Salary Structure', self.salary_structure)
|
||||||
@@ -313,6 +310,7 @@ class SalarySlip(TransactionBase):
|
|||||||
self.add_employee_benefits(payroll_period)
|
self.add_employee_benefits(payroll_period)
|
||||||
self.add_additional_salary_components()
|
self.add_additional_salary_components()
|
||||||
self.add_tax_components(payroll_period)
|
self.add_tax_components(payroll_period)
|
||||||
|
self.set_component_amounts_based_on_payment_days()
|
||||||
|
|
||||||
def add_structure_components(self):
|
def add_structure_components(self):
|
||||||
data = self.get_data_for_eval()
|
data = self.get_data_for_eval()
|
||||||
@@ -404,14 +402,18 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
def add_tax_components(self, payroll_period):
|
def add_tax_components(self, payroll_period):
|
||||||
# Calculate variable_based_on_taxable_salary after all components updated in salary slip
|
# Calculate variable_based_on_taxable_salary after all components updated in salary slip
|
||||||
struct_tax_components = [d.salary_component for d in self._salary_structure_doc.get("deductions")
|
tax_components, other_deduction_components = [], []
|
||||||
if d.variable_based_on_taxable_salary == 1 and not d.formula and not d.amount]
|
for d in self._salary_structure_doc.get("deductions"):
|
||||||
|
if d.variable_based_on_taxable_salary == 1 and not d.formula and not flt(d.amount):
|
||||||
|
tax_components.append(d.salary_component)
|
||||||
|
else:
|
||||||
|
other_deduction_components.append(d.salary_component)
|
||||||
|
|
||||||
if not struct_tax_components:
|
if not tax_components:
|
||||||
struct_tax_components = [d.name for d in
|
tax_components = [d.name for d in frappe.get_all("Salary Component", filters={"variable_based_on_taxable_salary": 1})
|
||||||
frappe.get_all("Salary Component", filters={"variable_based_on_taxable_salary": 1})]
|
if d.name not in other_deduction_components]
|
||||||
|
|
||||||
for d in struct_tax_components:
|
for d in tax_components:
|
||||||
tax_amount = self.calculate_variable_based_on_taxable_salary(d, payroll_period)
|
tax_amount = self.calculate_variable_based_on_taxable_salary(d, payroll_period)
|
||||||
tax_row = self.get_salary_slip_row(d)
|
tax_row = self.get_salary_slip_row(d)
|
||||||
self.update_component_row(tax_row, tax_amount, "deductions")
|
self.update_component_row(tax_row, tax_amount, "deductions")
|
||||||
@@ -477,8 +479,7 @@ class SalarySlip(TransactionBase):
|
|||||||
future_structured_taxable_earnings = current_taxable_earnings.taxable_earnings * (math.ceil(remaining_sub_periods) - 1)
|
future_structured_taxable_earnings = current_taxable_earnings.taxable_earnings * (math.ceil(remaining_sub_periods) - 1)
|
||||||
|
|
||||||
# get taxable_earnings, addition_earnings for current actual payment days
|
# get taxable_earnings, addition_earnings for current actual payment days
|
||||||
self.set_component_amounts_based_on_payment_days()
|
current_taxable_earnings_for_payment_days = self.get_taxable_earnings(based_on_payment_days=1)
|
||||||
current_taxable_earnings_for_payment_days = self.get_taxable_earnings()
|
|
||||||
current_structured_taxable_earnings = current_taxable_earnings_for_payment_days.taxable_earnings
|
current_structured_taxable_earnings = current_taxable_earnings_for_payment_days.taxable_earnings
|
||||||
current_additional_earnings = current_taxable_earnings_for_payment_days.additional_income
|
current_additional_earnings = current_taxable_earnings_for_payment_days.additional_income
|
||||||
current_additional_earnings_with_full_tax = current_taxable_earnings_for_payment_days.additional_income_with_full_tax
|
current_additional_earnings_with_full_tax = current_taxable_earnings_for_payment_days.additional_income_with_full_tax
|
||||||
@@ -501,7 +502,6 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
# Structured tax amount
|
# 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(payroll_period, total_taxable_earnings_without_full_tax_addl_components)
|
||||||
|
|
||||||
current_structured_tax_amount = (total_structured_tax_amount - previous_total_paid_taxes) / remaining_sub_periods
|
current_structured_tax_amount = (total_structured_tax_amount - previous_total_paid_taxes) / remaining_sub_periods
|
||||||
|
|
||||||
# Total taxable earnings with additional earnings with full tax
|
# Total taxable earnings with additional earnings with full tax
|
||||||
@@ -560,25 +560,39 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
return total_tax_paid
|
return total_tax_paid
|
||||||
|
|
||||||
def get_taxable_earnings(self, only_flexi=0):
|
def get_taxable_earnings(self, based_on_payment_days=0):
|
||||||
|
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
||||||
|
["date_of_joining", "relieving_date"])
|
||||||
|
|
||||||
|
if not relieving_date:
|
||||||
|
relieving_date = getdate(self.end_date)
|
||||||
|
|
||||||
|
if not joining_date:
|
||||||
|
frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name)))
|
||||||
|
|
||||||
taxable_earnings = 0
|
taxable_earnings = 0
|
||||||
additional_income = 0
|
additional_income = 0
|
||||||
additional_income_with_full_tax = 0
|
additional_income_with_full_tax = 0
|
||||||
flexi_benefits = 0
|
flexi_benefits = 0
|
||||||
|
|
||||||
for earning in self.earnings:
|
for earning in self.earnings:
|
||||||
|
if based_on_payment_days:
|
||||||
|
amount, additional_amount = self.get_amount_based_on_payment_days(earning, joining_date, relieving_date)
|
||||||
|
else:
|
||||||
|
amount, additional_amount = earning.amount, earning.additional_amount
|
||||||
|
|
||||||
if earning.is_tax_applicable:
|
if earning.is_tax_applicable:
|
||||||
if flt(earning.additional_amount):
|
if additional_amount:
|
||||||
taxable_earnings += (earning.amount - earning.additional_amount)
|
taxable_earnings += (amount - additional_amount)
|
||||||
additional_income += earning.additional_amount
|
additional_income += additional_amount
|
||||||
if earning.deduct_full_tax_on_selected_payroll_date:
|
if earning.deduct_full_tax_on_selected_payroll_date:
|
||||||
additional_income_with_full_tax += earning.additional_amount
|
additional_income_with_full_tax += additional_amount
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if earning.is_flexible_benefit:
|
if earning.is_flexible_benefit:
|
||||||
flexi_benefits += earning.amount
|
flexi_benefits += amount
|
||||||
else:
|
else:
|
||||||
taxable_earnings += earning.amount
|
taxable_earnings += amount
|
||||||
|
|
||||||
return frappe._dict({
|
return frappe._dict({
|
||||||
"taxable_earnings": taxable_earnings,
|
"taxable_earnings": taxable_earnings,
|
||||||
@@ -587,6 +601,26 @@ class SalarySlip(TransactionBase):
|
|||||||
"flexi_benefits": flexi_benefits
|
"flexi_benefits": flexi_benefits
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def get_amount_based_on_payment_days(self, row, joining_date, relieving_date):
|
||||||
|
amount, additional_amount = row.amount, row.additional_amount
|
||||||
|
if (self.salary_structure and
|
||||||
|
cint(row.depends_on_payment_days) and cint(self.total_working_days) and
|
||||||
|
(not self.salary_slip_based_on_timesheet or
|
||||||
|
getdate(self.start_date) < joining_date or
|
||||||
|
getdate(self.end_date) > relieving_date
|
||||||
|
)):
|
||||||
|
additional_amount = flt((flt(row.additional_amount) * flt(self.payment_days)
|
||||||
|
/ cint(self.total_working_days)), row.precision("additional_amount"))
|
||||||
|
amount = flt((flt(row.default_amount) * flt(self.payment_days)
|
||||||
|
/ cint(self.total_working_days)), row.precision("amount")) + additional_amount
|
||||||
|
|
||||||
|
elif not self.payment_days and not self.salary_slip_based_on_timesheet and cint(row.depends_on_payment_days):
|
||||||
|
amount, additional_amount = 0, 0
|
||||||
|
elif not row.amount:
|
||||||
|
amount = row.default_amount + row.additional_amount
|
||||||
|
|
||||||
|
return amount, additional_amount
|
||||||
|
|
||||||
def calculate_unclaimed_taxable_benefits(self, payroll_period):
|
def calculate_unclaimed_taxable_benefits(self, payroll_period):
|
||||||
# get total sum of benefits paid
|
# get total sum of benefits paid
|
||||||
total_benefits_paid = flt(frappe.db.sql("""
|
total_benefits_paid = flt(frappe.db.sql("""
|
||||||
@@ -688,7 +722,7 @@ class SalarySlip(TransactionBase):
|
|||||||
return total
|
return total
|
||||||
|
|
||||||
def set_component_amounts_based_on_payment_days(self):
|
def set_component_amounts_based_on_payment_days(self):
|
||||||
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
|
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
||||||
["date_of_joining", "relieving_date"])
|
["date_of_joining", "relieving_date"])
|
||||||
|
|
||||||
if not relieving_date:
|
if not relieving_date:
|
||||||
@@ -699,22 +733,7 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
for component_type in ("earnings", "deductions"):
|
for component_type in ("earnings", "deductions"):
|
||||||
for d in self.get(component_type):
|
for d in self.get(component_type):
|
||||||
if (self.salary_structure and
|
d.amount = self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0]
|
||||||
cint(d.depends_on_payment_days) and cint(self.total_working_days) and
|
|
||||||
(not self.salary_slip_based_on_timesheet or
|
|
||||||
getdate(self.start_date) < joining_date or
|
|
||||||
getdate(self.end_date) > relieving_date
|
|
||||||
)):
|
|
||||||
|
|
||||||
d.amount = flt(
|
|
||||||
(flt(d.default_amount + d.additional_amount) * flt(self.payment_days)
|
|
||||||
/ cint(self.total_working_days))
|
|
||||||
, d.precision("amount"))
|
|
||||||
|
|
||||||
elif not self.payment_days and not self.salary_slip_based_on_timesheet and cint(d.depends_on_payment_days):
|
|
||||||
d.amount = 0
|
|
||||||
elif not d.amount:
|
|
||||||
d.amount = d.default_amount + d.additional_amount
|
|
||||||
|
|
||||||
def set_loan_repayment(self):
|
def set_loan_repayment(self):
|
||||||
self.set('loans', [])
|
self.set('loans', [])
|
||||||
|
|||||||
@@ -442,7 +442,8 @@ def make_deduction_salary_component(setup=False, test_tax=False):
|
|||||||
"formula": 'base*.1',
|
"formula": 'base*.1',
|
||||||
"type": "Deduction",
|
"type": "Deduction",
|
||||||
"amount_based_on_formula": 1,
|
"amount_based_on_formula": 1,
|
||||||
"depends_on_payment_days": 0
|
"depends_on_payment_days": 0,
|
||||||
|
"variable_based_on_taxable_salary": 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
if not test_tax:
|
if not test_tax:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
0
erpnext/stock/doctype/warehouse_type/__init__.py
Normal file
0
erpnext/stock/doctype/warehouse_type/__init__.py
Normal file
10
erpnext/stock/doctype/warehouse_type/test_warehouse_type.py
Normal file
10
erpnext/stock/doctype/warehouse_type/test_warehouse_type.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# See license.txt
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class TestWarehouseType(unittest.TestCase):
|
||||||
|
pass
|
||||||
8
erpnext/stock/doctype/warehouse_type/warehouse_type.js
Normal file
8
erpnext/stock/doctype/warehouse_type/warehouse_type.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on('Warehouse Type', {
|
||||||
|
// refresh: function(frm) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
});
|
||||||
108
erpnext/stock/doctype/warehouse_type/warehouse_type.json
Normal file
108
erpnext/stock/doctype/warehouse_type/warehouse_type.json
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
{
|
||||||
|
"autoname": "Prompt",
|
||||||
|
"creation": "2019-05-21 15:27:06.514511",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"description"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "description",
|
||||||
|
"fieldtype": "Small Text",
|
||||||
|
"label": "Description"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modified": "2019-05-27 18:35:33.354571",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Stock",
|
||||||
|
"name": "Warehouse Type",
|
||||||
|
"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": "Item Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Stock Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Sales User",
|
||||||
|
"share": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Stock User",
|
||||||
|
"share": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Purchase User",
|
||||||
|
"share": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Accounts User",
|
||||||
|
"share": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Manufacturing User",
|
||||||
|
"share": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"quick_entry": 1,
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "ASC",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
||||||
10
erpnext/stock/doctype/warehouse_type/warehouse_type.py
Normal file
10
erpnext/stock/doctype/warehouse_type/warehouse_type.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2019, 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 WarehouseType(Document):
|
||||||
|
pass
|
||||||
@@ -49,7 +49,24 @@ frappe.query_reports["Stock Balance"] = {
|
|||||||
"label": __("Warehouse"),
|
"label": __("Warehouse"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"width": "80",
|
"width": "80",
|
||||||
"options": "Warehouse"
|
"options": "Warehouse",
|
||||||
|
get_query: () => {
|
||||||
|
var warehouse_type = frappe.query_report.get_filter_value('warehouse_type');
|
||||||
|
if(warehouse_type){
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
'warehouse_type': warehouse_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "warehouse_type",
|
||||||
|
"label": __("Warehouse Type"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"width": "80",
|
||||||
|
"options": "Warehouse Type"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"include_uom",
|
"fieldname":"include_uom",
|
||||||
|
|||||||
@@ -113,6 +113,10 @@ def get_conditions(filters):
|
|||||||
where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"%(warehouse_details.lft,
|
where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"%(warehouse_details.lft,
|
||||||
warehouse_details.rgt)
|
warehouse_details.rgt)
|
||||||
|
|
||||||
|
if filters.get("warehouse_type") and not filters.get("warehouse"):
|
||||||
|
conditions += " and exists (select name from `tabWarehouse` wh \
|
||||||
|
where wh.warehouse_type = '%s' and sle.warehouse = wh.name)"%(filters.get("warehouse_type"))
|
||||||
|
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
def get_stock_ledger_entries(filters, items):
|
def get_stock_ledger_entries(filters, items):
|
||||||
|
|||||||
Reference in New Issue
Block a user